Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -2434,9 +2434,16 @@ protected override void NewItem(

private static bool WinCreateSymbolicLink(string path, string strTargetPath, bool isDirectory)
{
int created = NativeMethods.CreateSymbolicLink(path, strTargetPath, (isDirectory ? 1 : 0));
bool success = (created == 1) ? true : false;
return success;
// The new AllowUnprivilegedCreate is only available on Win10 build 14972 or newer
var flags = isDirectory ? NativeMethods.SymbolicLinkFlags.Directory : NativeMethods.SymbolicLinkFlags.File;
if (Environment.OSVersion.Version.Major == 10 && Environment.OSVersion.Version.Build >= 14972 ||
Environment.OSVersion.Version.Major >= 11)
{
flags |= NativeMethods.SymbolicLinkFlags.AllowUnprivilegedCreate;
}

int created = NativeMethods.CreateSymbolicLink(path, strTargetPath, flags);
return (created == 1) ? true : false;
}

private static bool WinCreateHardLink(string path, string strTargetPath)
Expand Down Expand Up @@ -7014,10 +7021,32 @@ internal static bool PathIsNetworkPath(string path)
/// </summary>
/// <param name="name">Path of the symbolic link.</param>
/// <param name="destination">Path of the target of the symbolic link.</param>
/// <param name="destinationType">0 for destination as file and 1 for destination as directory.</param>
/// <param name="symbolicLinkFlags">Flag values from SymbolicLinkFlags enum.</param>
/// <returns>1 on successful creation.</returns>
[DllImport(PinvokeDllNames.CreateSymbolicLinkDllName, CharSet = CharSet.Unicode, SetLastError = true)]
internal static extern int CreateSymbolicLink(string name, string destination, int destinationType);
internal static extern int CreateSymbolicLink(string name, string destination, SymbolicLinkFlags symbolicLinkFlags);

/// <summary>
/// Flags used when creating a symbolic link.
/// </summary>
[Flags]
internal enum SymbolicLinkFlags
{
/// <summary>
/// Symbolic link is a file.
/// </summary>
File = 0,

/// <summary>
/// Symbolic link is a directory.
/// </summary>
Directory = 1,

/// <summary>
/// Allow creation of symbolic link without elevation. Requires Developer mode.
/// </summary>
AllowUnprivilegedCreate = 2
}

/// <summary>
/// Creates a hard link using the native API.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -256,19 +256,27 @@ Describe "New-Item with links" -Tags @('CI', 'RequireAdminOnWindows') {
}
}

Describe "New-Item with links fails for non elevated user." -Tags "CI" {
Describe "New-Item with links fails for non elevated user if developer mode not enabled on Windows." -Tags "CI" {
BeforeAll {
$tmpDirectory = $TestDrive
$testfile = "testfile.txt"
$testfolder = "newDirectory"
$testlink = "testlink"
$FullyQualifiedFile = Join-Path -Path $tmpDirectory -ChildPath $testfile
$FullyQualifiedFolder = Join-Path -Path $tmpDirectory -ChildPath $testfolder
$FullyQualifiedFile = Join-Path -Path $TestDrive -ChildPath $testfile
$TestFilePath = Join-Path -Path $TestDrive -ChildPath $testlink
$developerMode = (Get-ItemProperty HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\AppModelUnlock -ErrorAction SilentlyContinue).AllowDevelopmentWithoutDevLicense -eq 1
}

It "Should error correctly when failing to create a symbolic link" -Skip:(Test-IsRoot) {
# This test expects that /sbin exists but is not writable by the user
{ New-Item -ItemType SymbolicLink -Path "/sbin/powershell-test" -Target $FullyQualifiedFolder -ErrorAction Stop } |
AfterEach {
Remove-Item -Path $testFilePath -Force -ErrorAction SilentlyContinue
}

It "Should error correctly when failing to create a symbolic link and not in developer mode" -Skip:(!$IsWindows -or $developerMode -or (Test-IsElevated)) {
{ New-Item -ItemType SymbolicLink -Path $TestFilePath -Target $FullyQualifiedFile -ErrorAction Stop } |
Should -Throw -ErrorId "NewItemSymbolicLinkElevationRequired,Microsoft.PowerShell.Commands.NewItemCommand"
$TestFilePath | Should -Not -Exist
}

It "Should succeed to create a symbolic link without elevation and in developer mode" -Skip:(!$IsWindows -or !$developerMode -or (Test-IsElevated)) {
{ New-Item -ItemType SymbolicLink -Path $TestFilePath -Target $FullyQualifiedFile -ErrorAction Stop } | Should -Not -Throw
$TestFilePath | Should -Exist
}
}