diff --git a/src/System.Management.Automation/namespaces/FileSystemProvider.cs b/src/System.Management.Automation/namespaces/FileSystemProvider.cs
index 5e32b3d8b..aa1454128 100644
--- a/src/System.Management.Automation/namespaces/FileSystemProvider.cs
+++ b/src/System.Management.Automation/namespaces/FileSystemProvider.cs
@@ -2434,9 +2434,16 @@ namespace Microsoft.PowerShell.Commands
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)
@@ -7014,10 +7021,32 @@ namespace Microsoft.PowerShell.Commands
///
/// Path of the symbolic link.
/// Path of the target of the symbolic link.
- /// 0 for destination as file and 1 for destination as directory.
+ /// Flag values from SymbolicLinkFlags enum.
/// 1 on successful creation.
[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);
+
+ ///
+ /// Flags used when creating a symbolic link.
+ ///
+ [Flags]
+ internal enum SymbolicLinkFlags
+ {
+ ///
+ /// Symbolic link is a file.
+ ///
+ File = 0,
+
+ ///
+ /// Symbolic link is a directory.
+ ///
+ Directory = 1,
+
+ ///
+ /// Allow creation of symbolic link without elevation. Requires Developer mode.
+ ///
+ AllowUnprivilegedCreate = 2
+ }
///
/// Creates a hard link using the native API.
diff --git a/test/powershell/Modules/Microsoft.PowerShell.Management/New-Item.Tests.ps1 b/test/powershell/Modules/Microsoft.PowerShell.Management/New-Item.Tests.ps1
index 596c92270..9eaf79239 100644
--- a/test/powershell/Modules/Microsoft.PowerShell.Management/New-Item.Tests.ps1
+++ b/test/powershell/Modules/Microsoft.PowerShell.Management/New-Item.Tests.ps1
@@ -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
}
}