Skip to content

Commit 0302b1f

Browse files
authored
Support OpenSSH options for PSRP over SSH commands (PowerShell#12802)
Add an -Options parameter to Invoke-Command and Start-PSSession to pass SSH options Options parameter added to Invoke-Command Options parameter added to Start-PSSession Options parameter added to Enter-PSSession Options parameter added to SSHConnection Hashtable
1 parent f83660e commit 0302b1f

File tree

6 files changed

+111
-10
lines changed

6 files changed

+111
-10
lines changed

src/System.Management.Automation/engine/remoting/commands/InvokeCommandCommand.cs

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -858,6 +858,25 @@ public override Hashtable[] SSHConnection
858858
set;
859859
}
860860

861+
/// <summary>
862+
/// Hashtable containing options to be passed to OpenSSH.
863+
/// </summary>
864+
[Parameter(ParameterSetName = InvokeCommandCommand.SSHHostParameterSet)]
865+
[Parameter(ParameterSetName = InvokeCommandCommand.FilePathSSHHostParameterSet)]
866+
[ValidateNotNullOrEmpty]
867+
public override Hashtable Options
868+
{
869+
get
870+
{
871+
return base.Options;
872+
}
873+
874+
set
875+
{
876+
base.Options = value;
877+
}
878+
}
879+
861880
#endregion
862881

863882
#region Remote Debug Parameters

src/System.Management.Automation/engine/remoting/commands/PSRemotingCmdlet.cs

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -287,6 +287,7 @@ internal struct SSHConnection
287287
public int Port;
288288
public string Subsystem;
289289
public int ConnectingTimeout;
290+
public Hashtable Options;
290291
}
291292

292293
/// <summary>
@@ -805,6 +806,13 @@ public virtual Hashtable[] SSHConnection
805806
set;
806807
}
807808

809+
/// <summary>
810+
/// Gets or sets the Hashtable containing options to be passed to OpenSSH.
811+
/// </summary>
812+
[Parameter(ParameterSetName = InvokeCommandCommand.SSHHostParameterSet)]
813+
[ValidateNotNullOrEmpty]
814+
public virtual Hashtable Options { get; set; }
815+
808816
#endregion
809817

810818
#endregion Properties
@@ -866,6 +874,7 @@ internal static void ValidateSpecifiedAuthentication(PSCredential credential, st
866874
private const string PortParameter = "Port";
867875
private const string SubsystemParameter = "Subsystem";
868876
private const string ConnectingTimeoutParameter = "ConnectingTimeout";
877+
private const string OptionsParameter = "Options";
869878

870879
#endregion
871880

@@ -969,6 +978,10 @@ internal SSHConnection[] ParseSSHConnectionHashTable()
969978
{
970979
connectionInfo.ConnectingTimeout = GetSSHConnectionIntParameter(item[paramName]);
971980
}
981+
else if (paramName.Equals(OptionsParameter, StringComparison.OrdinalIgnoreCase))
982+
{
983+
connectionInfo.Options = item[paramName] as Hashtable;
984+
}
972985
else
973986
{
974987
throw new PSArgumentException(
@@ -1462,7 +1475,7 @@ protected void CreateHelpersForSpecifiedSSHComputerNames()
14621475
{
14631476
ParseSshHostName(computerName, out string host, out string userName, out int port);
14641477

1465-
var sshConnectionInfo = new SSHConnectionInfo(userName, host, KeyFilePath, port, Subsystem, ConnectingTimeout);
1478+
var sshConnectionInfo = new SSHConnectionInfo(userName, host, KeyFilePath, port, Subsystem, ConnectingTimeout, Options);
14661479
var typeTable = TypeTable.LoadDefaultTypeFiles();
14671480
var remoteRunspace = RunspaceFactory.CreateRunspace(sshConnectionInfo, Host, typeTable) as RemoteRunspace;
14681481
var pipeline = CreatePipeline(remoteRunspace);

src/System.Management.Automation/engine/remoting/commands/PushRunspaceCommand.cs

Lines changed: 19 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -58,6 +58,24 @@ public class EnterPSSessionCommand : PSRemotingBaseCmdlet
5858
[ValidateNotNullOrEmpty()]
5959
public new string HostName { get; set; }
6060

61+
/// <summary>
62+
/// Gets or sets the Hashtable containing options to be passed to OpenSSH.
63+
/// </summary>
64+
[Parameter(ParameterSetName = PSRemotingBaseCmdlet.SSHHostParameterSet)]
65+
[ValidateNotNullOrEmpty]
66+
public override Hashtable Options
67+
{
68+
get
69+
{
70+
return base.Options;
71+
}
72+
73+
set
74+
{
75+
base.Options = value;
76+
}
77+
}
78+
6179
#endregion
6280

6381
/// <summary>
@@ -1262,7 +1280,7 @@ private RemoteRunspace GetRunspaceForContainerSession()
12621280
private RemoteRunspace GetRunspaceForSSHSession()
12631281
{
12641282
ParseSshHostName(HostName, out string host, out string userName, out int port);
1265-
var sshConnectionInfo = new SSHConnectionInfo(userName, host, KeyFilePath, port, Subsystem, ConnectingTimeout);
1283+
var sshConnectionInfo = new SSHConnectionInfo(userName, host, KeyFilePath, port, Subsystem, ConnectingTimeout, Options);
12661284
var typeTable = TypeTable.LoadDefaultTypeFiles();
12671285

12681286
// Use the class _tempRunspace field while the runspace is being opened so that StopProcessing can be handled at that time.

src/System.Management.Automation/engine/remoting/commands/newrunspacecommand.cs

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1093,7 +1093,8 @@ private List<RemoteRunspace> CreateRunspacesForSSHHostParameterSet()
10931093
this.KeyFilePath,
10941094
port,
10951095
Subsystem,
1096-
ConnectingTimeout);
1096+
ConnectingTimeout,
1097+
Options);
10971098
var typeTable = TypeTable.LoadDefaultTypeFiles();
10981099
string rsName = GetRunspaceName(index, out int rsIdUnused);
10991100
index++;
@@ -1120,7 +1121,8 @@ private List<RemoteRunspace> CreateRunspacesForSSHHostHashParameterSet()
11201121
sshConnection.KeyFilePath,
11211122
sshConnection.Port,
11221123
sshConnection.Subsystem,
1123-
sshConnection.ConnectingTimeout);
1124+
sshConnection.ConnectingTimeout,
1125+
sshConnection.Options);
11241126
var typeTable = TypeTable.LoadDefaultTypeFiles();
11251127
string rsName = GetRunspaceName(index, out int rsIdUnused);
11261128
index++;

src/System.Management.Automation/engine/remoting/common/RunspaceConnectionInfo.cs

Lines changed: 48 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
// Copyright (c) Microsoft Corporation.
22
// Licensed under the MIT License.
33

4+
using System.Collections;
45
using System.Collections.Generic;
56
using System.ComponentModel; // Win32Exception
67
using System.Diagnostics;
@@ -1969,18 +1970,27 @@ public int ConnectingTimeout
19691970
set;
19701971
}
19711972

1973+
/// The SSH options to pass to OpenSSH.
1974+
/// Gets or sets the SSH options to pass to OpenSSH.
1975+
/// </summary>
1976+
private Hashtable Options
1977+
{
1978+
get;
1979+
set;
1980+
}
1981+
19721982
#endregion
19731983

19741984
#region Constructors
19751985

19761986
/// <summary>
1977-
/// Constructor.
1987+
/// Initializes a new instance of the <see cref="SSHConnectionInfo" /> class.
19781988
/// </summary>
19791989
private SSHConnectionInfo()
19801990
{ }
19811991

19821992
/// <summary>
1983-
/// Constructor.
1993+
/// Initializes a new instance of the <see cref="SSHConnectionInfo" /> class.
19841994
/// </summary>
19851995
/// <param name="userName">User Name.</param>
19861996
/// <param name="computerName">Computer Name.</param>
@@ -2001,7 +2011,7 @@ public SSHConnectionInfo(
20012011
}
20022012

20032013
/// <summary>
2004-
/// Constructor.
2014+
/// Initializes a new instance of the <see cref="SSHConnectionInfo" /> class.
20052015
/// </summary>
20062016
/// <param name="userName">User Name.</param>
20072017
/// <param name="computerName">Computer Name.</param>
@@ -2018,7 +2028,7 @@ public SSHConnectionInfo(
20182028
}
20192029

20202030
/// <summary>
2021-
/// Constructor.
2031+
/// Initializes a new instance of the <see cref="SSHConnectionInfo" /> class.
20222032
/// </summary>
20232033
/// <param name="userName">User Name.</param>
20242034
/// <param name="computerName">Computer Name.</param>
@@ -2055,6 +2065,28 @@ public SSHConnectionInfo(
20552065
ConnectingTimeout = connectingTimeout;
20562066
}
20572067

2068+
/// <summary>
2069+
/// Initializes a new instance of the <see cref="SSHConnectionInfo" /> class.
2070+
/// </summary>
2071+
/// <param name="userName">User Name.</param>
2072+
/// <param name="computerName">Computer Name.</param>
2073+
/// <param name="keyFilePath">Key File Path.</param>
2074+
/// <param name="port">Port number for connection (default 22).</param>
2075+
/// <param name="subsystem">Subsystem to use (default 'powershell').</param>
2076+
/// <param name="connectingTimeout">Timeout time for terminating connection attempt.</param>
2077+
/// <param name="options">Options for the SSH connection.</param>
2078+
public SSHConnectionInfo(
2079+
string userName,
2080+
string computerName,
2081+
string keyFilePath,
2082+
int port,
2083+
string subsystem,
2084+
int connectingTimeout,
2085+
Hashtable options) : this(userName, computerName, keyFilePath, port, subsystem, connectingTimeout)
2086+
{
2087+
Options = options;
2088+
}
2089+
20582090
#endregion
20592091

20602092
#region Overrides
@@ -2111,6 +2143,7 @@ internal override RunspaceConnectionInfo InternalCopy()
21112143
newCopy.Port = Port;
21122144
newCopy.Subsystem = Subsystem;
21132145
newCopy.ConnectingTimeout = ConnectingTimeout;
2146+
newCopy.Options = Options;
21142147

21152148
return newCopy;
21162149
}
@@ -2163,9 +2196,9 @@ internal int StartSSHProcess(
21632196
//
21642197
// Local ssh invoked as:
21652198
// windows:
2166-
// ssh.exe [-i identity_file] [-l login_name] [-p port] -s <destination> <command>
2199+
// ssh.exe [-i identity_file] [-l login_name] [-p port] [-o option] -s <destination> <command>
21672200
// linux|macos:
2168-
// ssh [-i identity_file] [-l login_name] [-p port] -s <destination> <command>
2201+
// ssh [-i identity_file] [-l login_name] [-p port] [-o option] -s <destination> <command>
21692202
// where <command> is interpreted as the subsystem due to the -s flag.
21702203
//
21712204
// Remote sshd configured for PowerShell Remoting Protocol (PSRP) over Secure Shell Protocol (SSH)
@@ -2216,6 +2249,15 @@ internal int StartSSHProcess(
22162249
startInfo.ArgumentList.Add(string.Format(CultureInfo.InvariantCulture, @"-p {0}", this.Port));
22172250
}
22182251

2252+
// pass "-o option=value" command line argument to ssh if options are provided
2253+
if (this.Options != null)
2254+
{
2255+
foreach (DictionaryEntry pair in this.Options)
2256+
{
2257+
startInfo.ArgumentList.Add(string.Format(CultureInfo.InvariantCulture, @"-o {0}={1}", pair.Key, pair.Value));
2258+
}
2259+
}
2260+
22192261
// pass "-s destination command" command line arguments to ssh where command is the subsystem to invoke on the destination
22202262
// note that ssh expects IPv6 addresses to not be enclosed in square brackets so trim them if present
22212263
startInfo.ArgumentList.Add(string.Format(CultureInfo.InvariantCulture, @"-s {0} {1}", this.ComputerName.TrimStart('[').TrimEnd(']'), this.Subsystem));

test/SSHRemoting/SSHRemoting.Basic.Tests.ps1

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -179,6 +179,13 @@ Describe "SSHRemoting Basic Tests" -tags CI {
179179
Write-Verbose -Verbose "It Complete"
180180
}
181181

182+
It "Verifies explicit Options parameter" {
183+
$options = @{"Port"="22"}
184+
$script:session = New-PSSession -HostName localhost -Options $options -ErrorVariable err
185+
$err | Should -HaveCount 0
186+
VerifySession $script:session
187+
}
188+
182189
It "Verifies explicit Subsystem parameter" {
183190
Write-Verbose -Verbose "It Starting: Verifies explicit Subsystem parameter"
184191
$portNum = 22

0 commit comments

Comments
 (0)