mirror of
https://github.com/PowerShell/PowerShell
synced 2026-06-08 12:12:50 +00:00
SSH remoting cmdlet parameter set changes based on RFC 0010 (#2710)
* RFC 0010 SSH remoting cmdlet updates. * Tweaks to SSH remoting cmdlets * SSHTransport parameter is now optional instead of mandatory. Aded fix for CoreCLR entry point when hosted in SSH as a subsystem. * Added tests * Code review feedback * Code review comment changes * Making SSHTransport switch parameter mandatory because otherwise existing Invoke-Command parameter set * The new SSH parameter set was causing legacy positional based parameters to no longer work. This fix separates the SSH parameter sets from the existing WinRM parameter sets. * Fixed region name spelling error.
This commit is contained in:
committed by
Mike Richmond
parent
19a0d993e7
commit
d2bf6294ab
@@ -240,6 +240,13 @@ namespace Microsoft.PowerShell
|
||||
throw hostException;
|
||||
}
|
||||
|
||||
#if !CORECLR
|
||||
// The default font face used for Powershell Console is Lucida Console.
|
||||
// However certain CJK locales dont support Lucida Console font. Hence for such
|
||||
// locales the console font is updated to Raster dynamically.
|
||||
ConsoleControl.UpdateLocaleSpecificFont();
|
||||
#endif
|
||||
|
||||
s_theConsoleHost.BindBreakHandler();
|
||||
PSHost.IsStdOutputRedirected = Console.IsOutputRedirected;
|
||||
|
||||
|
||||
@@ -82,17 +82,6 @@ namespace Microsoft.PowerShell
|
||||
throw PSTraceSource.NewArgumentNullException("args");
|
||||
}
|
||||
|
||||
// The default font face used for Powershell Console is Lucida Console.
|
||||
// However certain CJK locales dont support Lucida Console font. Hence for such
|
||||
// locales the console font is updated to Raster dynamically.
|
||||
|
||||
// For NanoServer:
|
||||
// 1. There is no GetCurrentConsoleFontEx / SetCurrentConsoleFontEx on NanoServer;
|
||||
// 2. We don't handle CJK locales on NanoServer due to lack of win32 API supports on NanoServer.
|
||||
#if !CORECLR
|
||||
ConsoleControl.UpdateLocaleSpecificFont();
|
||||
#endif
|
||||
|
||||
return ConsoleHost.Start(configuration, bannerText, helpText, preStartWarning, args);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3,6 +3,7 @@ Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
--********************************************************************/
|
||||
|
||||
using System;
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using System.Collections.ObjectModel;
|
||||
using System.Diagnostics.CodeAnalysis;
|
||||
@@ -387,7 +388,9 @@ namespace Microsoft.PowerShell.Commands
|
||||
[Parameter(ParameterSetName = InvokeCommandCommand.FilePathVMNameParameterSet)]
|
||||
[Parameter(ParameterSetName = InvokeCommandCommand.FilePathContainerIdParameterSet)]
|
||||
[Parameter(ParameterSetName = InvokeCommandCommand.SSHHostParameterSet)]
|
||||
[Parameter(ParameterSetName = InvokeCommandCommand.SSHHostHashParameterSet)]
|
||||
[Parameter(ParameterSetName = InvokeCommandCommand.FilePathSSHHostParameterSet)]
|
||||
[Parameter(ParameterSetName = InvokeCommandCommand.FilePathSSHHostHashParameterSet)]
|
||||
public SwitchParameter AsJob
|
||||
{
|
||||
get
|
||||
@@ -446,7 +449,9 @@ namespace Microsoft.PowerShell.Commands
|
||||
[Parameter(ParameterSetName = InvokeCommandCommand.FilePathVMNameParameterSet)]
|
||||
[Parameter(ParameterSetName = InvokeCommandCommand.FilePathContainerIdParameterSet)]
|
||||
[Parameter(ParameterSetName = InvokeCommandCommand.SSHHostParameterSet)]
|
||||
[Parameter(ParameterSetName = InvokeCommandCommand.SSHHostHashParameterSet)]
|
||||
[Parameter(ParameterSetName = InvokeCommandCommand.FilePathSSHHostParameterSet)]
|
||||
[Parameter(ParameterSetName = InvokeCommandCommand.FilePathSSHHostHashParameterSet)]
|
||||
[Alias("HCN")]
|
||||
public SwitchParameter HideComputerName
|
||||
{
|
||||
@@ -509,9 +514,10 @@ namespace Microsoft.PowerShell.Commands
|
||||
[Parameter(Position = 1,
|
||||
Mandatory = true,
|
||||
ParameterSetName = InvokeCommandCommand.ContainerIdParameterSet)]
|
||||
[Parameter(Position = 1,
|
||||
Mandatory = true,
|
||||
[Parameter(Mandatory = true,
|
||||
ParameterSetName = InvokeCommandCommand.SSHHostParameterSet)]
|
||||
[Parameter(Mandatory = true,
|
||||
ParameterSetName = InvokeCommandCommand.SSHHostHashParameterSet)]
|
||||
[ValidateNotNull]
|
||||
[Alias("Command")]
|
||||
public override ScriptBlock ScriptBlock
|
||||
@@ -555,9 +561,10 @@ namespace Microsoft.PowerShell.Commands
|
||||
[Parameter(Position = 1,
|
||||
Mandatory = true,
|
||||
ParameterSetName = FilePathContainerIdParameterSet)]
|
||||
[Parameter(Position = 1,
|
||||
Mandatory = true,
|
||||
[Parameter(Mandatory = true,
|
||||
ParameterSetName = FilePathSSHHostParameterSet)]
|
||||
[Parameter(Mandatory = true,
|
||||
ParameterSetName = FilePathSSHHostHashParameterSet)]
|
||||
[ValidateNotNull]
|
||||
[Alias("PSPath")]
|
||||
public override string FilePath
|
||||
@@ -662,28 +669,28 @@ namespace Microsoft.PowerShell.Commands
|
||||
#region SSH Parameters
|
||||
|
||||
/// <summary>
|
||||
/// Host Name
|
||||
/// Host name for an SSH remote connection
|
||||
/// </summary>
|
||||
[Parameter(Mandatory = true,
|
||||
ParameterSetName = InvokeCommandCommand.SSHHostParameterSet)]
|
||||
[Parameter(Mandatory = true,
|
||||
ParameterSetName = InvokeCommandCommand.FilePathSSHHostParameterSet)]
|
||||
[ValidateNotNullOrEmpty()]
|
||||
[Parameter(Position = 0, Mandatory = true, ParameterSetName = InvokeCommandCommand.SSHHostParameterSet)]
|
||||
[Parameter(Position = 0, Mandatory = true, ParameterSetName = InvokeCommandCommand.FilePathSSHHostParameterSet)]
|
||||
public override string HostName
|
||||
public override string[] HostName
|
||||
{
|
||||
get { return base.HostName; }
|
||||
|
||||
set { base.HostName = value; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// User Name
|
||||
/// </summary>
|
||||
[Parameter(Mandatory = true, ParameterSetName = InvokeCommandCommand.SSHHostParameterSet)]
|
||||
[Parameter(Mandatory = true, ParameterSetName = InvokeCommandCommand.FilePathSSHHostParameterSet)]
|
||||
[Parameter(ParameterSetName = InvokeCommandCommand.SSHHostParameterSet)]
|
||||
[Parameter(ParameterSetName = InvokeCommandCommand.FilePathSSHHostParameterSet)]
|
||||
[ValidateNotNullOrEmpty()]
|
||||
public override string UserName
|
||||
{
|
||||
get { return base.UserName; }
|
||||
|
||||
set { base.UserName = value; }
|
||||
}
|
||||
|
||||
@@ -693,13 +700,43 @@ namespace Microsoft.PowerShell.Commands
|
||||
[Parameter(ParameterSetName = InvokeCommandCommand.SSHHostParameterSet)]
|
||||
[Parameter(ParameterSetName = InvokeCommandCommand.FilePathSSHHostParameterSet)]
|
||||
[ValidateNotNullOrEmpty()]
|
||||
[Alias("IdentityFilePath")]
|
||||
public override string KeyFilePath
|
||||
{
|
||||
get { return base.KeyFilePath; }
|
||||
|
||||
set { base.KeyFilePath = value; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// This parameter specifies that SSH is used to establish the remote
|
||||
/// connection and act as the remoting transport. By default WinRM is used
|
||||
/// as the remoting transport. Using the SSH transport requires that SSH is
|
||||
/// installed and PowerShell remoting is enabled on both client and remote machines.
|
||||
/// </summary>
|
||||
[Parameter(ParameterSetName = PSRemotingBaseCmdlet.SSHHostParameterSet)]
|
||||
[Parameter(ParameterSetName = InvokeCommandCommand.FilePathSSHHostParameterSet)]
|
||||
[ValidateSet("true")]
|
||||
public override SwitchParameter SSHTransport
|
||||
{
|
||||
get { return base.SSHTransport; }
|
||||
set { base.SSHTransport = value; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Hashtable array containing SSH connection parameters for each remote target
|
||||
/// ComputerName (Alias: HostName) (required)
|
||||
/// UserName (optional)
|
||||
/// KeyFilePath (Alias: IdentityFilePath) (optional)
|
||||
/// </summary>
|
||||
[Parameter(ParameterSetName = PSRemotingBaseCmdlet.SSHHostHashParameterSet, Mandatory = true)]
|
||||
[Parameter(ParameterSetName = InvokeCommandCommand.FilePathSSHHostHashParameterSet, Mandatory = true)]
|
||||
[ValidateNotNullOrEmpty()]
|
||||
public override Hashtable[] SSHConnection
|
||||
{
|
||||
get;
|
||||
set;
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#endregion Parameters
|
||||
@@ -969,6 +1006,10 @@ namespace Microsoft.PowerShell.Commands
|
||||
case InvokeCommandCommand.FilePathVMIdParameterSet:
|
||||
case InvokeCommandCommand.FilePathVMNameParameterSet:
|
||||
case InvokeCommandCommand.FilePathContainerIdParameterSet:
|
||||
case InvokeCommandCommand.SSHHostParameterSet:
|
||||
case InvokeCommandCommand.FilePathSSHHostParameterSet:
|
||||
case InvokeCommandCommand.SSHHostHashParameterSet:
|
||||
case InvokeCommandCommand.FilePathSSHHostHashParameterSet:
|
||||
{
|
||||
if (ResolvedComputerNames.Length != 0 && Operations.Count > 0)
|
||||
{
|
||||
@@ -982,18 +1023,6 @@ namespace Microsoft.PowerShell.Commands
|
||||
}
|
||||
break;
|
||||
|
||||
case InvokeCommandCommand.SSHHostParameterSet:
|
||||
case InvokeCommandCommand.FilePathSSHHostParameterSet:
|
||||
{
|
||||
var job = new PSRemotingJob(new string[] { this.HostName }, Operations,
|
||||
ScriptBlock.ToString(), ThrottleLimit, _name);
|
||||
job.PSJobTypeName = RemoteJobType;
|
||||
job.HideComputerName = _hideComputerName;
|
||||
this.JobRepository.Add(job);
|
||||
WriteObject(job);
|
||||
}
|
||||
break;
|
||||
|
||||
case InvokeCommandCommand.SessionParameterSet:
|
||||
case InvokeCommandCommand.FilePathSessionParameterSet:
|
||||
{
|
||||
|
||||
@@ -181,6 +181,11 @@ namespace Microsoft.PowerShell.Commands
|
||||
/// </summary>
|
||||
protected const string SSHHostParameterSet = "SSHHost";
|
||||
|
||||
/// <summary>
|
||||
/// SSH host parmeter set supporting hash connection parameters
|
||||
/// </summary>
|
||||
protected const string SSHHostHashParameterSet = "SSHHostHashParam";
|
||||
|
||||
/// <summary>
|
||||
/// runspace parameter set
|
||||
/// </summary>
|
||||
@@ -262,6 +267,16 @@ namespace Microsoft.PowerShell.Commands
|
||||
#endregion
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Contains SSH connection information
|
||||
/// </summary>
|
||||
internal struct SSHConnection
|
||||
{
|
||||
public string ComputerName;
|
||||
public string UserName;
|
||||
public string KeyFilePath;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Base class for any cmdlet which takes a -Session parameter
|
||||
/// or a -ComputerName parameter (along with its other associated
|
||||
@@ -273,6 +288,8 @@ namespace Microsoft.PowerShell.Commands
|
||||
/// </summary>
|
||||
public abstract partial class PSRemotingBaseCmdlet : PSRemotingCmdlet
|
||||
{
|
||||
#region Enums
|
||||
|
||||
/// <summary>
|
||||
/// State of virtual machine. This is the same as VMState in
|
||||
/// \vm\ux\powershell\objects\common\Types.cs
|
||||
@@ -415,6 +432,8 @@ namespace Microsoft.PowerShell.Commands
|
||||
FastSavingCritical,
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Tracer
|
||||
|
||||
//PSETWTracer tracer = PSETWTracer.GetETWTracer(PSKeyword.Runspace);
|
||||
@@ -681,11 +700,12 @@ namespace Microsoft.PowerShell.Commands
|
||||
#region SSHHostParameters
|
||||
|
||||
/// <summary>
|
||||
/// SSH Target Host Name
|
||||
/// Host name for an SSH remote connection.
|
||||
/// </summary>
|
||||
[Parameter(ParameterSetName = PSRemotingBaseCmdlet.SSHHostParameterSet, Mandatory = true)]
|
||||
[Parameter(Position = 0, Mandatory = true,
|
||||
ParameterSetName = PSRemotingBaseCmdlet.SSHHostParameterSet)]
|
||||
[ValidateNotNullOrEmpty()]
|
||||
public virtual string HostName
|
||||
public virtual string[] HostName
|
||||
{
|
||||
get;
|
||||
set;
|
||||
@@ -694,7 +714,7 @@ namespace Microsoft.PowerShell.Commands
|
||||
/// <summary>
|
||||
/// SSH User Name
|
||||
/// </summary>
|
||||
[Parameter(ParameterSetName = PSRemotingBaseCmdlet.SSHHostParameterSet, Mandatory = true)]
|
||||
[Parameter(ParameterSetName = PSRemotingBaseCmdlet.SSHHostParameterSet)]
|
||||
[ValidateNotNullOrEmpty()]
|
||||
public virtual string UserName
|
||||
{
|
||||
@@ -707,12 +727,41 @@ namespace Microsoft.PowerShell.Commands
|
||||
/// </summary>
|
||||
[Parameter(ParameterSetName = PSRemotingBaseCmdlet.SSHHostParameterSet)]
|
||||
[ValidateNotNullOrEmpty()]
|
||||
[Alias("IdentityFilePath")]
|
||||
public virtual string KeyFilePath
|
||||
{
|
||||
get;
|
||||
set;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// This parameter specifies that SSH is used to establish the remote
|
||||
/// connection and act as the remoting transport. By default WinRM is used
|
||||
/// as the remoting transport. Using the SSH transport requires that SSH is
|
||||
/// installed and PowerShell remoting is enabled on both client and remote machines.
|
||||
/// </summary>
|
||||
[Parameter(ParameterSetName = PSRemotingBaseCmdlet.SSHHostParameterSet)]
|
||||
[ValidateSet("true")]
|
||||
public virtual SwitchParameter SSHTransport
|
||||
{
|
||||
get;
|
||||
set;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Hashtable array containing SSH connection parameters for each remote target
|
||||
/// ComputerName (Alias: HostName) (required)
|
||||
/// UserName (optional)
|
||||
/// KeyFilePath (Alias: IdentityFilePath) (optional)
|
||||
/// </summary>
|
||||
[Parameter(ParameterSetName = PSRemotingBaseCmdlet.SSHHostHashParameterSet, Mandatory = true)]
|
||||
[ValidateNotNullOrEmpty()]
|
||||
public virtual Hashtable[] SSHConnection
|
||||
{
|
||||
get;
|
||||
set;
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#endregion Properties
|
||||
@@ -762,6 +811,86 @@ namespace Microsoft.PowerShell.Commands
|
||||
|
||||
#endregion
|
||||
|
||||
#region Internal Methods
|
||||
|
||||
#region SSH Connection Strings
|
||||
|
||||
private const string ComputerNameParameter = "ComputerName";
|
||||
private const string HostNameAlias = "HostName";
|
||||
private const string UserNameParameter = "UserName";
|
||||
private const string KeyFilePathParameter = "KeyFilePath";
|
||||
private const string IdentityFilePathAlias = "IdentityFilePath";
|
||||
|
||||
#endregion
|
||||
|
||||
/// <summary>
|
||||
/// Parse the Connection parameter HashTable array.
|
||||
/// </summary>
|
||||
/// <returns>Array of SSHConnection objects</returns>
|
||||
internal SSHConnection[] ParseSSHConnectionHashTable()
|
||||
{
|
||||
List<SSHConnection> connections = new List<SSHConnection>();
|
||||
foreach (var item in this.SSHConnection)
|
||||
{
|
||||
if (item.ContainsKey(ComputerNameParameter) && item.ContainsKey(HostNameAlias))
|
||||
{
|
||||
throw new PSArgumentException(RemotingErrorIdStrings.SSHConnectionDuplicateHostName);
|
||||
}
|
||||
|
||||
if (item.ContainsKey(KeyFilePathParameter) && item.ContainsKey(IdentityFilePathAlias))
|
||||
{
|
||||
throw new PSArgumentException(RemotingErrorIdStrings.SSHConnectionDuplicateKeyPath);
|
||||
}
|
||||
|
||||
SSHConnection connectionInfo = new SSHConnection();
|
||||
foreach (var key in item.Keys)
|
||||
{
|
||||
string paramName = key as string;
|
||||
if (string.IsNullOrEmpty(paramName))
|
||||
{
|
||||
throw new PSArgumentException(RemotingErrorIdStrings.InvalidSSHConnectionParameter);
|
||||
}
|
||||
|
||||
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));
|
||||
}
|
||||
}
|
||||
|
||||
if (string.IsNullOrEmpty(connectionInfo.ComputerName))
|
||||
{
|
||||
throw new PSArgumentException(RemotingErrorIdStrings.MissingRequiredSSHParameter);
|
||||
}
|
||||
|
||||
connections.Add(connectionInfo);
|
||||
}
|
||||
|
||||
return connections.ToArray();
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Private Methods
|
||||
|
||||
/// <summary>
|
||||
@@ -920,6 +1049,11 @@ namespace Microsoft.PowerShell.Commands
|
||||
/// </summary>
|
||||
protected const string FilePathSSHHostParameterSet = "FilePathSSHHost";
|
||||
|
||||
/// <summary>
|
||||
/// SSH Host file path parameter set with HashTable connection parameter
|
||||
/// </summary>
|
||||
protected const string FilePathSSHHostHashParameterSet = "FilePathSSHHostHash";
|
||||
|
||||
#endregion
|
||||
|
||||
#region Parameters
|
||||
@@ -1169,18 +1303,45 @@ namespace Microsoft.PowerShell.Commands
|
||||
}// CreateHelpersForSpecifiedComputerNames
|
||||
|
||||
/// <summary>
|
||||
/// Creates helper objects for host names for PSRP over SSH
|
||||
/// Creates helper objects for SSH remoting computer names
|
||||
/// remoting.
|
||||
/// </summary>
|
||||
protected void CreateHelpersForSpecifiedHostNames()
|
||||
protected void CreateHelpersForSpecifiedSSHComputerNames()
|
||||
{
|
||||
var sshConnectionInfo = new SSHConnectionInfo(this.UserName, this.HostName, this.KeyFilePath);
|
||||
var typeTable = TypeTable.LoadDefaultTypeFiles();
|
||||
var remoteRunspace = RunspaceFactory.CreateRunspace(sshConnectionInfo, this.Host, typeTable) as RemoteRunspace;
|
||||
var pipeline = CreatePipeline(remoteRunspace);
|
||||
ValidateComputerName(ResolvedComputerNames);
|
||||
|
||||
var operation = new ExecutionCmdletHelperComputerName(remoteRunspace, pipeline);
|
||||
Operations.Add(operation);
|
||||
foreach (string computerName in ResolvedComputerNames)
|
||||
{
|
||||
var sshConnectionInfo = new SSHConnectionInfo(this.UserName, computerName, this.KeyFilePath);
|
||||
var typeTable = TypeTable.LoadDefaultTypeFiles();
|
||||
var remoteRunspace = RunspaceFactory.CreateRunspace(sshConnectionInfo, this.Host, typeTable) as RemoteRunspace;
|
||||
var pipeline = CreatePipeline(remoteRunspace);
|
||||
|
||||
var operation = new ExecutionCmdletHelperComputerName(remoteRunspace, pipeline);
|
||||
Operations.Add(operation);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Creates helper objects for SSH remoting from HashTable parameters.
|
||||
/// </summary>
|
||||
protected void CreateHelpersForSpecifiedSSHHashComputerNames()
|
||||
{
|
||||
var sshConnections = ParseSSHConnectionHashTable();
|
||||
var remoteRunspaces = new List<RemoteRunspace>();
|
||||
foreach (var sshConnection in sshConnections)
|
||||
{
|
||||
var sshConnectionInfo = new SSHConnectionInfo(
|
||||
sshConnection.UserName,
|
||||
sshConnection.ComputerName,
|
||||
sshConnection.KeyFilePath);
|
||||
var typeTable = TypeTable.LoadDefaultTypeFiles();
|
||||
var remoteRunspace = RunspaceFactory.CreateRunspace(sshConnectionInfo, this.Host, typeTable) as RemoteRunspace;
|
||||
var pipeline = CreatePipeline(remoteRunspace);
|
||||
|
||||
var operation = new ExecutionCmdletHelperComputerName(remoteRunspace, pipeline);
|
||||
Operations.Add(operation);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -1791,7 +1952,20 @@ namespace Microsoft.PowerShell.Commands
|
||||
|
||||
case PSExecutionCmdlet.SSHHostParameterSet:
|
||||
case PSExecutionCmdlet.FilePathSSHHostParameterSet:
|
||||
CreateHelpersForSpecifiedHostNames();
|
||||
{
|
||||
String[] resolvedComputerNames = null;
|
||||
ResolveComputerNames(HostName, out resolvedComputerNames);
|
||||
ResolvedComputerNames = resolvedComputerNames;
|
||||
|
||||
CreateHelpersForSpecifiedSSHComputerNames();
|
||||
}
|
||||
break;
|
||||
|
||||
case PSExecutionCmdlet.SSHHostHashParameterSet:
|
||||
case PSExecutionCmdlet.FilePathSSHHostHashParameterSet:
|
||||
{
|
||||
CreateHelpersForSpecifiedSSHHashComputerNames();
|
||||
}
|
||||
break;
|
||||
|
||||
case PSExecutionCmdlet.FilePathSessionParameterSet:
|
||||
|
||||
@@ -13,7 +13,7 @@ using System.Management.Automation.Remoting;
|
||||
using System.Management.Automation.Internal;
|
||||
using System.Management.Automation.Runspaces;
|
||||
using Dbg = System.Management.Automation.Diagnostics;
|
||||
|
||||
using System.Collections;
|
||||
|
||||
namespace Microsoft.PowerShell.Commands
|
||||
{
|
||||
@@ -44,6 +44,18 @@ namespace Microsoft.PowerShell.Commands
|
||||
|
||||
#region Parameters
|
||||
|
||||
#region SSH Parameter Set
|
||||
|
||||
/// <summary>
|
||||
/// Host name for an SSH remote connection
|
||||
/// </summary>
|
||||
[Parameter(Position = 0, Mandatory = true, ValueFromPipeline = true,
|
||||
ParameterSetName = PSRemotingBaseCmdlet.SSHHostParameterSet)]
|
||||
[ValidateNotNullOrEmpty()]
|
||||
public new string HostName { get; set; }
|
||||
|
||||
#endregion
|
||||
|
||||
/// <summary>
|
||||
/// Computer name parameter.
|
||||
/// </summary>
|
||||
@@ -172,6 +184,18 @@ namespace Microsoft.PowerShell.Commands
|
||||
ParameterSetName = EnterPSSessionCommand.VMNameParameterSet)]
|
||||
public String ConfigurationName { get; set; }
|
||||
|
||||
#region Suppress PSRemotingBaseCmdlet SSH hash parameter set
|
||||
|
||||
/// <summary>
|
||||
/// Suppress SSHConnection parameter set
|
||||
/// </summary>
|
||||
public override Hashtable[] SSHConnection
|
||||
{
|
||||
get { return null; }
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#endregion
|
||||
|
||||
#region Overrides
|
||||
@@ -1246,7 +1270,7 @@ namespace Microsoft.PowerShell.Commands
|
||||
/// </summary>
|
||||
private RemoteRunspace GetRunspaceForSSHSession()
|
||||
{
|
||||
var sshConnectionInfo = new SSHConnectionInfo(this.UserName, this.HostName, this.KeyFilePath);
|
||||
var sshConnectionInfo = new SSHConnectionInfo(this.UserName, ResolveComputerName(HostName), this.KeyFilePath);
|
||||
var typeTable = TypeTable.LoadDefaultTypeFiles();
|
||||
var remoteRunspace = RunspaceFactory.CreateRunspace(sshConnectionInfo, this.Host, typeTable) as RemoteRunspace;
|
||||
remoteRunspace.Open();
|
||||
|
||||
@@ -10,6 +10,7 @@ using System.Management.Automation.Runspaces;
|
||||
using System.Management.Automation.Security;
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics.CodeAnalysis;
|
||||
using System.Collections;
|
||||
|
||||
namespace Microsoft.PowerShell.Commands
|
||||
{
|
||||
@@ -119,6 +120,8 @@ namespace Microsoft.PowerShell.Commands
|
||||
}
|
||||
}
|
||||
|
||||
#region Suppress PSRemotingBaseCmdlet parameters
|
||||
|
||||
// suppress all the parameters from PSRemotingBaseCmdlet
|
||||
// which should not be part of Start-PSJob
|
||||
|
||||
@@ -152,6 +155,40 @@ namespace Microsoft.PowerShell.Commands
|
||||
get { return false; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Suppress SSHTransport
|
||||
/// </summary>
|
||||
public override SwitchParameter SSHTransport
|
||||
{
|
||||
get { return false; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Suppress SSHConnection
|
||||
/// </summary>
|
||||
public override Hashtable[] SSHConnection
|
||||
{
|
||||
get { return null; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Suppress UserName
|
||||
/// </summary>
|
||||
public override string UserName
|
||||
{
|
||||
get { return null; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Suppress KeyFilePath
|
||||
/// </summary>
|
||||
public override string KeyFilePath
|
||||
{
|
||||
get { return null; }
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
/// <summary>
|
||||
/// Credential to use for this job
|
||||
/// </summary>
|
||||
|
||||
@@ -244,6 +244,12 @@ namespace Microsoft.PowerShell.Commands
|
||||
}
|
||||
break;
|
||||
|
||||
case NewPSSessionCommand.SSHHostHashParameterSet:
|
||||
{
|
||||
remoteRunspaces = CreateRunspacesForSSHHostHashParameterSet();
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
{
|
||||
Dbg.Assert(false, "Missing parameter set in switch statement");
|
||||
@@ -1061,13 +1067,38 @@ namespace Microsoft.PowerShell.Commands
|
||||
/// <returns></returns>
|
||||
private List<RemoteRunspace> CreateRunspacesForSSHHostParameterSet()
|
||||
{
|
||||
// Resolve all the machine names
|
||||
String[] resolvedComputerNames;
|
||||
ResolveComputerNames(HostName, out resolvedComputerNames);
|
||||
ValidateComputerName(resolvedComputerNames);
|
||||
|
||||
var remoteRunspaces = new List<RemoteRunspace>();
|
||||
var sshConnectionInfo = new SSHConnectionInfo(
|
||||
this.UserName,
|
||||
this.HostName,
|
||||
this.KeyFilePath);
|
||||
var typeTable = TypeTable.LoadDefaultTypeFiles();
|
||||
remoteRunspaces.Add(RunspaceFactory.CreateRunspace(sshConnectionInfo, this.Host, typeTable) as RemoteRunspace);
|
||||
foreach (var computerName in resolvedComputerNames)
|
||||
{
|
||||
var sshConnectionInfo = new SSHConnectionInfo(
|
||||
this.UserName,
|
||||
computerName,
|
||||
this.KeyFilePath);
|
||||
var typeTable = TypeTable.LoadDefaultTypeFiles();
|
||||
remoteRunspaces.Add(RunspaceFactory.CreateRunspace(sshConnectionInfo, this.Host, typeTable) as RemoteRunspace);
|
||||
}
|
||||
|
||||
return remoteRunspaces;
|
||||
}
|
||||
|
||||
private List<RemoteRunspace> CreateRunspacesForSSHHostHashParameterSet()
|
||||
{
|
||||
var sshConnections = ParseSSHConnectionHashTable();
|
||||
var remoteRunspaces = new List<RemoteRunspace>();
|
||||
foreach (var sshConnection in sshConnections)
|
||||
{
|
||||
var sshConnectionInfo = new SSHConnectionInfo(
|
||||
sshConnection.UserName,
|
||||
sshConnection.ComputerName,
|
||||
sshConnection.KeyFilePath);
|
||||
var typeTable = TypeTable.LoadDefaultTypeFiles();
|
||||
remoteRunspaces.Add(RunspaceFactory.CreateRunspace(sshConnectionInfo, this.Host, typeTable) as RemoteRunspace);
|
||||
}
|
||||
|
||||
return remoteRunspaces;
|
||||
}
|
||||
|
||||
@@ -1873,7 +1873,6 @@ namespace System.Management.Automation.Runspaces
|
||||
string computerName,
|
||||
string keyFilePath)
|
||||
{
|
||||
if (userName == null) { throw new PSArgumentNullException("userName"); }
|
||||
if (computerName == null) { throw new PSArgumentNullException("computerName"); }
|
||||
|
||||
this.UserName = userName;
|
||||
@@ -1980,9 +1979,9 @@ namespace System.Management.Automation.Runspaces
|
||||
|
||||
// Extract an optional domain name if provided.
|
||||
string domainName = null;
|
||||
string userName = this.UserName;
|
||||
string userName = this.UserName ?? GetCurrentUserName();
|
||||
#if !UNIX
|
||||
var parts = this.UserName.Split(Utils.Separators.Backslash);
|
||||
var parts = userName.Split(Utils.Separators.Backslash);
|
||||
if (parts.Length == 2)
|
||||
{
|
||||
domainName = parts[0];
|
||||
@@ -2027,6 +2026,19 @@ namespace System.Management.Automation.Runspaces
|
||||
|
||||
#endregion
|
||||
|
||||
#region Private Methods
|
||||
|
||||
private string GetCurrentUserName()
|
||||
{
|
||||
#if UNIX
|
||||
return System.Environment.GetEnvironmentVariable("USER") ?? string.Empty;
|
||||
#else
|
||||
return System.Security.Principal.WindowsIdentity.GetCurrent().Name;
|
||||
#endif
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region SSH Process Creation
|
||||
|
||||
#if UNIX
|
||||
|
||||
@@ -1516,7 +1516,12 @@ namespace System.Management.Automation.Remoting.Client
|
||||
while (true)
|
||||
{
|
||||
string error = reader.ReadLine();
|
||||
if (!string.IsNullOrEmpty(error) && (error.IndexOf("WARNING:", StringComparison.OrdinalIgnoreCase) > -1))
|
||||
if (string.IsNullOrEmpty(error))
|
||||
{
|
||||
// Ignore blank error messages.
|
||||
continue;
|
||||
}
|
||||
if (error.IndexOf("WARNING:", StringComparison.OrdinalIgnoreCase) > -1)
|
||||
{
|
||||
// Handle as interactive warning message.
|
||||
Console.WriteLine(error);
|
||||
|
||||
@@ -1621,4 +1621,19 @@ All WinRM sessions connected to Windows PowerShell session configurations, such
|
||||
<data name="SSHClientEndNoErrorMessage" xml:space="preserve">
|
||||
<value>The SSH client session has ended with no error message.</value>
|
||||
</data>
|
||||
<data name="MissingRequiredSSHParameter" xml:space="preserve">
|
||||
<value>The provided SSHConnection hashtable is missing the required ComputerName or HostName parameter.</value>
|
||||
</data>
|
||||
<data name="InvalidSSHConnectionParameter" xml:space="preserve">
|
||||
<value>The provided SSHConnection hashtable parameter name or element is null or empty.</value>
|
||||
</data>
|
||||
<data name="UnknownSSHConnectionParameter" xml:space="preserve">
|
||||
<value>The provided SSHConnection hashtable parameter {0} is not supported.</value>
|
||||
</data>
|
||||
<data name="SSHConnectionDuplicateHostName" xml:space="preserve">
|
||||
<value>The provided SSHConnection hashtable contains both a ComputerName and HostName parameter. Only one can be specified.</value>
|
||||
</data>
|
||||
<data name="SSHConnectionDuplicateKeyPath" xml:space="preserve">
|
||||
<value>The provided SSHConnection hashtable contains both a KeyFilePath and IdentityFilePath parameter. Only one can be specified.</value>
|
||||
</data>
|
||||
</root>
|
||||
@@ -0,0 +1,57 @@
|
||||
##
|
||||
## SSH Remoting cmdlet tests
|
||||
##
|
||||
|
||||
Describe "SSHTransport switch parameter value" -Tags 'Feature' {
|
||||
|
||||
BeforeAll {
|
||||
|
||||
$TestCasesSSHTransport = @(
|
||||
@{scriptBlock = {New-PSSession -HostName localhost -UserName UserA -SSHTransport:$false}; testName = 'New-PSSession SSHTransport parameter cannot have false value'}
|
||||
@{scriptBlock = {Enter-PSSession -HostName localhost -UserName UserA -SSHTransport:$false}; testName = 'Enter-PSSession SSHTransport parameter cannot have false value'}
|
||||
@{scriptBlock = {Invoke-Command -ScriptBlock {"Hello"} -HostName localhost -UserName UserA -SSHTransport:$false}; testName = 'Invoke-Command SSHTransport parameter cannot have false value'}
|
||||
)
|
||||
}
|
||||
|
||||
It "<testName>" -TestCases $TestCasesSSHTransport {
|
||||
|
||||
param($scriptBlock)
|
||||
try
|
||||
{
|
||||
& $scriptBlock
|
||||
throw "Parameter argument should not be valid"
|
||||
}
|
||||
catch
|
||||
{
|
||||
$_.FullyQualifiedErrorId | Should Match "ParameterArgumentValidationError"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Describe "SSHConnection parameter hashtable error conditions" -Tags 'Feature' {
|
||||
|
||||
BeforeAll {
|
||||
|
||||
$TestCasesSSHConnection = @(
|
||||
@{scriptBlock = {New-PSSession -SSHConnection @{ ComputerName = "localhost"; "" = "noParameter" }}; testName = 'SSHConnection parameter hashtable cannot contain empty parameter names'}
|
||||
@{scriptBlock = {New-PSSession -SSHConnection @{ HostName = $null }}; testName = 'SSHConnection parameter hashtable cannot contain empty parameter values'}
|
||||
@{scriptBlock = {New-PSSession -SSHConnection @{ ComputerName = "localhost"; UnknownParameter = "Hello" }}; testName = 'SSHConnection parameter hashtable cannot contain unknown parameter names'}
|
||||
@{scriptBlock = {New-PSSession -SSHConnection @{ UserName = "UserName"; KeyFilePath = "path" }}; testName = 'SSHConnection parmeter hashtable must contain the ComputerName parameter'}
|
||||
@{scriptBlock = {New-PSSession -SSHConnection @{ ComputerName = "computerA"; hostname = "computerB" }}; testName = 'SSHConnection parameter hashtable cannot contain both ComputerName and HostName parameters' }
|
||||
@{scriptBlock = {New-PSSession -SSHConnection @{ keyfilepath = "pathA"; IdentityFilePath = "pathB" }}; testName = 'SSHConnection parameter hashtable cannot contain both KeyFilePath and IdentityFilePath parameters' }
|
||||
)
|
||||
}
|
||||
|
||||
It "<testName>" -TestCases $TestCasesSSHConnection {
|
||||
param ($scriptBlock)
|
||||
try
|
||||
{
|
||||
& $scriptBlock
|
||||
throw "Parameter set should not be valid"
|
||||
}
|
||||
catch
|
||||
{
|
||||
$_.FullyQualifiedErrorId | Should Match "Argument,Microsoft.PowerShell.Commands.NewPSSessionCommand"
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user