From 04243d03bb65bcbe7bf5d01b9dda7eb84936578e Mon Sep 17 00:00:00 2001 From: Steve Lee Date: Mon, 27 Nov 2023 14:22:56 -0800 Subject: [PATCH 1/3] Fix rendering of DisplayRoot for network PSDrive --- .../engine/Interop/Windows/WNetGetConnection.cs | 12 ++++++++++-- .../New-PSDrive.Tests.ps1 | 6 ++++++ 2 files changed, 16 insertions(+), 2 deletions(-) diff --git a/src/System.Management.Automation/engine/Interop/Windows/WNetGetConnection.cs b/src/System.Management.Automation/engine/Interop/Windows/WNetGetConnection.cs index bf7742526f1..d4c2cb9da05 100644 --- a/src/System.Management.Automation/engine/Interop/Windows/WNetGetConnection.cs +++ b/src/System.Management.Automation/engine/Interop/Windows/WNetGetConnection.cs @@ -52,7 +52,7 @@ internal static int GetUNCForNetworkDrive(char drive, out string? uncPath) if (errorCode == ERROR_SUCCESS) { - uncPath = uncBuffer.Slice((int)bufferSize).ToString(); + uncPath = ToString(uncBuffer.ToArray()); } else if (errorCode == ERROR_MORE_DATA) { @@ -64,7 +64,7 @@ internal static int GetUNCForNetworkDrive(char drive, out string? uncPath) if (errorCode == ERROR_SUCCESS) { - uncPath = uncBuffer.Slice((int)bufferSize).ToString(); + uncPath = ToString(uncBuffer.ToArray()); } } finally @@ -78,5 +78,13 @@ internal static int GetUNCForNetworkDrive(char drive, out string? uncPath) return errorCode; } + + private static string ToString(ushort[] buffer) + { + // trim trailing null character + byte[] asBytes = new byte[(buffer.Length - 1) * sizeof(ushort)]; + Buffer.BlockCopy(buffer, 0, asBytes, 0, asBytes.Length); + return System.Text.Encoding.Unicode.GetString(asBytes); + } } } diff --git a/test/powershell/Modules/Microsoft.PowerShell.Management/New-PSDrive.Tests.ps1 b/test/powershell/Modules/Microsoft.PowerShell.Management/New-PSDrive.Tests.ps1 index 77d76b6ec6a..3894b5a0257 100644 --- a/test/powershell/Modules/Microsoft.PowerShell.Management/New-PSDrive.Tests.ps1 +++ b/test/powershell/Modules/Microsoft.PowerShell.Management/New-PSDrive.Tests.ps1 @@ -17,6 +17,12 @@ Describe "Tests for New-PSDrive cmdlet." -Tag "CI","RequireAdminOnWindows" { { New-PSDrive -Name $PSDriveName -PSProvider FileSystem -Root $RemoteShare -Persist -ErrorAction Stop } | Should -Not -Throw } + It "Network drive initialization on pwsh startup DisplayRoot should have value of share" -Skip:(-not $IsWindows) { + $null = New-PSDrive -Name $PSDriveName -PSProvider FileSystem -Root $RemoteShare -Persist -ErrorAction Stop + $drive = pwsh -noprofile -outputformat XML -command "Get-PSDrive -Name $PSDriveName" + $drive.DisplayRoot | Should -Be $RemoteShare.TrimEnd('\') + } + It "Should throw exception if root is not a remote share." -Skip:(-not $IsWindows) { { New-PSDrive -Name $PSDriveName -PSProvider FileSystem -Root "TestDrive:\" -Persist -ErrorAction Stop } | Should -Throw -ErrorId 'DriveRootNotNetworkPath' } From 69f69f01b7892d512e0a1598ec99f2949f0fd67e Mon Sep 17 00:00:00 2001 From: Steve Lee Date: Tue, 28 Nov 2023 07:37:09 -0800 Subject: [PATCH 2/3] change to use char --- .../Interop/Windows/WNetGetConnection.cs | 29 ++++++------------- 1 file changed, 9 insertions(+), 20 deletions(-) diff --git a/src/System.Management.Automation/engine/Interop/Windows/WNetGetConnection.cs b/src/System.Management.Automation/engine/Interop/Windows/WNetGetConnection.cs index d4c2cb9da05..e8585526e9b 100644 --- a/src/System.Management.Automation/engine/Interop/Windows/WNetGetConnection.cs +++ b/src/System.Management.Automation/engine/Interop/Windows/WNetGetConnection.cs @@ -13,8 +13,8 @@ internal static unsafe partial class Windows { private static bool s_WNetApiNotAvailable; - [LibraryImport("mpr.dll", EntryPoint = "WNetGetConnectionW")] - internal static partial int WNetGetConnection(ReadOnlySpan localName, Span remoteName, ref uint remoteNameLength); + [LibraryImport("mpr.dll", EntryPoint = "WNetGetConnectionW", StringMarshalling = StringMarshalling.Utf16)] + internal static partial int WNetGetConnection(ReadOnlySpan localName, Span remoteName, ref uint remoteNameLength); internal static int GetUNCForNetworkDrive(char drive, out string? uncPath) { @@ -33,11 +33,8 @@ internal static int GetUNCForNetworkDrive(char drive, out string? uncPath) bufferSize = 3; #endif - // TODO: change ushort with char after LibraryImport will support 'ref char' - // without applying the 'System.Runtime.CompilerServices.DisableRuntimeMarshallingAttribute' - // to the assembly. - ReadOnlySpan driveName = stackalloc ushort[] { drive, ':', '\0' }; - Span uncBuffer = stackalloc ushort[(int)bufferSize]; + ReadOnlySpan driveName = stackalloc char[] { drive, ':', '\0' }; + Span uncBuffer = stackalloc char[(int)bufferSize]; int errorCode = ERROR_NO_NETWORK; try @@ -52,39 +49,31 @@ internal static int GetUNCForNetworkDrive(char drive, out string? uncPath) if (errorCode == ERROR_SUCCESS) { - uncPath = ToString(uncBuffer.ToArray()); + uncPath = uncBuffer.Slice(0, (int)bufferSize).ToString(); } else if (errorCode == ERROR_MORE_DATA) { - ushort[]? rentedArray = null; + char[]? rentedArray = null; try { - uncBuffer = rentedArray = ArrayPool.Shared.Rent((int)bufferSize); + uncBuffer = rentedArray = ArrayPool.Shared.Rent((int)bufferSize); errorCode = WNetGetConnection(driveName, uncBuffer, ref bufferSize); if (errorCode == ERROR_SUCCESS) { - uncPath = ToString(uncBuffer.ToArray()); + uncPath = uncBuffer.Slice(0, (int)bufferSize).ToString(); } } finally { if (rentedArray is not null) { - ArrayPool.Shared.Return(rentedArray); + ArrayPool.Shared.Return(rentedArray); } } } return errorCode; } - - private static string ToString(ushort[] buffer) - { - // trim trailing null character - byte[] asBytes = new byte[(buffer.Length - 1) * sizeof(ushort)]; - Buffer.BlockCopy(buffer, 0, asBytes, 0, asBytes.Length); - return System.Text.Encoding.Unicode.GetString(asBytes); - } } } From a411070f1d005464b3e6609d02205652b0677ec2 Mon Sep 17 00:00:00 2001 From: Steve Lee Date: Tue, 28 Nov 2023 09:24:00 -0800 Subject: [PATCH 3/3] remove null terminator --- .../engine/Interop/Windows/WNetGetConnection.cs | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/System.Management.Automation/engine/Interop/Windows/WNetGetConnection.cs b/src/System.Management.Automation/engine/Interop/Windows/WNetGetConnection.cs index e8585526e9b..fcdaeb65d3c 100644 --- a/src/System.Management.Automation/engine/Interop/Windows/WNetGetConnection.cs +++ b/src/System.Management.Automation/engine/Interop/Windows/WNetGetConnection.cs @@ -49,7 +49,8 @@ internal static int GetUNCForNetworkDrive(char drive, out string? uncPath) if (errorCode == ERROR_SUCCESS) { - uncPath = uncBuffer.Slice(0, (int)bufferSize).ToString(); + // exclude null terminator + uncPath = uncBuffer.Slice(0, (int)bufferSize - 1).ToString(); } else if (errorCode == ERROR_MORE_DATA) { @@ -61,7 +62,8 @@ internal static int GetUNCForNetworkDrive(char drive, out string? uncPath) if (errorCode == ERROR_SUCCESS) { - uncPath = uncBuffer.Slice(0, (int)bufferSize).ToString(); + // exclude null terminator + uncPath = uncBuffer.Slice(0, (int)bufferSize - 1).ToString(); } } finally