Thanks to visit codestin.com
Credit goes to github.com

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 @@ -1923,9 +1923,7 @@ internal Pipeline CreatePipeline(RemoteRunspace remoteRunspace)
// the array-form using values if all UsingExpressions are in the same scope, otherwise, we handle the UsingExpression as
// if the remote end is PSv2.
string serverPsVersion = GetRemoteServerPsVersion(remoteRunspace);
System.Management.Automation.PowerShell powershellToUse = (serverPsVersion == PSv2)
? GetPowerShellForPSv2()
: GetPowerShellForPSv3OrLater(serverPsVersion);
System.Management.Automation.PowerShell powershellToUse = GetPowerShellForPSv3OrLater(serverPsVersion);
Pipeline pipeline =
remoteRunspace.CreatePipeline(powershellToUse.Commands.Commands[0].CommandText, true);

Expand All @@ -1946,9 +1944,9 @@ internal Pipeline CreatePipeline(RemoteRunspace remoteRunspace)
/// </summary>
private static string GetRemoteServerPsVersion(RemoteRunspace remoteRunspace)
{
if (remoteRunspace.ConnectionInfo is NewProcessConnectionInfo)
if (remoteRunspace.ConnectionInfo is not WSManConnectionInfo)
{
// This is for Start-Job. The remote end is actually a child local powershell process, so it must be PSv5 or later
// All transport types except for WSManConnectionInfo work with 5.1 or later.
return PSv5OrLater;
}

Expand All @@ -1957,35 +1955,19 @@ private static string GetRemoteServerPsVersion(RemoteRunspace remoteRunspace)
{
// The remote runspace is not opened yet, or it's disconnected before the private data is retrieved.
// In this case we cannot validate if the remote server is running PSv5 or later, so for safety purpose,
// we will handle the $using expressions as if the remote server is PSv2.
return PSv2;
// we will handle the $using expressions as if the remote server is PSv3Orv4.
return PSv3Orv4;
}

// Unfortunately, the PSVersion value in the private data from PSv3 and PSv4 server is always 2.0.
// This got fixed in PSv5, so a PSv5 server will return 5.0. That means we need other way to tell
// if the remote server is PSv2 or PSv3+. After PSv3, remote runspace supports connect/disconnect,
// so we can use it to differentiate PSv2 from PSv3+.
if (remoteRunspace.CanDisconnect)
{
Version serverPsVersion = null;
PSPrimitiveDictionary.TryPathGet(
psApplicationPrivateData,
out serverPsVersion,
PSVersionInfo.PSVersionTableName,
PSVersionInfo.PSVersionName);

if (serverPsVersion != null)
{
return serverPsVersion.Major >= 5 ? PSv5OrLater : PSv3Orv4;
}

// The private data is available but we failed to get the server powershell version.
// This should never happen, but in case it happens, handle the $using expressions
// as if the remote server is PSv2.
Dbg.Assert(false, "Application private data is available but we failed to get the server powershell version. This should never happen.");
}
PSPrimitiveDictionary.TryPathGet(
psApplicationPrivateData,
out Version serverPsVersion,
PSVersionInfo.PSVersionTableName,
PSVersionInfo.PSVersionName);

return PSv2;
// PSv5 server will return 5.0 whereas older versions will always be 2.0. As we don't care about v2
// anymore we can use a simple ternary check here to differenciate v5 using behaviour vs v3/4.
return serverPsVersion != null && serverPsVersion.Major >= 5 ? PSv5OrLater : PSv3Orv4;
}

/// <summary>
Expand Down Expand Up @@ -2059,7 +2041,6 @@ private void WriteErrorCreateRemoteRunspaceFailed(Exception e, Uri uri)
/// </summary>
private const string PSv5OrLater = "PSv5OrLater";
private const string PSv3Orv4 = "PSv3Orv4";
private const string PSv2 = "PSv2";

private System.Management.Automation.PowerShell _powershellV2;
private System.Management.Automation.PowerShell _powershellV3;
Expand Down
33 changes: 31 additions & 2 deletions test/powershell/engine/Remoting/CustomConnection.Tests.ps1
Original file line number Diff line number Diff line change
Expand Up @@ -27,14 +27,14 @@ function Start-PwshProcess

Describe 'NamedPipe Custom Remote Connection Tests' -Tags 'Feature','RequireAdminOnWindows' {

BeforeAll {
BeforeEach {
Import-Module -Name Microsoft.PowerShell.NamedPipeConnection -ErrorAction Stop

$script:PwshProcId = Start-PwshProcess
$script:session = $null
}

AfterAll {
AfterEach {
if ($null -ne $script:session)
{
Remove-PSSession -Session $script:session
Expand All @@ -57,6 +57,10 @@ Describe 'NamedPipe Custom Remote Connection Tests' -Tags 'Feature','RequireAdmi
# Skip this timeout test for non-Windows platforms, because dotNet named pipes do not honor the 'NumberOfServerInstances'
# property and allows connection to a currently connected server.
It 'Verifies timeout error when trying to connect to pwsh process with current connection' -Skip:(!$IsWindows) {
# We start an active connection to have it block the second connection attempt.
$script:session = New-NamedPipeSession -ProcessId $script:PwshProcId -ConnectingTimeout 10 -Name CustomNPConnection -ErrorAction Stop

# The above connection means the named pipe server is busy and won't allow this second connection.
$brokenSession = New-NamedPipeSession -ProcessId $script:PwshProcId -ConnectingTimeout 2 -Name CustomNPConnection -ErrorAction Stop

# Verify expected broken session
Expand All @@ -66,4 +70,29 @@ Describe 'NamedPipe Custom Remote Connection Tests' -Tags 'Feature','RequireAdmi

$brokenSession | Remove-PSSession
}

It 'Passes $using: with PSv5 compatibility in Invoke-Command' {
$script:session = New-NamedPipeSession -ProcessId $script:PwshProcId -ConnectingTimeout 10 -Name CustomNPConnection -ErrorAction Stop

Function Test-Function {
'foo'
}

# The v2 engine will choke on a var with '-' in the name and the v3/v4
# using logic will revert to the v2 branch if $using is in a new scope.
# By using a function and a new scope we can verify the v5 logic is
# used and not the v2-4 one.
$result = Invoke-Command -Session $script:session -ScriptBlock {
${function:Test-Function} = ${using:function:Test-Function}

Test-Function

# Running in a new scope triggers the v2 logic if the v3/v4 branch
# was used.
& { (${using:function:Test-Function}).Trim() }
}
$result.Count | Should -Be 2
$result[0] | Should -BeExactly foo
$result[1] | Should -BeExactly "'foo'"
}
}
3 changes: 2 additions & 1 deletion test/tools/Modules/HelpersCommon/HelpersCommon.psm1
Original file line number Diff line number Diff line change
Expand Up @@ -551,7 +551,8 @@ function Get-HelpNetworkTestCases

# Command discovery does not follow symlinks to network locations for module qualified paths
$networkBlockedError = "CommandNameNotAllowed,Microsoft.PowerShell.Commands.GetHelpCommand"
$scriptBlockedError = "ScriptsNotAllowed"
# This error may change as long as no test cases start failing for other reasons
$scriptBlockedError = "CommandNotFoundException"

$formats = @(
'//{0}/share/{1}'
Expand Down
Loading