diff --git a/src/Microsoft.PowerShell.ConsoleHost/host/msh/ConsoleHost.cs b/src/Microsoft.PowerShell.ConsoleHost/host/msh/ConsoleHost.cs
index 1f8909bfc9..b54449a17e 100644
--- a/src/Microsoft.PowerShell.ConsoleHost/host/msh/ConsoleHost.cs
+++ b/src/Microsoft.PowerShell.ConsoleHost/host/msh/ConsoleHost.cs
@@ -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;
diff --git a/src/Microsoft.PowerShell.ConsoleHost/host/msh/ConsoleShell.cs b/src/Microsoft.PowerShell.ConsoleHost/host/msh/ConsoleShell.cs
index 49f6ec56a4..abce899add 100644
--- a/src/Microsoft.PowerShell.ConsoleHost/host/msh/ConsoleShell.cs
+++ b/src/Microsoft.PowerShell.ConsoleHost/host/msh/ConsoleShell.cs
@@ -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);
}
}
diff --git a/src/System.Management.Automation/engine/remoting/commands/InvokeCommandCommand.cs b/src/System.Management.Automation/engine/remoting/commands/InvokeCommandCommand.cs
index b8d665ead6..df4945c53a 100644
--- a/src/System.Management.Automation/engine/remoting/commands/InvokeCommandCommand.cs
+++ b/src/System.Management.Automation/engine/remoting/commands/InvokeCommandCommand.cs
@@ -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
///
- /// Host Name
+ /// Host name for an SSH remote connection
///
+ [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; }
}
///
/// User Name
///
- [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; }
}
+ ///
+ /// 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.
+ ///
+ [Parameter(ParameterSetName = PSRemotingBaseCmdlet.SSHHostParameterSet)]
+ [Parameter(ParameterSetName = InvokeCommandCommand.FilePathSSHHostParameterSet)]
+ [ValidateSet("true")]
+ public override SwitchParameter SSHTransport
+ {
+ get { return base.SSHTransport; }
+ set { base.SSHTransport = value; }
+ }
+
+ ///
+ /// Hashtable array containing SSH connection parameters for each remote target
+ /// ComputerName (Alias: HostName) (required)
+ /// UserName (optional)
+ /// KeyFilePath (Alias: IdentityFilePath) (optional)
+ ///
+ [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:
{
diff --git a/src/System.Management.Automation/engine/remoting/commands/PSRemotingCmdlet.cs b/src/System.Management.Automation/engine/remoting/commands/PSRemotingCmdlet.cs
index 624ad25dbf..f8ec2b44aa 100644
--- a/src/System.Management.Automation/engine/remoting/commands/PSRemotingCmdlet.cs
+++ b/src/System.Management.Automation/engine/remoting/commands/PSRemotingCmdlet.cs
@@ -181,6 +181,11 @@ namespace Microsoft.PowerShell.Commands
///
protected const string SSHHostParameterSet = "SSHHost";
+ ///
+ /// SSH host parmeter set supporting hash connection parameters
+ ///
+ protected const string SSHHostHashParameterSet = "SSHHostHashParam";
+
///
/// runspace parameter set
///
@@ -262,6 +267,16 @@ namespace Microsoft.PowerShell.Commands
#endregion
}
+ ///
+ /// Contains SSH connection information
+ ///
+ internal struct SSHConnection
+ {
+ public string ComputerName;
+ public string UserName;
+ public string KeyFilePath;
+ }
+
///
/// 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
///
public abstract partial class PSRemotingBaseCmdlet : PSRemotingCmdlet
{
+ #region Enums
+
///
/// 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
///
- /// SSH Target Host Name
+ /// Host name for an SSH remote connection.
///
- [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
///
/// SSH User Name
///
- [Parameter(ParameterSetName = PSRemotingBaseCmdlet.SSHHostParameterSet, Mandatory = true)]
+ [Parameter(ParameterSetName = PSRemotingBaseCmdlet.SSHHostParameterSet)]
[ValidateNotNullOrEmpty()]
public virtual string UserName
{
@@ -707,12 +727,41 @@ namespace Microsoft.PowerShell.Commands
///
[Parameter(ParameterSetName = PSRemotingBaseCmdlet.SSHHostParameterSet)]
[ValidateNotNullOrEmpty()]
+ [Alias("IdentityFilePath")]
public virtual string KeyFilePath
{
get;
set;
}
+ ///
+ /// 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.
+ ///
+ [Parameter(ParameterSetName = PSRemotingBaseCmdlet.SSHHostParameterSet)]
+ [ValidateSet("true")]
+ public virtual SwitchParameter SSHTransport
+ {
+ get;
+ set;
+ }
+
+ ///
+ /// Hashtable array containing SSH connection parameters for each remote target
+ /// ComputerName (Alias: HostName) (required)
+ /// UserName (optional)
+ /// KeyFilePath (Alias: IdentityFilePath) (optional)
+ ///
+ [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
+
+ ///
+ /// Parse the Connection parameter HashTable array.
+ ///
+ /// Array of SSHConnection objects
+ internal SSHConnection[] ParseSSHConnectionHashTable()
+ {
+ List connections = new List();
+ 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
///
@@ -920,6 +1049,11 @@ namespace Microsoft.PowerShell.Commands
///
protected const string FilePathSSHHostParameterSet = "FilePathSSHHost";
+ ///
+ /// SSH Host file path parameter set with HashTable connection parameter
+ ///
+ protected const string FilePathSSHHostHashParameterSet = "FilePathSSHHostHash";
+
#endregion
#region Parameters
@@ -1169,18 +1303,45 @@ namespace Microsoft.PowerShell.Commands
}// CreateHelpersForSpecifiedComputerNames
///
- /// Creates helper objects for host names for PSRP over SSH
+ /// Creates helper objects for SSH remoting computer names
/// remoting.
///
- 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);
+ }
+ }
+
+ ///
+ /// Creates helper objects for SSH remoting from HashTable parameters.
+ ///
+ protected void CreateHelpersForSpecifiedSSHHashComputerNames()
+ {
+ var sshConnections = ParseSSHConnectionHashTable();
+ var remoteRunspaces = new List();
+ 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);
+ }
}
///
@@ -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:
diff --git a/src/System.Management.Automation/engine/remoting/commands/PushRunspaceCommand.cs b/src/System.Management.Automation/engine/remoting/commands/PushRunspaceCommand.cs
index 66c9f20965..c1c81cea93 100644
--- a/src/System.Management.Automation/engine/remoting/commands/PushRunspaceCommand.cs
+++ b/src/System.Management.Automation/engine/remoting/commands/PushRunspaceCommand.cs
@@ -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
+
+ ///
+ /// Host name for an SSH remote connection
+ ///
+ [Parameter(Position = 0, Mandatory = true, ValueFromPipeline = true,
+ ParameterSetName = PSRemotingBaseCmdlet.SSHHostParameterSet)]
+ [ValidateNotNullOrEmpty()]
+ public new string HostName { get; set; }
+
+ #endregion
+
///
/// Computer name parameter.
///
@@ -172,6 +184,18 @@ namespace Microsoft.PowerShell.Commands
ParameterSetName = EnterPSSessionCommand.VMNameParameterSet)]
public String ConfigurationName { get; set; }
+ #region Suppress PSRemotingBaseCmdlet SSH hash parameter set
+
+ ///
+ /// Suppress SSHConnection parameter set
+ ///
+ public override Hashtable[] SSHConnection
+ {
+ get { return null; }
+ }
+
+ #endregion
+
#endregion
#region Overrides
@@ -1246,7 +1270,7 @@ namespace Microsoft.PowerShell.Commands
///
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();
diff --git a/src/System.Management.Automation/engine/remoting/commands/StartJob.cs b/src/System.Management.Automation/engine/remoting/commands/StartJob.cs
index 7d46f8259e..fb52844b32 100644
--- a/src/System.Management.Automation/engine/remoting/commands/StartJob.cs
+++ b/src/System.Management.Automation/engine/remoting/commands/StartJob.cs
@@ -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; }
}
+ ///
+ /// Suppress SSHTransport
+ ///
+ public override SwitchParameter SSHTransport
+ {
+ get { return false; }
+ }
+
+ ///
+ /// Suppress SSHConnection
+ ///
+ public override Hashtable[] SSHConnection
+ {
+ get { return null; }
+ }
+
+ ///
+ /// Suppress UserName
+ ///
+ public override string UserName
+ {
+ get { return null; }
+ }
+
+ ///
+ /// Suppress KeyFilePath
+ ///
+ public override string KeyFilePath
+ {
+ get { return null; }
+ }
+
+ #endregion
+
///
/// Credential to use for this job
///
diff --git a/src/System.Management.Automation/engine/remoting/commands/newrunspacecommand.cs b/src/System.Management.Automation/engine/remoting/commands/newrunspacecommand.cs
index b310787575..386e320541 100644
--- a/src/System.Management.Automation/engine/remoting/commands/newrunspacecommand.cs
+++ b/src/System.Management.Automation/engine/remoting/commands/newrunspacecommand.cs
@@ -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
///
private List CreateRunspacesForSSHHostParameterSet()
{
+ // Resolve all the machine names
+ String[] resolvedComputerNames;
+ ResolveComputerNames(HostName, out resolvedComputerNames);
+ ValidateComputerName(resolvedComputerNames);
+
var remoteRunspaces = new List();
- 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 CreateRunspacesForSSHHostHashParameterSet()
+ {
+ var sshConnections = ParseSSHConnectionHashTable();
+ var remoteRunspaces = new List();
+ 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;
}
diff --git a/src/System.Management.Automation/engine/remoting/common/RunspaceConnectionInfo.cs b/src/System.Management.Automation/engine/remoting/common/RunspaceConnectionInfo.cs
index 5b5a19f3cd..b50f21da22 100644
--- a/src/System.Management.Automation/engine/remoting/common/RunspaceConnectionInfo.cs
+++ b/src/System.Management.Automation/engine/remoting/common/RunspaceConnectionInfo.cs
@@ -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
diff --git a/src/System.Management.Automation/engine/remoting/fanin/OutOfProcTransportManager.cs b/src/System.Management.Automation/engine/remoting/fanin/OutOfProcTransportManager.cs
index 69eff7e11d..71174daffd 100644
--- a/src/System.Management.Automation/engine/remoting/fanin/OutOfProcTransportManager.cs
+++ b/src/System.Management.Automation/engine/remoting/fanin/OutOfProcTransportManager.cs
@@ -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);
diff --git a/src/System.Management.Automation/resources/RemotingErrorIdStrings.resx b/src/System.Management.Automation/resources/RemotingErrorIdStrings.resx
index d74de9dd3e..69c3a35660 100644
--- a/src/System.Management.Automation/resources/RemotingErrorIdStrings.resx
+++ b/src/System.Management.Automation/resources/RemotingErrorIdStrings.resx
@@ -1621,4 +1621,19 @@ All WinRM sessions connected to Windows PowerShell session configurations, such
The SSH client session has ended with no error message.
+
+ The provided SSHConnection hashtable is missing the required ComputerName or HostName parameter.
+
+
+ The provided SSHConnection hashtable parameter name or element is null or empty.
+
+
+ The provided SSHConnection hashtable parameter {0} is not supported.
+
+
+ The provided SSHConnection hashtable contains both a ComputerName and HostName parameter. Only one can be specified.
+
+
+ The provided SSHConnection hashtable contains both a KeyFilePath and IdentityFilePath parameter. Only one can be specified.
+
\ No newline at end of file
diff --git a/test/powershell/engine/Remoting/SSHRemotingCmdlets.Tests.ps1 b/test/powershell/engine/Remoting/SSHRemotingCmdlets.Tests.ps1
new file mode 100644
index 0000000000..8c325a6663
--- /dev/null
+++ b/test/powershell/engine/Remoting/SSHRemotingCmdlets.Tests.ps1
@@ -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 "" -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 "" -TestCases $TestCasesSSHConnection {
+ param ($scriptBlock)
+ try
+ {
+ & $scriptBlock
+ throw "Parameter set should not be valid"
+ }
+ catch
+ {
+ $_.FullyQualifiedErrorId | Should Match "Argument,Microsoft.PowerShell.Commands.NewPSSessionCommand"
+ }
+ }
+}