From 925c564b11f3ec57466a696540ed271ab700acc9 Mon Sep 17 00:00:00 2001 From: Lee Spottiswood Date: Wed, 28 Dec 2016 13:37:53 +0000 Subject: [PATCH 01/17] fixes summary block typo --- .../NewCimSessionOptionCommand.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Microsoft.Management.Infrastructure.CimCmdlets/NewCimSessionOptionCommand.cs b/src/Microsoft.Management.Infrastructure.CimCmdlets/NewCimSessionOptionCommand.cs index 3e0d11aad25..05d32760100 100644 --- a/src/Microsoft.Management.Infrastructure.CimCmdlets/NewCimSessionOptionCommand.cs +++ b/src/Microsoft.Management.Infrastructure.CimCmdlets/NewCimSessionOptionCommand.cs @@ -29,7 +29,7 @@ public enum ProtocolType /// /// The Cmdlet allows the IT Pro to create a CimSessionOptions object that she/he - /// can subsequently use to crate one or more CimSession connections. The + /// can subsequently use to create one or more CimSession connections. The /// options object holds the CIM Session information that is less commonly set /// and used by the IT Pro, and most commonly defaulted. /// From 125769f56b427a87ee7612af6b73b0ee8fad923e Mon Sep 17 00:00:00 2001 From: Lee Date: Thu, 6 Apr 2017 21:28:59 +0100 Subject: [PATCH 02/17] Adds support for Port parameter for SSH PSSessions --- .../remoting/commands/PSRemotingCmdlet.cs | 12 ++++- .../remoting/commands/PushRunspaceCommand.cs | 2 +- .../remoting/commands/newrunspacecommand.cs | 6 ++- .../remoting/common/RunspaceConnectionInfo.cs | 52 ++++++++++++++++--- .../engine/Remoting/SSHRemotingAPI.Tests.ps1 | 39 ++++++++++++-- 5 files changed, 97 insertions(+), 14 deletions(-) diff --git a/src/System.Management.Automation/engine/remoting/commands/PSRemotingCmdlet.cs b/src/System.Management.Automation/engine/remoting/commands/PSRemotingCmdlet.cs index f8ec2b44aa8..55154a50fb5 100644 --- a/src/System.Management.Automation/engine/remoting/commands/PSRemotingCmdlet.cs +++ b/src/System.Management.Automation/engine/remoting/commands/PSRemotingCmdlet.cs @@ -275,6 +275,7 @@ internal struct SSHConnection public string ComputerName; public string UserName; public string KeyFilePath; + public int Port; } /// @@ -561,6 +562,7 @@ public virtual PSCredential Credential /// to override the policy setting /// [Parameter(ParameterSetName = PSRemotingBaseCmdlet.ComputerNameParameterSet)] + [Parameter(ParameterSetName = PSRemotingBaseCmdlet.SSHHostParameterSet)] [ValidateRange((Int32)1, (Int32)UInt16.MaxValue)] public virtual Int32 Port { get; set; } @@ -820,6 +822,7 @@ internal static void ValidateSpecifiedAuthentication(PSCredential credential, st private const string UserNameParameter = "UserName"; private const string KeyFilePathParameter = "KeyFilePath"; private const string IdentityFilePathAlias = "IdentityFilePath"; + private const string PortParameter = "Port"; #endregion @@ -871,6 +874,10 @@ internal SSHConnection[] ParseSSHConnectionHashTable() { connectionInfo.KeyFilePath = paramValue; } + else if (paramName.Equals(PortParameter, StringComparison.OrdinalIgnoreCase)) + { + connectionInfo.Port = int.Parse(paramValue); + } else { throw new PSArgumentException( @@ -1312,7 +1319,7 @@ protected void CreateHelpersForSpecifiedSSHComputerNames() foreach (string computerName in ResolvedComputerNames) { - var sshConnectionInfo = new SSHConnectionInfo(this.UserName, computerName, this.KeyFilePath); + var sshConnectionInfo = new SSHConnectionInfo(this.UserName, computerName, this.KeyFilePath, this.Port); var typeTable = TypeTable.LoadDefaultTypeFiles(); var remoteRunspace = RunspaceFactory.CreateRunspace(sshConnectionInfo, this.Host, typeTable) as RemoteRunspace; var pipeline = CreatePipeline(remoteRunspace); @@ -1334,7 +1341,8 @@ protected void CreateHelpersForSpecifiedSSHHashComputerNames() var sshConnectionInfo = new SSHConnectionInfo( sshConnection.UserName, sshConnection.ComputerName, - sshConnection.KeyFilePath); + sshConnection.KeyFilePath, + sshConnection.Port); var typeTable = TypeTable.LoadDefaultTypeFiles(); var remoteRunspace = RunspaceFactory.CreateRunspace(sshConnectionInfo, this.Host, typeTable) as RemoteRunspace; var pipeline = CreatePipeline(remoteRunspace); diff --git a/src/System.Management.Automation/engine/remoting/commands/PushRunspaceCommand.cs b/src/System.Management.Automation/engine/remoting/commands/PushRunspaceCommand.cs index c1c81cea939..22ecae6e59d 100644 --- a/src/System.Management.Automation/engine/remoting/commands/PushRunspaceCommand.cs +++ b/src/System.Management.Automation/engine/remoting/commands/PushRunspaceCommand.cs @@ -1270,7 +1270,7 @@ private RemoteRunspace GetRunspaceForContainerSession() /// private RemoteRunspace GetRunspaceForSSHSession() { - var sshConnectionInfo = new SSHConnectionInfo(this.UserName, ResolveComputerName(HostName), this.KeyFilePath); + var sshConnectionInfo = new SSHConnectionInfo(this.UserName, ResolveComputerName(HostName), this.KeyFilePath, this.Port); var typeTable = TypeTable.LoadDefaultTypeFiles(); var remoteRunspace = RunspaceFactory.CreateRunspace(sshConnectionInfo, this.Host, typeTable) as RemoteRunspace; remoteRunspace.Open(); diff --git a/src/System.Management.Automation/engine/remoting/commands/newrunspacecommand.cs b/src/System.Management.Automation/engine/remoting/commands/newrunspacecommand.cs index 386e3205413..ea5505e7a4b 100644 --- a/src/System.Management.Automation/engine/remoting/commands/newrunspacecommand.cs +++ b/src/System.Management.Automation/engine/remoting/commands/newrunspacecommand.cs @@ -1078,7 +1078,8 @@ private List CreateRunspacesForSSHHostParameterSet() var sshConnectionInfo = new SSHConnectionInfo( this.UserName, computerName, - this.KeyFilePath); + this.KeyFilePath, + this.Port); var typeTable = TypeTable.LoadDefaultTypeFiles(); remoteRunspaces.Add(RunspaceFactory.CreateRunspace(sshConnectionInfo, this.Host, typeTable) as RemoteRunspace); } @@ -1095,7 +1096,8 @@ private List CreateRunspacesForSSHHostHashParameterSet() var sshConnectionInfo = new SSHConnectionInfo( sshConnection.UserName, sshConnection.ComputerName, - sshConnection.KeyFilePath); + sshConnection.KeyFilePath, + sshConnection.Port); var typeTable = TypeTable.LoadDefaultTypeFiles(); remoteRunspaces.Add(RunspaceFactory.CreateRunspace(sshConnectionInfo, this.Host, typeTable) as RemoteRunspace); } diff --git a/src/System.Management.Automation/engine/remoting/common/RunspaceConnectionInfo.cs b/src/System.Management.Automation/engine/remoting/common/RunspaceConnectionInfo.cs index b50f21da228..b6cfb9e096e 100644 --- a/src/System.Management.Automation/engine/remoting/common/RunspaceConnectionInfo.cs +++ b/src/System.Management.Automation/engine/remoting/common/RunspaceConnectionInfo.cs @@ -1852,6 +1852,15 @@ private string KeyFilePath set; } + /// + /// Port for connection + /// + private int Port + { + get; + set; + } + #endregion #region Constructors @@ -1868,16 +1877,27 @@ private SSHConnectionInfo() /// User Name /// Computer Name /// Key File Path + /// Port number for connection (default 22) public SSHConnectionInfo( string userName, string computerName, - string keyFilePath) + string keyFilePath, + int port) { if (computerName == null) { throw new PSArgumentNullException("computerName"); } + if ((port < MinPort || port > MaxPort)) + { + String message = + PSRemotingErrorInvariants.FormatResourceString( + RemotingErrorIdStrings.PortIsOutOfRange, port); + ArgumentException e = new ArgumentException(message); + throw e; + } this.UserName = userName; this.ComputerName = computerName; this.KeyFilePath = keyFilePath; + this.Port = (port != 0) ? port : DefaultPort; } #endregion @@ -1930,6 +1950,7 @@ internal override RunspaceConnectionInfo InternalCopy() newCopy.ComputerName = this.ComputerName; newCopy.UserName = this.UserName; newCopy.KeyFilePath = this.KeyFilePath; + newCopy.Port = this.Port; return newCopy; } @@ -2004,14 +2025,14 @@ internal System.Diagnostics.Process StartSSHProcess( } arguments = (string.IsNullOrEmpty(domainName)) ? - string.Format(CultureInfo.InvariantCulture, @"-i ""{0}"" {1}@{2} -s powershell", this.KeyFilePath, userName, this.ComputerName) : - string.Format(CultureInfo.InvariantCulture, @"-i ""{0}"" -l {1}@{2} {3} -s powershell", this.KeyFilePath, userName, domainName, this.ComputerName); + string.Format(CultureInfo.InvariantCulture, @"-i ""{0}"" {1}@{2} -p {3} -s powershell", this.KeyFilePath, userName, this.ComputerName, this.Port) : + string.Format(CultureInfo.InvariantCulture, @"-i ""{0}"" -l {1}@{2} {3} -p {4} -s powershell", this.KeyFilePath, userName, domainName, this.ComputerName, this.Port); } else { arguments = (string.IsNullOrEmpty(domainName)) ? - string.Format(CultureInfo.InvariantCulture, @"{0}@{1} -s powershell", userName, this.ComputerName) : - string.Format(CultureInfo.InvariantCulture, @"-l {0}@{1} {2} -s powershell", userName, domainName, this.ComputerName); + string.Format(CultureInfo.InvariantCulture, @"{0}@{1} -p {2} -s powershell", userName, this.ComputerName, this.Port) : + string.Format(CultureInfo.InvariantCulture, @"-l {0}@{1} {2} -p {3} -s powershell", userName, domainName, this.ComputerName, this.Port); } System.Diagnostics.ProcessStartInfo startInfo = new System.Diagnostics.ProcessStartInfo( @@ -2037,7 +2058,26 @@ private string GetCurrentUserName() #endif } -#endregion + #endregion + + #region Constants + + /// + /// Default value for port + /// + private const int DefaultPort = 22; + + /// + /// Maximum value for port + /// + private const int MaxPort = 0xFFFF; + + /// + /// Minimum value for port + /// + private const int MinPort = 0; + + #endregion #region SSH Process Creation diff --git a/test/powershell/engine/Remoting/SSHRemotingAPI.Tests.ps1 b/test/powershell/engine/Remoting/SSHRemotingAPI.Tests.ps1 index 9a1c0073642..1913285bb6a 100644 --- a/test/powershell/engine/Remoting/SSHRemotingAPI.Tests.ps1 +++ b/test/powershell/engine/Remoting/SSHRemotingAPI.Tests.ps1 @@ -1,3 +1,5 @@ +Import-Module $PSScriptRoot\..\..\Common\Test.Helpers.psm1 + Describe "SSH Remoting API Tests" -Tags "Feature" { Context "SSHConnectionInfo Class Tests" { @@ -9,7 +11,8 @@ Describe "SSH Remoting API Tests" -Tags "Feature" { [System.Management.Automation.Runspaces.SSHConnectionInfo]::new( [System.Management.Automation.Internal.AutomationNull]::Value, "localhost", - [System.Management.Automation.Internal.AutomationNull]::Value) + [System.Management.Automation.Internal.AutomationNull]::Value, + 0) throw "SSHConnectionInfo constructor did not throw expected PSArgumentNullException exception" } @@ -26,7 +29,8 @@ Describe "SSH Remoting API Tests" -Tags "Feature" { [System.Management.Automation.Runspaces.SSHConnectionInfo]::new( "UserName", [System.Management.Automation.Internal.AutomationNull]::Value, - [System.Management.Automation.Internal.AutomationNull]::Value) + [System.Management.Automation.Internal.AutomationNull]::Value, + 0) throw "SSHConnectionInfo constructor did not throw expected PSArgumentNullException exception" } @@ -43,7 +47,8 @@ Describe "SSH Remoting API Tests" -Tags "Feature" { $sshConnectionInfo = [System.Management.Automation.Runspaces.SSHConnectionInfo]::new( "UserName", "localhost", - "NoValidKeyFilePath") + "NoValidKeyFilePath", + 22) $rs = [runspacefactory]::CreateRunspace($sshConnectionInfo) $rs.Open() @@ -61,5 +66,33 @@ Describe "SSH Remoting API Tests" -Tags "Feature" { ($expectedFileNotFoundExecption.GetType().FullName) | Should Be "System.IO.FileNotFoundException" } } + + It "SSHConnectionInfo should throw argument exception for invalid port (non 16bit uint)" { + try + { + + $File = Get-ChildItem -File | select -First 1 + $sshConnectionInfo = [System.Management.Automation.Runspaces.SSHConnectionInfo]::new( + "UserName", + "localhost", + "ValidKeyFilePath", + 99999) + + $rs = [runspacefactory]::CreateRunspace($sshConnectionInfo) + $rs.Open() + + throw "SSHConnectionInfo did not throw expected ArgumentException exception" + } + catch + { + $expectedArgumentException = $_.Exception + if (($_.Exception -ne $null) -and ($_.Exception.InnerException -ne $null)) + { + $expectedArgumentException = $_.Exception.InnerException + } + + ($expectedArgumentException.GetType().FullName) | Should Be "System.ArgumentException" + } + } } } From b525b70d67d0e85e88524b4b35f4c9d3b245497a Mon Sep 17 00:00:00 2001 From: Lee Date: Fri, 7 Apr 2017 19:33:35 +0100 Subject: [PATCH 03/17] Reverted back to master, modified based on PR feedback --- .../engine/Remoting/SSHRemotingAPI.Tests.ps1 | 57 ++++++------------- 1 file changed, 16 insertions(+), 41 deletions(-) diff --git a/test/powershell/engine/Remoting/SSHRemotingAPI.Tests.ps1 b/test/powershell/engine/Remoting/SSHRemotingAPI.Tests.ps1 index 56f193b0959..9487b4ef5fc 100644 --- a/test/powershell/engine/Remoting/SSHRemotingAPI.Tests.ps1 +++ b/test/powershell/engine/Remoting/SSHRemotingAPI.Tests.ps1 @@ -1,41 +1,16 @@ +Import-Module $PSScriptRoot\..\..\Common\Test.Helpers.psm1 + Describe "SSH Remoting API Tests" -Tags "Feature" { Context "SSHConnectionInfo Class Tests" { - It "SSHConnectionInfo constructor should throw null argument exception for null UserName parameter" { - - try - { - [System.Management.Automation.Runspaces.SSHConnectionInfo]::new( - [System.Management.Automation.Internal.AutomationNull]::Value, - "localhost", - [System.Management.Automation.Internal.AutomationNull]::Value, - 0) - - throw "SSHConnectionInfo constructor did not throw expected PSArgumentNullException exception" - } - catch - { - $_.FullyQualifiedErrorId | Should Match "PSArgumentNullException" - } - } - It "SSHConnectionInfo constructor should throw null argument exception for null HostName parameter" { - try - { - [System.Management.Automation.Runspaces.SSHConnectionInfo]::new( - "UserName", - [System.Management.Automation.Internal.AutomationNull]::Value, - [System.Management.Automation.Internal.AutomationNull]::Value, - 0) - - throw "SSHConnectionInfo constructor did not throw expected PSArgumentNullException exception" - } - catch - { - $_.FullyQualifiedErrorId | Should Match "PSArgumentNullException" - } + { [System.Management.Automation.Runspaces.SSHConnectionInfo]::new( + "UserName", + [System.Management.Automation.Internal.AutomationNull]::Value, + [System.Management.Automation.Internal.AutomationNull]::Value, + 0) } | ShouldBeErrorId "PSArgumentNullException" } It "SSHConnectionInfo should throw file not found exception for invalid key file path" { @@ -50,18 +25,18 @@ Describe "SSH Remoting API Tests" -Tags "Feature" { $rs = [runspacefactory]::CreateRunspace($sshConnectionInfo) $rs.Open() - - throw "SSHConnectionInfo did not throw expected FileNotFoundException exception" + + throw "No Exception!" } catch { - $expectedFileNotFoundExecption = $null - if (($_.Exception -ne $null) -and ($_.Exception.InnerException -ne $null)) + $expectedFileNotFoundException = $_.Exception + if ($_.Exception.InnerException -ne $null -and $_.Exception.InnerException.InnerException -ne $null) { - $expectedFileNotFoundExecption = $_.Exception.InnerException.InnerException + $expectedFileNotFoundException = $_.Exception.InnerException.InnerException } - - ($expectedFileNotFoundExecption.GetType().FullName) | Should Be "System.IO.FileNotFoundException" + + $expectedFileNotFoundException | Should BeOfType "System.IO.FileNotFoundException" } } @@ -84,12 +59,12 @@ Describe "SSH Remoting API Tests" -Tags "Feature" { catch { $expectedArgumentException = $_.Exception - if (($_.Exception -ne $null) -and ($_.Exception.InnerException -ne $null)) + if ($_.Exception.InnerException -ne $null) { $expectedArgumentException = $_.Exception.InnerException } - ($expectedArgumentException.GetType().FullName) | Should Be "System.ArgumentException" + $expectedArgumentException | Should BeOfType "System.ArgumentException" } } } From aa658fb561462baad4dbcaf324a8f0d228f8c4da Mon Sep 17 00:00:00 2001 From: Lee Date: Fri, 7 Apr 2017 19:37:35 +0100 Subject: [PATCH 04/17] Update exception message --- test/powershell/engine/Remoting/SSHRemotingAPI.Tests.ps1 | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/test/powershell/engine/Remoting/SSHRemotingAPI.Tests.ps1 b/test/powershell/engine/Remoting/SSHRemotingAPI.Tests.ps1 index 9487b4ef5fc..5239fe38c59 100644 --- a/test/powershell/engine/Remoting/SSHRemotingAPI.Tests.ps1 +++ b/test/powershell/engine/Remoting/SSHRemotingAPI.Tests.ps1 @@ -53,8 +53,8 @@ Describe "SSH Remoting API Tests" -Tags "Feature" { $rs = [runspacefactory]::CreateRunspace($sshConnectionInfo) $rs.Open() - - throw "SSHConnectionInfo did not throw expected ArgumentException exception" + + throw "No Exception!" } catch { From 5ff64456961e2adb87c62ac3d321d5c6072f486a Mon Sep 17 00:00:00 2001 From: Lee Date: Fri, 7 Apr 2017 20:16:49 +0100 Subject: [PATCH 05/17] remove unused line --- test/powershell/engine/Remoting/SSHRemotingAPI.Tests.ps1 | 2 -- 1 file changed, 2 deletions(-) diff --git a/test/powershell/engine/Remoting/SSHRemotingAPI.Tests.ps1 b/test/powershell/engine/Remoting/SSHRemotingAPI.Tests.ps1 index 5239fe38c59..f4e0cbbd581 100644 --- a/test/powershell/engine/Remoting/SSHRemotingAPI.Tests.ps1 +++ b/test/powershell/engine/Remoting/SSHRemotingAPI.Tests.ps1 @@ -43,8 +43,6 @@ Describe "SSH Remoting API Tests" -Tags "Feature" { It "SSHConnectionInfo should throw argument exception for invalid port (non 16bit uint)" { try { - - $File = Get-ChildItem -File | select -First 1 $sshConnectionInfo = [System.Management.Automation.Runspaces.SSHConnectionInfo]::new( "UserName", "localhost", From 6f7057e343e1bddca1429ec7dbe4b5e8240e780c Mon Sep 17 00:00:00 2001 From: Lee Date: Sun, 9 Apr 2017 22:12:47 +0100 Subject: [PATCH 06/17] Add existing constructor back in as to not break public contract --- .../remoting/common/RunspaceConnectionInfo.cs | 27 +++++++++++++++++++ 1 file changed, 27 insertions(+) diff --git a/src/System.Management.Automation/engine/remoting/common/RunspaceConnectionInfo.cs b/src/System.Management.Automation/engine/remoting/common/RunspaceConnectionInfo.cs index f5b00371588..29656f5d8be 100644 --- a/src/System.Management.Automation/engine/remoting/common/RunspaceConnectionInfo.cs +++ b/src/System.Management.Automation/engine/remoting/common/RunspaceConnectionInfo.cs @@ -1871,6 +1871,33 @@ private int Port private SSHConnectionInfo() { } + /// + /// Constructor + /// + /// User Name + /// Computer Name + /// Key File Path + public SSHConnectionInfo( + string userName, + string computerName, + string keyFilePath) + { + if (computerName == null) { throw new PSArgumentNullException("computerName"); } + if ((port < MinPort || port > MaxPort)) + { + String message = + PSRemotingErrorInvariants.FormatResourceString( + RemotingErrorIdStrings.PortIsOutOfRange, port); + ArgumentException e = new ArgumentException(message); + throw e; + } + + this.UserName = userName; + this.ComputerName = computerName; + this.KeyFilePath = keyFilePath; + this.Port = DefaultPort; + } + /// /// Constructor /// From 6a6e6d8502031ec8c131bf8011c368cda79eae35 Mon Sep 17 00:00:00 2001 From: Lee Date: Sun, 9 Apr 2017 22:14:18 +0100 Subject: [PATCH 07/17] remove port check --- .../engine/remoting/common/RunspaceConnectionInfo.cs | 8 -------- 1 file changed, 8 deletions(-) diff --git a/src/System.Management.Automation/engine/remoting/common/RunspaceConnectionInfo.cs b/src/System.Management.Automation/engine/remoting/common/RunspaceConnectionInfo.cs index 29656f5d8be..a098ca86504 100644 --- a/src/System.Management.Automation/engine/remoting/common/RunspaceConnectionInfo.cs +++ b/src/System.Management.Automation/engine/remoting/common/RunspaceConnectionInfo.cs @@ -1883,14 +1883,6 @@ public SSHConnectionInfo( string keyFilePath) { if (computerName == null) { throw new PSArgumentNullException("computerName"); } - if ((port < MinPort || port > MaxPort)) - { - String message = - PSRemotingErrorInvariants.FormatResourceString( - RemotingErrorIdStrings.PortIsOutOfRange, port); - ArgumentException e = new ArgumentException(message); - throw e; - } this.UserName = userName; this.ComputerName = computerName; From e4fc798265d77b0ed0fc3d880e3ef25590e0e916 Mon Sep 17 00:00:00 2001 From: Lee Date: Mon, 10 Apr 2017 21:47:58 +0100 Subject: [PATCH 08/17] pass nested inner exception straight to Should --- test/powershell/engine/Remoting/SSHRemotingAPI.Tests.ps1 | 8 +------- 1 file changed, 1 insertion(+), 7 deletions(-) diff --git a/test/powershell/engine/Remoting/SSHRemotingAPI.Tests.ps1 b/test/powershell/engine/Remoting/SSHRemotingAPI.Tests.ps1 index f4e0cbbd581..5be1a0540fa 100644 --- a/test/powershell/engine/Remoting/SSHRemotingAPI.Tests.ps1 +++ b/test/powershell/engine/Remoting/SSHRemotingAPI.Tests.ps1 @@ -30,13 +30,7 @@ Describe "SSH Remoting API Tests" -Tags "Feature" { } catch { - $expectedFileNotFoundException = $_.Exception - if ($_.Exception.InnerException -ne $null -and $_.Exception.InnerException.InnerException -ne $null) - { - $expectedFileNotFoundException = $_.Exception.InnerException.InnerException - } - - $expectedFileNotFoundException | Should BeOfType "System.IO.FileNotFoundException" + $_.Exception.InnerException.InnerException | Should BeOfType "System.IO.FileNotFoundException" } } From dc7a4f3969efa8420eb6fe66b2c5835e1cb3b556 Mon Sep 17 00:00:00 2001 From: Lee Date: Mon, 10 Apr 2017 21:50:07 +0100 Subject: [PATCH 09/17] dispose runspace after each test --- test/powershell/engine/Remoting/SSHRemotingAPI.Tests.ps1 | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/test/powershell/engine/Remoting/SSHRemotingAPI.Tests.ps1 b/test/powershell/engine/Remoting/SSHRemotingAPI.Tests.ps1 index 5be1a0540fa..eeb71b4436f 100644 --- a/test/powershell/engine/Remoting/SSHRemotingAPI.Tests.ps1 +++ b/test/powershell/engine/Remoting/SSHRemotingAPI.Tests.ps1 @@ -4,6 +4,12 @@ Describe "SSH Remoting API Tests" -Tags "Feature" { Context "SSHConnectionInfo Class Tests" { + AfterEach { + if ($rs -ne $null) { + $rs.Dispose() + } + } + It "SSHConnectionInfo constructor should throw null argument exception for null HostName parameter" { { [System.Management.Automation.Runspaces.SSHConnectionInfo]::new( From de296a474cdafdb258484b230b8afe30fb262d6b Mon Sep 17 00:00:00 2001 From: Lee Date: Fri, 14 Apr 2017 22:19:04 +0100 Subject: [PATCH 10/17] Add SSHHostParameterSet attribute for Invoke-Command Port property --- .../engine/remoting/commands/InvokeCommandCommand.cs | 1 + 1 file changed, 1 insertion(+) diff --git a/src/System.Management.Automation/engine/remoting/commands/InvokeCommandCommand.cs b/src/System.Management.Automation/engine/remoting/commands/InvokeCommandCommand.cs index 0b7640c97c3..4850a064cce 100644 --- a/src/System.Management.Automation/engine/remoting/commands/InvokeCommandCommand.cs +++ b/src/System.Management.Automation/engine/remoting/commands/InvokeCommandCommand.cs @@ -223,6 +223,7 @@ public override PSCredential Credential /// [Parameter(ParameterSetName = InvokeCommandCommand.ComputerNameParameterSet)] [Parameter(ParameterSetName = InvokeCommandCommand.FilePathComputerNameParameterSet)] + [Parameter(ParameterSetName = InvokeCommandCommand.SSHHostParameterSet)] [ValidateRange((Int32)1, (Int32)UInt16.MaxValue)] public override Int32 Port { From 153ca565e5b83bbd572971d395654f4b9b4ac1dc Mon Sep 17 00:00:00 2001 From: Lee Date: Fri, 14 Apr 2017 23:42:05 +0100 Subject: [PATCH 11/17] Update ParseSSHConnectionHashTable method to accept Port value as integer --- .../remoting/commands/PSRemotingCmdlet.cs | 54 +++++++++++-------- 1 file changed, 31 insertions(+), 23 deletions(-) diff --git a/src/System.Management.Automation/engine/remoting/commands/PSRemotingCmdlet.cs b/src/System.Management.Automation/engine/remoting/commands/PSRemotingCmdlet.cs index 03e10e43598..4ad3740e53c 100644 --- a/src/System.Management.Automation/engine/remoting/commands/PSRemotingCmdlet.cs +++ b/src/System.Management.Automation/engine/remoting/commands/PSRemotingCmdlet.cs @@ -854,34 +854,42 @@ internal SSHConnection[] ParseSSHConnectionHashTable() throw new PSArgumentException(RemotingErrorIdStrings.InvalidSSHConnectionParameter); } - string paramValue = item[paramName] as string; - if (string.IsNullOrEmpty(paramValue)) + if (paramName.Equals(PortParameter, StringComparison.OrdinalIgnoreCase)) { - throw new PSArgumentException(RemotingErrorIdStrings.InvalidSSHConnectionParameter); - } + if (item[paramName] is int == false) + { + throw new PSArgumentException(RemotingErrorIdStrings.InvalidSSHConnectionParameter); + } - if (paramName.Equals(ComputerNameParameter, StringComparison.OrdinalIgnoreCase) || paramName.Equals(HostNameAlias, StringComparison.OrdinalIgnoreCase)) - { - var resolvedComputerName = ResolveComputerName(paramValue); - ValidateComputerName(new string[] { resolvedComputerName }); - connectionInfo.ComputerName = resolvedComputerName; - } - else if (paramName.Equals(UserNameParameter, StringComparison.OrdinalIgnoreCase)) - { - connectionInfo.UserName = paramValue; - } - else if (paramName.Equals(KeyFilePathParameter, StringComparison.OrdinalIgnoreCase) || paramName.Equals(IdentityFilePathAlias, StringComparison.OrdinalIgnoreCase)) - { - connectionInfo.KeyFilePath = paramValue; - } - else if (paramName.Equals(PortParameter, StringComparison.OrdinalIgnoreCase)) - { - connectionInfo.Port = int.Parse(paramValue); + connectionInfo.Port = Convert.ToInt32(item[paramName]); } else { - throw new PSArgumentException( - StringUtil.Format(RemotingErrorIdStrings.UnknownSSHConnectionParameter, paramName)); + string paramValue = item[paramName] as string; + if (string.IsNullOrEmpty(paramValue)) + { + throw new PSArgumentException(RemotingErrorIdStrings.InvalidSSHConnectionParameter); + } + + if (paramName.Equals(ComputerNameParameter, StringComparison.OrdinalIgnoreCase) || paramName.Equals(HostNameAlias, StringComparison.OrdinalIgnoreCase)) + { + var resolvedComputerName = ResolveComputerName(paramValue); + ValidateComputerName(new string[] { resolvedComputerName }); + connectionInfo.ComputerName = resolvedComputerName; + } + else if (paramName.Equals(UserNameParameter, StringComparison.OrdinalIgnoreCase)) + { + connectionInfo.UserName = paramValue; + } + else if (paramName.Equals(KeyFilePathParameter, StringComparison.OrdinalIgnoreCase) || paramName.Equals(IdentityFilePathAlias, StringComparison.OrdinalIgnoreCase)) + { + connectionInfo.KeyFilePath = paramValue; + } + else + { + throw new PSArgumentException( + StringUtil.Format(RemotingErrorIdStrings.UnknownSSHConnectionParameter, paramName)); + } } } From 0ccd8f26307835a6991424dbb1104150ba68e484 Mon Sep 17 00:00:00 2001 From: Lee Date: Fri, 14 Apr 2017 23:58:41 +0100 Subject: [PATCH 12/17] Add helper method for validating port in range. Refactor port parameter constructor overload to use original constructor --- .../remoting/common/RunspaceConnectionInfo.cs | 70 ++++++++----------- 1 file changed, 29 insertions(+), 41 deletions(-) diff --git a/src/System.Management.Automation/engine/remoting/common/RunspaceConnectionInfo.cs b/src/System.Management.Automation/engine/remoting/common/RunspaceConnectionInfo.cs index a098ca86504..6c0097c1424 100644 --- a/src/System.Management.Automation/engine/remoting/common/RunspaceConnectionInfo.cs +++ b/src/System.Management.Automation/engine/remoting/common/RunspaceConnectionInfo.cs @@ -355,6 +355,32 @@ internal virtual RunspaceConnectionInfo InternalCopy() throw new PSNotImplementedException(); } + internal virtual void ValidatePortInRange(int port) + { + if ((port < MinPort || port > MaxPort)) + { + String message = + PSRemotingErrorInvariants.FormatResourceString( + RemotingErrorIdStrings.PortIsOutOfRange, port); + ArgumentException e = new ArgumentException(message); + throw e; + } + } + + #endregion + + #region Constants + + /// + /// Maximum value for port + /// + protected const int MaxPort = 0xFFFF; + + /// + /// Minimum value for port + /// + protected const int MinPort = 0; + #endregion } @@ -1172,6 +1198,7 @@ internal void ConstructUri(String scheme, String computerName, Nullable p if (port.HasValue) { + ValidatePortRange(port.Value); // resolve to default ports if required if (port.Value == DefaultPort) { @@ -1185,14 +1212,6 @@ internal void ConstructUri(String scheme, String computerName, Nullable p PortSetting = port.Value; UseDefaultWSManPort = false; } - else if ((port.Value < MinPort || port.Value > MaxPort)) - { - String message = - PSRemotingErrorInvariants.FormatResourceString( - RemotingErrorIdStrings.PortIsOutOfRange, port); - ArgumentException e = new ArgumentException(message); - throw e; - } else { PortSetting = port.Value; @@ -1391,16 +1410,6 @@ internal bool UseDefaultWSManPort /// private const string DefaultComputerName = "localhost"; - /// - /// Maximum value for port - /// - private const int MaxPort = 0xFFFF; - - /// - /// Minimum value for port - /// - private const int MinPort = 0; - /// /// String that represents the local host Uri /// @@ -1901,21 +1910,10 @@ public SSHConnectionInfo( string userName, string computerName, string keyFilePath, - int port) + int port) : this(userName, computerName, keyFilePath) { - if (computerName == null) { throw new PSArgumentNullException("computerName"); } - if ((port < MinPort || port > MaxPort)) - { - String message = - PSRemotingErrorInvariants.FormatResourceString( - RemotingErrorIdStrings.PortIsOutOfRange, port); - ArgumentException e = new ArgumentException(message); - throw e; - } + ValidatePortRange(port); - this.UserName = userName; - this.ComputerName = computerName; - this.KeyFilePath = keyFilePath; this.Port = (port != 0) ? port : DefaultPort; } @@ -2086,16 +2084,6 @@ private string GetCurrentUserName() /// private const int DefaultPort = 22; - /// - /// Maximum value for port - /// - private const int MaxPort = 0xFFFF; - - /// - /// Minimum value for port - /// - private const int MinPort = 0; - #endregion #region SSH Process Creation From 7a6535cc11af9ce4b38e1a206c8ef299dcda631f Mon Sep 17 00:00:00 2001 From: Lee Date: Sat, 15 Apr 2017 00:13:44 +0100 Subject: [PATCH 13/17] rename method --- .../engine/remoting/common/RunspaceConnectionInfo.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/System.Management.Automation/engine/remoting/common/RunspaceConnectionInfo.cs b/src/System.Management.Automation/engine/remoting/common/RunspaceConnectionInfo.cs index 6c0097c1424..9ca8188f3c5 100644 --- a/src/System.Management.Automation/engine/remoting/common/RunspaceConnectionInfo.cs +++ b/src/System.Management.Automation/engine/remoting/common/RunspaceConnectionInfo.cs @@ -1198,7 +1198,7 @@ internal void ConstructUri(String scheme, String computerName, Nullable p if (port.HasValue) { - ValidatePortRange(port.Value); + ValidatePortInRange(port.Value); // resolve to default ports if required if (port.Value == DefaultPort) { @@ -1912,7 +1912,7 @@ public SSHConnectionInfo( string keyFilePath, int port) : this(userName, computerName, keyFilePath) { - ValidatePortRange(port); + ValidatePortInRange(port); this.Port = (port != 0) ? port : DefaultPort; } From c8f1a10226b3115bdc63c9006f683df65f64e6a0 Mon Sep 17 00:00:00 2001 From: Lee Date: Mon, 17 Apr 2017 19:44:28 +0100 Subject: [PATCH 14/17] Adds GetSSHConnectionStringParameter and GetSSHConnectionIntParameter methods for retrieving SSHConnection hashtable values --- .../remoting/commands/PSRemotingCmdlet.cs | 72 ++++++++++--------- 1 file changed, 40 insertions(+), 32 deletions(-) diff --git a/src/System.Management.Automation/engine/remoting/commands/PSRemotingCmdlet.cs b/src/System.Management.Automation/engine/remoting/commands/PSRemotingCmdlet.cs index 4ad3740e53c..bef28052c97 100644 --- a/src/System.Management.Automation/engine/remoting/commands/PSRemotingCmdlet.cs +++ b/src/System.Management.Automation/engine/remoting/commands/PSRemotingCmdlet.cs @@ -854,42 +854,28 @@ internal SSHConnection[] ParseSSHConnectionHashTable() throw new PSArgumentException(RemotingErrorIdStrings.InvalidSSHConnectionParameter); } - if (paramName.Equals(PortParameter, StringComparison.OrdinalIgnoreCase)) + if (paramName.Equals(ComputerNameParameter, StringComparison.OrdinalIgnoreCase) || paramName.Equals(HostNameAlias, StringComparison.OrdinalIgnoreCase)) { - if (item[paramName] is int == false) - { - throw new PSArgumentException(RemotingErrorIdStrings.InvalidSSHConnectionParameter); - } - - connectionInfo.Port = Convert.ToInt32(item[paramName]); + var resolvedComputerName = ResolveComputerName(GetSSHConnectionStringParameter(item[paramName])); + ValidateComputerName(new string[] { resolvedComputerName }); + connectionInfo.ComputerName = resolvedComputerName; + } + else if (paramName.Equals(UserNameParameter, StringComparison.OrdinalIgnoreCase)) + { + connectionInfo.UserName = GetSSHConnectionStringParameter(item[paramName]); + } + else if (paramName.Equals(KeyFilePathParameter, StringComparison.OrdinalIgnoreCase) || paramName.Equals(IdentityFilePathAlias, StringComparison.OrdinalIgnoreCase)) + { + connectionInfo.KeyFilePath = GetSSHConnectionStringParameter(item[paramName]); + } + else if (paramName.Equals(PortParameter, StringComparison.OrdinalIgnoreCase)) + { + connectionInfo.Port = GetSSHConnectionIntParameter(item[paramName]); } else { - string paramValue = item[paramName] as string; - if (string.IsNullOrEmpty(paramValue)) - { - throw new PSArgumentException(RemotingErrorIdStrings.InvalidSSHConnectionParameter); - } - - if (paramName.Equals(ComputerNameParameter, StringComparison.OrdinalIgnoreCase) || paramName.Equals(HostNameAlias, StringComparison.OrdinalIgnoreCase)) - { - var resolvedComputerName = ResolveComputerName(paramValue); - ValidateComputerName(new string[] { resolvedComputerName }); - connectionInfo.ComputerName = resolvedComputerName; - } - else if (paramName.Equals(UserNameParameter, StringComparison.OrdinalIgnoreCase)) - { - connectionInfo.UserName = paramValue; - } - else if (paramName.Equals(KeyFilePathParameter, StringComparison.OrdinalIgnoreCase) || paramName.Equals(IdentityFilePathAlias, StringComparison.OrdinalIgnoreCase)) - { - connectionInfo.KeyFilePath = paramValue; - } - else - { - throw new PSArgumentException( - StringUtil.Format(RemotingErrorIdStrings.UnknownSSHConnectionParameter, paramName)); - } + throw new PSArgumentException( + StringUtil.Format(RemotingErrorIdStrings.UnknownSSHConnectionParameter, paramName)); } } @@ -996,6 +982,28 @@ protected void ValidateComputerName(String[] computerNames) } } + private static string GetSSHConnectionStringParameter(object param) + { + var paramValue = param as string; + if (string.IsNullOrEmpty(paramValue)) + { + throw new PSArgumentException(RemotingErrorIdStrings.InvalidSSHConnectionParameter); + } + + return paramValue; + } + + private static int GetSSHConnectionIntParameter(object param) + { + int? paramValue = param as int?; + if (paramValue == null) + { + throw new PSArgumentException(RemotingErrorIdStrings.InvalidSSHConnectionParameter); + } + + return paramValue.Value; + } + #endregion Private Methods #region Overrides From 4795020fec7b8d76102bc9536c17bc592885d3b2 Mon Sep 17 00:00:00 2001 From: Lee Date: Mon, 17 Apr 2017 20:21:07 +0100 Subject: [PATCH 15/17] Adds method comments --- .../engine/remoting/commands/PSRemotingCmdlet.cs | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/src/System.Management.Automation/engine/remoting/commands/PSRemotingCmdlet.cs b/src/System.Management.Automation/engine/remoting/commands/PSRemotingCmdlet.cs index bef28052c97..70c7b2efe56 100644 --- a/src/System.Management.Automation/engine/remoting/commands/PSRemotingCmdlet.cs +++ b/src/System.Management.Automation/engine/remoting/commands/PSRemotingCmdlet.cs @@ -982,6 +982,11 @@ protected void ValidateComputerName(String[] computerNames) } } + /// + /// Validates parameter value and returns as string + /// + /// Parameter value to be validated + /// Parameter value as string private static string GetSSHConnectionStringParameter(object param) { var paramValue = param as string; @@ -993,6 +998,12 @@ private static string GetSSHConnectionStringParameter(object param) return paramValue; } + + /// + /// Validates parameter value and returns as integer + /// + /// Parameter value to be validated + /// Parameter value as integer private static int GetSSHConnectionIntParameter(object param) { int? paramValue = param as int?; From 70f344806b06f4d976a9258cbc670c334a4b0468 Mon Sep 17 00:00:00 2001 From: Lee Date: Mon, 17 Apr 2017 20:22:28 +0100 Subject: [PATCH 16/17] Adds helper method comment --- .../engine/remoting/common/RunspaceConnectionInfo.cs | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/System.Management.Automation/engine/remoting/common/RunspaceConnectionInfo.cs b/src/System.Management.Automation/engine/remoting/common/RunspaceConnectionInfo.cs index 9ca8188f3c5..296565943cf 100644 --- a/src/System.Management.Automation/engine/remoting/common/RunspaceConnectionInfo.cs +++ b/src/System.Management.Automation/engine/remoting/common/RunspaceConnectionInfo.cs @@ -355,6 +355,10 @@ internal virtual RunspaceConnectionInfo InternalCopy() throw new PSNotImplementedException(); } + /// + /// Validates port number is in range + /// + /// Port number to validate internal virtual void ValidatePortInRange(int port) { if ((port < MinPort || port > MaxPort)) From 97f070a7ae742cabc90c7b9c7e871390220b2620 Mon Sep 17 00:00:00 2001 From: Lee Date: Mon, 24 Apr 2017 19:24:24 +0100 Subject: [PATCH 17/17] Change methods to add C# 7 patterns --- .../engine/remoting/commands/PSRemotingCmdlet.cs | 14 ++++++-------- 1 file changed, 6 insertions(+), 8 deletions(-) diff --git a/src/System.Management.Automation/engine/remoting/commands/PSRemotingCmdlet.cs b/src/System.Management.Automation/engine/remoting/commands/PSRemotingCmdlet.cs index 70c7b2efe56..2a34eef8c22 100644 --- a/src/System.Management.Automation/engine/remoting/commands/PSRemotingCmdlet.cs +++ b/src/System.Management.Automation/engine/remoting/commands/PSRemotingCmdlet.cs @@ -989,13 +989,12 @@ protected void ValidateComputerName(String[] computerNames) /// Parameter value as string private static string GetSSHConnectionStringParameter(object param) { - var paramValue = param as string; - if (string.IsNullOrEmpty(paramValue)) + if (param is string paramValue && !string.IsNullOrEmpty(paramValue)) { - throw new PSArgumentException(RemotingErrorIdStrings.InvalidSSHConnectionParameter); + return paramValue; } - return paramValue; + throw new PSArgumentException(RemotingErrorIdStrings.InvalidSSHConnectionParameter); } @@ -1006,13 +1005,12 @@ private static string GetSSHConnectionStringParameter(object param) /// Parameter value as integer private static int GetSSHConnectionIntParameter(object param) { - int? paramValue = param as int?; - if (paramValue == null) + if (param is int paramValue) { - throw new PSArgumentException(RemotingErrorIdStrings.InvalidSSHConnectionParameter); + return paramValue; } - return paramValue.Value; + throw new PSArgumentException(RemotingErrorIdStrings.InvalidSSHConnectionParameter); } #endregion Private Methods