2016-03-30 14:20:52 -07:00
|
|
|
/********************************************************************++
|
|
|
|
|
Copyright (c) Microsoft Corporation. All rights reserved.
|
|
|
|
|
--********************************************************************/
|
2016-07-29 13:02:49 -07:00
|
|
|
|
2016-03-30 14:20:52 -07:00
|
|
|
using System;
|
|
|
|
|
using System.Collections.Generic;
|
|
|
|
|
using System.Collections.ObjectModel;
|
|
|
|
|
using System.Threading;
|
|
|
|
|
using System.Diagnostics.CodeAnalysis;
|
|
|
|
|
using System.Management.Automation;
|
|
|
|
|
using System.Management.Automation.Host;
|
|
|
|
|
using System.Management.Automation.Remoting;
|
|
|
|
|
using System.Management.Automation.Internal;
|
|
|
|
|
using System.Management.Automation.Runspaces;
|
|
|
|
|
using Dbg = System.Management.Automation.Diagnostics;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
namespace Microsoft.PowerShell.Commands
|
|
|
|
|
{
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// Enter-PSSession cmdlet.
|
|
|
|
|
/// </summary>
|
|
|
|
|
[Cmdlet(VerbsCommon.Enter, "PSSession", DefaultParameterSetName = "ComputerName",
|
2016-08-23 21:21:31 -04:00
|
|
|
HelpUri = "https://go.microsoft.com/fwlink/?LinkID=135210", RemotingCapability = RemotingCapability.OwnedByCommand)]
|
2016-03-30 14:20:52 -07:00
|
|
|
public class EnterPSSessionCommand : PSRemotingBaseCmdlet
|
|
|
|
|
{
|
|
|
|
|
#region Strings
|
|
|
|
|
|
|
|
|
|
private const string InstanceIdParameterSet = "InstanceId";
|
|
|
|
|
private const string IdParameterSet = "Id";
|
|
|
|
|
private const string NameParameterSet = "Name";
|
|
|
|
|
|
|
|
|
|
#endregion
|
|
|
|
|
|
|
|
|
|
#region Members
|
2016-07-29 13:02:49 -07:00
|
|
|
|
2016-03-30 14:20:52 -07:00
|
|
|
/// <summary>
|
|
|
|
|
/// Disable ThrottleLimit parameter inherited from base class.
|
|
|
|
|
/// </summary>
|
|
|
|
|
public new Int32 ThrottleLimit { set { } get { return 0; } }
|
2016-07-29 13:02:49 -07:00
|
|
|
private ObjectStream _stream;
|
2016-03-30 14:20:52 -07:00
|
|
|
|
|
|
|
|
#endregion
|
|
|
|
|
|
|
|
|
|
#region Parameters
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// Computer name parameter.
|
|
|
|
|
/// </summary>
|
|
|
|
|
[Parameter(Position = 0, Mandatory = true, ValueFromPipeline = true,
|
|
|
|
|
ValueFromPipelineByPropertyName = true, ParameterSetName = ComputerNameParameterSet)]
|
|
|
|
|
[Alias("Cn")]
|
|
|
|
|
[ValidateNotNullOrEmpty]
|
2016-08-02 13:29:09 -07:00
|
|
|
public new string ComputerName { get; set; }
|
2016-03-30 14:20:52 -07:00
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// Runspace parameter.
|
|
|
|
|
/// </summary>
|
|
|
|
|
[Parameter(Position = 0, ValueFromPipelineByPropertyName = true,
|
|
|
|
|
ValueFromPipeline = true, ParameterSetName = SessionParameterSet)]
|
|
|
|
|
[ValidateNotNullOrEmpty]
|
|
|
|
|
[SuppressMessage("Microsoft.Naming", "CA1704:IdentifiersShouldBeSpelledCorrectly", MessageId = "Runspace")]
|
2016-08-02 13:29:09 -07:00
|
|
|
public new PSSession Session { get; set; }
|
2016-03-30 14:20:52 -07:00
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// ConnectionUri parameter.
|
|
|
|
|
/// </summary>
|
|
|
|
|
[Parameter(Position = 1, ValueFromPipelineByPropertyName = true,
|
|
|
|
|
ParameterSetName = UriParameterSet)]
|
|
|
|
|
[ValidateNotNullOrEmpty]
|
|
|
|
|
[Alias("URI", "CU")]
|
2016-08-02 13:29:09 -07:00
|
|
|
public new Uri ConnectionUri { get; set; }
|
2016-03-30 14:20:52 -07:00
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// RemoteRunspaceId of the remote runspace info object.
|
|
|
|
|
/// </summary>
|
|
|
|
|
[Parameter(ValueFromPipelineByPropertyName = true,
|
|
|
|
|
ParameterSetName = InstanceIdParameterSet)]
|
|
|
|
|
[ValidateNotNull]
|
|
|
|
|
[SuppressMessage("Microsoft.Naming", "CA1704:IdentifiersShouldBeSpelledCorrectly", MessageId = "Runspace")]
|
2016-08-02 13:29:09 -07:00
|
|
|
public Guid InstanceId { get; set; }
|
2016-03-30 14:20:52 -07:00
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// SessionId of the remote runspace info object.
|
|
|
|
|
/// </summary>
|
|
|
|
|
[Parameter(Position = 0,
|
|
|
|
|
ValueFromPipelineByPropertyName = true,
|
|
|
|
|
ParameterSetName = IdParameterSet)]
|
|
|
|
|
[ValidateNotNull]
|
2016-08-02 13:29:09 -07:00
|
|
|
public int Id { get; set; }
|
2016-03-30 14:20:52 -07:00
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// Name of the remote runspace info object.
|
|
|
|
|
/// </summary>
|
|
|
|
|
[Parameter(ValueFromPipelineByPropertyName = true,
|
|
|
|
|
ParameterSetName = NameParameterSet)]
|
2016-08-02 13:29:09 -07:00
|
|
|
public String Name { get; set; }
|
2016-03-30 14:20:52 -07:00
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// When set and in loopback scenario (localhost) this enables creation of WSMan
|
|
|
|
|
/// host process with the user interactive token, allowing PowerShell script network access,
|
|
|
|
|
/// i.e., allows going off box. When this property is true and a PSSession is disconnected,
|
|
|
|
|
/// reconnection is allowed only if reconnecting from a PowerShell session on the same box.
|
|
|
|
|
/// </summary>
|
|
|
|
|
[Parameter(ParameterSetName = ComputerNameParameterSet)]
|
|
|
|
|
[Parameter(ParameterSetName = UriParameterSet)]
|
2016-08-02 13:29:09 -07:00
|
|
|
public SwitchParameter EnableNetworkAccess { get; set; }
|
2016-03-30 14:20:52 -07:00
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// Virtual machine ID.
|
|
|
|
|
/// </summary>
|
|
|
|
|
[ValidateNotNullOrEmpty]
|
2016-07-29 13:02:49 -07:00
|
|
|
[Parameter(Position = 0, Mandatory = true, ValueFromPipeline = true,
|
2016-03-30 14:20:52 -07:00
|
|
|
ValueFromPipelineByPropertyName = true, ParameterSetName = VMIdParameterSet)]
|
|
|
|
|
[Alias("VMGuid")]
|
2016-08-02 13:29:09 -07:00
|
|
|
public new Guid VMId { get; set; }
|
2016-03-30 14:20:52 -07:00
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// Virtual machine name.
|
|
|
|
|
/// </summary>
|
|
|
|
|
[ValidateNotNullOrEmpty]
|
2016-07-29 13:02:49 -07:00
|
|
|
[Parameter(Position = 0, Mandatory = true, ValueFromPipeline = true,
|
2016-03-30 14:20:52 -07:00
|
|
|
ValueFromPipelineByPropertyName = true, ParameterSetName = VMNameParameterSet)]
|
2016-08-02 13:29:09 -07:00
|
|
|
public new string VMName { get; set; }
|
2016-03-30 14:20:52 -07:00
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// Specifies the credentials of the user to impersonate in the
|
|
|
|
|
/// virtual machine. If this parameter is not specified then the
|
|
|
|
|
/// credentials of the current user process will be assumed.
|
|
|
|
|
/// </summary>
|
|
|
|
|
[Parameter(ValueFromPipelineByPropertyName = true,
|
|
|
|
|
ParameterSetName = PSRemotingBaseCmdlet.ComputerNameParameterSet)]
|
|
|
|
|
[Parameter(ValueFromPipelineByPropertyName = true,
|
|
|
|
|
ParameterSetName = PSRemotingBaseCmdlet.UriParameterSet)]
|
|
|
|
|
[Parameter(Position = 1, Mandatory = true, ValueFromPipelineByPropertyName = true,
|
|
|
|
|
ParameterSetName = VMIdParameterSet)]
|
|
|
|
|
[Parameter(Position = 1, Mandatory = true, ValueFromPipelineByPropertyName = true,
|
|
|
|
|
ParameterSetName = VMNameParameterSet)]
|
|
|
|
|
[Credential()]
|
|
|
|
|
public override PSCredential Credential
|
|
|
|
|
{
|
|
|
|
|
get { return base.Credential; }
|
|
|
|
|
set { base.Credential = value; }
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// The Id of the target container.
|
|
|
|
|
/// </summary>
|
|
|
|
|
[ValidateNotNullOrEmpty]
|
2016-07-29 13:02:49 -07:00
|
|
|
[Parameter(Position = 0, Mandatory = true, ValueFromPipeline = true,
|
2016-03-30 14:20:52 -07:00
|
|
|
ValueFromPipelineByPropertyName = true, ParameterSetName = ContainerIdParameterSet)]
|
2016-08-02 13:29:09 -07:00
|
|
|
public new string ContainerId { get; set; }
|
2016-03-30 14:20:52 -07:00
|
|
|
|
2016-03-31 17:27:44 -07:00
|
|
|
/// <summary>
|
|
|
|
|
/// For WSMan sessions:
|
|
|
|
|
/// If this parameter is not specified then the value specified in
|
|
|
|
|
/// the environment variable DEFAULTREMOTESHELLNAME will be used. If
|
|
|
|
|
/// this is not set as well, then Microsoft.PowerShell is used.
|
|
|
|
|
///
|
|
|
|
|
/// For VM/Container sessions:
|
|
|
|
|
/// If this parameter is not specified then no configuration is used.
|
|
|
|
|
/// </summary>
|
|
|
|
|
[Parameter(ValueFromPipelineByPropertyName = true,
|
|
|
|
|
ParameterSetName = EnterPSSessionCommand.ComputerNameParameterSet)]
|
|
|
|
|
[Parameter(ValueFromPipelineByPropertyName = true,
|
|
|
|
|
ParameterSetName = EnterPSSessionCommand.UriParameterSet)]
|
|
|
|
|
[Parameter(ValueFromPipelineByPropertyName = true,
|
|
|
|
|
ParameterSetName = EnterPSSessionCommand.ContainerIdParameterSet)]
|
|
|
|
|
[Parameter(ValueFromPipelineByPropertyName = true,
|
|
|
|
|
ParameterSetName = EnterPSSessionCommand.VMIdParameterSet)]
|
|
|
|
|
[Parameter(ValueFromPipelineByPropertyName = true,
|
|
|
|
|
ParameterSetName = EnterPSSessionCommand.VMNameParameterSet)]
|
2016-08-02 13:29:09 -07:00
|
|
|
public String ConfigurationName { get; set; }
|
2016-03-31 17:27:44 -07:00
|
|
|
|
2016-03-30 14:20:52 -07:00
|
|
|
#endregion
|
|
|
|
|
|
|
|
|
|
#region Overrides
|
|
|
|
|
|
2016-03-31 17:27:44 -07:00
|
|
|
/// <summary>
|
|
|
|
|
/// Resolves shellname and appname
|
|
|
|
|
/// </summary>
|
|
|
|
|
protected override void BeginProcessing()
|
|
|
|
|
{
|
|
|
|
|
base.BeginProcessing();
|
|
|
|
|
|
|
|
|
|
if (String.IsNullOrEmpty(ConfigurationName))
|
|
|
|
|
{
|
|
|
|
|
if ((ParameterSetName == EnterPSSessionCommand.ComputerNameParameterSet) ||
|
|
|
|
|
(ParameterSetName == EnterPSSessionCommand.UriParameterSet))
|
|
|
|
|
{
|
|
|
|
|
// set to default value for WSMan session
|
|
|
|
|
ConfigurationName = ResolveShell(null);
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
// convert null to String.Empty for VM/Container session
|
|
|
|
|
ConfigurationName = String.Empty;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2016-03-30 14:20:52 -07:00
|
|
|
/// <summary>
|
|
|
|
|
/// Process record.
|
|
|
|
|
/// </summary>
|
|
|
|
|
protected override void ProcessRecord()
|
|
|
|
|
{
|
|
|
|
|
// Push the remote runspace on the local host.
|
|
|
|
|
IHostSupportsInteractiveSession host = this.Host as IHostSupportsInteractiveSession;
|
|
|
|
|
if (host == null)
|
|
|
|
|
{
|
|
|
|
|
WriteError(
|
|
|
|
|
new ErrorRecord(
|
|
|
|
|
new ArgumentException(GetMessage(RemotingErrorIdStrings.HostDoesNotSupportPushRunspace)),
|
|
|
|
|
PSRemotingErrorId.HostDoesNotSupportPushRunspace.ToString(),
|
|
|
|
|
ErrorCategory.InvalidArgument,
|
|
|
|
|
null));
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Check if current host is remote host. Enter-PSSession on remote host is not
|
|
|
|
|
// currently supported.
|
|
|
|
|
if (!IsParameterSetForVM() &&
|
|
|
|
|
!IsParameterSetForContainer() &&
|
|
|
|
|
!IsParameterSetForVMContainerSession() &&
|
|
|
|
|
this.Context != null &&
|
|
|
|
|
this.Context.EngineHostInterface != null &&
|
|
|
|
|
this.Context.EngineHostInterface.ExternalHost != null &&
|
|
|
|
|
this.Context.EngineHostInterface.ExternalHost is System.Management.Automation.Remoting.ServerRemoteHost)
|
|
|
|
|
{
|
|
|
|
|
WriteError(
|
|
|
|
|
new ErrorRecord(
|
|
|
|
|
new ArgumentException(GetMessage(RemotingErrorIdStrings.RemoteHostDoesNotSupportPushRunspace)),
|
|
|
|
|
PSRemotingErrorId.RemoteHostDoesNotSupportPushRunspace.ToString(),
|
|
|
|
|
ErrorCategory.InvalidArgument,
|
|
|
|
|
null));
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// for the console host and Graphical PowerShell host
|
|
|
|
|
// we want to skip pushing into the the runspace if
|
|
|
|
|
// the host is in a nested prompt
|
2016-07-29 13:02:49 -07:00
|
|
|
System.Management.Automation.Internal.Host.InternalHost chost =
|
2016-03-30 14:20:52 -07:00
|
|
|
this.Host as System.Management.Automation.Internal.Host.InternalHost;
|
|
|
|
|
|
2016-07-29 13:02:49 -07:00
|
|
|
if (!IsParameterSetForVM() &&
|
2016-03-30 14:20:52 -07:00
|
|
|
!IsParameterSetForContainer() &&
|
|
|
|
|
!IsParameterSetForVMContainerSession() &&
|
|
|
|
|
chost != null && chost.HostInNestedPrompt())
|
|
|
|
|
{
|
|
|
|
|
ThrowTerminatingError(new ErrorRecord(
|
|
|
|
|
new InvalidOperationException(PSRemotingErrorInvariants.FormatResourceString(RemotingErrorIdStrings.HostInNestedPrompt)),
|
|
|
|
|
"HostInNestedPrompt", ErrorCategory.InvalidOperation, chost));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*Microsoft.Windows.PowerShell.Gui.Internal.GPSHost ghost = this.Host as Microsoft.Windows.PowerShell.Gui.Internal.GPSHost;
|
|
|
|
|
|
|
|
|
|
if (ghost != null && ghost.HostInNestedPrompt())
|
|
|
|
|
{
|
|
|
|
|
ThrowTerminatingError(new ErrorRecord(
|
|
|
|
|
new InvalidOperationException(PSRemotingErrorInvariants.FormatResourceString(PSRemotingErrorId.HostInNestedPrompt)),
|
|
|
|
|
"HostInNestedPrompt", ErrorCategory.InvalidOperation, wpshost));
|
|
|
|
|
}*/
|
|
|
|
|
|
|
|
|
|
// Get the remote runspace.
|
|
|
|
|
RemoteRunspace remoteRunspace = null;
|
|
|
|
|
switch (ParameterSetName)
|
|
|
|
|
{
|
|
|
|
|
case ComputerNameParameterSet:
|
|
|
|
|
remoteRunspace = CreateRunspaceWhenComputerNameParameterSpecified();
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case UriParameterSet:
|
|
|
|
|
remoteRunspace = CreateRunspaceWhenUriParameterSpecified();
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case SessionParameterSet:
|
2016-08-02 13:29:09 -07:00
|
|
|
remoteRunspace = (RemoteRunspace)Session.Runspace;
|
2016-03-30 14:20:52 -07:00
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case InstanceIdParameterSet:
|
|
|
|
|
remoteRunspace = GetRunspaceMatchingRunspaceId(this.InstanceId);
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case IdParameterSet:
|
|
|
|
|
remoteRunspace = GetRunspaceMatchingSessionId(this.Id);
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case NameParameterSet:
|
|
|
|
|
remoteRunspace = GetRunspaceMatchingName(this.Name);
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case VMIdParameterSet:
|
|
|
|
|
case VMNameParameterSet:
|
|
|
|
|
remoteRunspace = GetRunspaceForVMSession();
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case ContainerIdParameterSet:
|
|
|
|
|
remoteRunspace = GetRunspaceForContainerSession();
|
|
|
|
|
break;
|
2016-08-12 15:05:05 -07:00
|
|
|
|
|
|
|
|
case SSHHostParameterSet:
|
|
|
|
|
remoteRunspace = GetRunspaceForSSHSession();
|
|
|
|
|
break;
|
2016-03-30 14:20:52 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// If runspace is null then the error record has already been written and we can exit.
|
|
|
|
|
if (remoteRunspace == null) { return; }
|
|
|
|
|
|
|
|
|
|
// If the runspace is in a disconnected state try to connect.
|
|
|
|
|
bool runspaceConnected = false;
|
|
|
|
|
if (remoteRunspace.RunspaceStateInfo.State == RunspaceState.Disconnected)
|
|
|
|
|
{
|
|
|
|
|
if (!remoteRunspace.CanConnect)
|
|
|
|
|
{
|
|
|
|
|
string message = StringUtil.Format(RemotingErrorIdStrings.SessionNotAvailableForConnection);
|
|
|
|
|
WriteError(
|
|
|
|
|
new ErrorRecord(
|
|
|
|
|
new RuntimeException(message), "EnterPSSessionCannotConnectDisconnectedSession",
|
|
|
|
|
ErrorCategory.InvalidOperation, remoteRunspace));
|
|
|
|
|
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Connect the runspace.
|
|
|
|
|
Exception ex = null;
|
|
|
|
|
try
|
|
|
|
|
{
|
|
|
|
|
remoteRunspace.Connect();
|
|
|
|
|
runspaceConnected = true;
|
|
|
|
|
}
|
|
|
|
|
catch (System.Management.Automation.Remoting.PSRemotingTransportException e)
|
|
|
|
|
{
|
|
|
|
|
ex = e;
|
|
|
|
|
}
|
|
|
|
|
catch (PSInvalidOperationException e)
|
|
|
|
|
{
|
|
|
|
|
ex = e;
|
|
|
|
|
}
|
|
|
|
|
catch (InvalidRunspacePoolStateException e)
|
|
|
|
|
{
|
|
|
|
|
ex = e;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (ex != null)
|
|
|
|
|
{
|
|
|
|
|
string message = StringUtil.Format(RemotingErrorIdStrings.SessionConnectFailed);
|
|
|
|
|
WriteError(
|
|
|
|
|
new ErrorRecord(
|
|
|
|
|
new RuntimeException(message, ex), "EnterPSSessionConnectSessionFailed",
|
|
|
|
|
ErrorCategory.InvalidOperation, remoteRunspace));
|
|
|
|
|
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Verify that the runspace is open.
|
|
|
|
|
if (remoteRunspace.RunspaceStateInfo.State != RunspaceState.Opened)
|
|
|
|
|
{
|
|
|
|
|
if (ParameterSetName == SessionParameterSet)
|
|
|
|
|
{
|
2016-08-02 13:29:09 -07:00
|
|
|
string sessionName = (Session != null) ? Session.Name : string.Empty;
|
2016-03-30 14:20:52 -07:00
|
|
|
WriteError(
|
|
|
|
|
new ErrorRecord(
|
|
|
|
|
new ArgumentException(GetMessage(RemotingErrorIdStrings.EnterPSSessionBrokenSession,
|
|
|
|
|
sessionName, remoteRunspace.ConnectionInfo.ComputerName, remoteRunspace.InstanceId)),
|
|
|
|
|
PSRemotingErrorId.PushedRunspaceMustBeOpen.ToString(),
|
|
|
|
|
ErrorCategory.InvalidArgument,
|
|
|
|
|
null));
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
WriteError(
|
|
|
|
|
new ErrorRecord(
|
|
|
|
|
new ArgumentException(GetMessage(RemotingErrorIdStrings.PushedRunspaceMustBeOpen)),
|
|
|
|
|
PSRemotingErrorId.PushedRunspaceMustBeOpen.ToString(),
|
|
|
|
|
ErrorCategory.InvalidArgument,
|
|
|
|
|
null));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
Debugger debugger = null;
|
|
|
|
|
try
|
|
|
|
|
{
|
|
|
|
|
if (host.Runspace != null)
|
|
|
|
|
{
|
|
|
|
|
debugger = host.Runspace.Debugger;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
catch (PSNotImplementedException) { }
|
|
|
|
|
|
|
|
|
|
bool supportRunningCommand = ((debugger != null) && ((debugger.DebugMode & DebugModes.RemoteScript) == DebugModes.RemoteScript));
|
|
|
|
|
if (remoteRunspace.RunspaceAvailability != RunspaceAvailability.Available)
|
|
|
|
|
{
|
|
|
|
|
// Session has running command.
|
|
|
|
|
if (!supportRunningCommand)
|
|
|
|
|
{
|
|
|
|
|
// Host does not support remote debug and cannot connect to running command.
|
|
|
|
|
if (runspaceConnected)
|
|
|
|
|
{
|
|
|
|
|
// If we succeeded connecting the session (runspace) but it is already running a command,
|
|
|
|
|
// emit an error for this case because since it is disconnected this session object will
|
|
|
|
|
// never complete and the user must use *reconstruct* scenario to retrieve data.
|
|
|
|
|
string message = StringUtil.Format(RemotingErrorIdStrings.EnterPSSessionDisconnected,
|
|
|
|
|
remoteRunspace.PSSessionName);
|
|
|
|
|
WriteError(
|
|
|
|
|
new ErrorRecord(
|
|
|
|
|
new RuntimeException(message), "EnterPSSessionConnectSessionNotAvailable",
|
2016-08-02 13:29:09 -07:00
|
|
|
ErrorCategory.InvalidOperation, Session));
|
2016-03-30 14:20:52 -07:00
|
|
|
|
|
|
|
|
// Leave session in original disconnected state.
|
|
|
|
|
remoteRunspace.DisconnectAsync();
|
|
|
|
|
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
// If the remote runspace is currently not available then let user know that this command
|
|
|
|
|
// will not complete until it becomes available.
|
|
|
|
|
WriteWarning(GetMessage(RunspaceStrings.RunspaceNotReady));
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
// Running commands supported.
|
|
|
|
|
// Warn user that they are entering a session that is running a command and output may
|
|
|
|
|
// be going to a job object.
|
|
|
|
|
Job job = FindJobForRunspace(remoteRunspace.InstanceId);
|
|
|
|
|
string msg;
|
|
|
|
|
if (job != null)
|
|
|
|
|
{
|
|
|
|
|
msg = StringUtil.Format(
|
|
|
|
|
RunspaceStrings.RunningCmdWithJob,
|
|
|
|
|
(!string.IsNullOrEmpty(job.Name)) ? job.Name : string.Empty);
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
2016-07-29 13:02:49 -07:00
|
|
|
if (remoteRunspace.RunspaceAvailability == RunspaceAvailability.RemoteDebug)
|
2016-03-30 14:20:52 -07:00
|
|
|
{
|
|
|
|
|
msg = StringUtil.Format(
|
|
|
|
|
RunspaceStrings.RunningCmdDebugStop);
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
msg = StringUtil.Format(
|
|
|
|
|
RunspaceStrings.RunningCmdWithoutJob);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
WriteWarning(msg);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Make sure any PSSession object passed in is saved in the local runspace repository.
|
2016-08-02 13:29:09 -07:00
|
|
|
if (Session != null)
|
2016-03-30 14:20:52 -07:00
|
|
|
{
|
2016-08-02 13:29:09 -07:00
|
|
|
this.RunspaceRepository.AddOrReplace(Session);
|
2016-03-30 14:20:52 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// prepare runspace for prompt
|
|
|
|
|
SetRunspacePrompt(remoteRunspace);
|
|
|
|
|
|
|
|
|
|
try
|
|
|
|
|
{
|
|
|
|
|
host.PushRunspace(remoteRunspace);
|
|
|
|
|
}
|
|
|
|
|
catch (Exception)
|
|
|
|
|
{
|
|
|
|
|
// A third-party host can throw any exception here..we should
|
|
|
|
|
// clean the runspace created in this case.
|
|
|
|
|
if ((null != remoteRunspace) && (remoteRunspace.ShouldCloseOnPop))
|
|
|
|
|
{
|
|
|
|
|
remoteRunspace.Close();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// rethrow the exception after cleanup.
|
|
|
|
|
throw;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// This method will until the runspace is opened and warnings if any
|
|
|
|
|
/// are reported
|
|
|
|
|
/// </summary>
|
|
|
|
|
protected override void EndProcessing()
|
|
|
|
|
{
|
2016-07-29 13:02:49 -07:00
|
|
|
if (null != _stream)
|
2016-03-30 14:20:52 -07:00
|
|
|
{
|
|
|
|
|
while (true)
|
|
|
|
|
{
|
|
|
|
|
// Keep reading objects until end of stream is encountered
|
2016-07-29 13:02:49 -07:00
|
|
|
_stream.ObjectReader.WaitHandle.WaitOne();
|
2016-03-30 14:20:52 -07:00
|
|
|
|
2016-07-29 13:02:49 -07:00
|
|
|
if (!_stream.ObjectReader.EndOfPipeline)
|
2016-03-30 14:20:52 -07:00
|
|
|
{
|
2016-07-29 13:02:49 -07:00
|
|
|
Object streamObject = _stream.ObjectReader.Read();
|
2016-03-30 14:20:52 -07:00
|
|
|
WriteStreamObject((Action<Cmdlet>)streamObject);
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
} // while ...
|
|
|
|
|
}
|
|
|
|
|
}// EndProcessing()
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
///
|
|
|
|
|
/// </summary>
|
|
|
|
|
protected override void StopProcessing()
|
|
|
|
|
{
|
|
|
|
|
IHostSupportsInteractiveSession host = this.Host as IHostSupportsInteractiveSession;
|
|
|
|
|
if (host == null)
|
|
|
|
|
{
|
|
|
|
|
WriteError(
|
|
|
|
|
new ErrorRecord(
|
|
|
|
|
new ArgumentException(GetMessage(RemotingErrorIdStrings.HostDoesNotSupportPushRunspace)),
|
|
|
|
|
PSRemotingErrorId.HostDoesNotSupportPushRunspace.ToString(),
|
|
|
|
|
ErrorCategory.InvalidArgument,
|
|
|
|
|
null));
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
host.PopRunspace();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#endregion
|
|
|
|
|
|
|
|
|
|
#region Private Methods
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// Create temporary remote runspace.
|
|
|
|
|
/// </summary>
|
|
|
|
|
private RemoteRunspace CreateTemporaryRemoteRunspace(PSHost host, WSManConnectionInfo connectionInfo)
|
|
|
|
|
{
|
|
|
|
|
// Create and open the runspace.
|
|
|
|
|
int rsId;
|
|
|
|
|
string rsName = PSSession.GenerateRunspaceName(out rsId);
|
|
|
|
|
RemoteRunspace remoteRunspace = new RemoteRunspace(
|
|
|
|
|
Utils.GetTypeTableFromExecutionContextTLS(),
|
|
|
|
|
connectionInfo,
|
|
|
|
|
host,
|
|
|
|
|
this.SessionOption.ApplicationArguments,
|
|
|
|
|
rsName,
|
|
|
|
|
rsId);
|
|
|
|
|
Dbg.Assert(remoteRunspace != null, "Expected remoteRunspace != null");
|
|
|
|
|
remoteRunspace.URIRedirectionReported += HandleURIDirectionReported;
|
|
|
|
|
|
2016-07-29 13:02:49 -07:00
|
|
|
_stream = new ObjectStream();
|
2016-03-30 14:20:52 -07:00
|
|
|
try
|
|
|
|
|
{
|
|
|
|
|
remoteRunspace.Open();
|
|
|
|
|
|
|
|
|
|
// Mark this temporary runspace so that it closes on pop.
|
|
|
|
|
remoteRunspace.ShouldCloseOnPop = true;
|
|
|
|
|
}
|
|
|
|
|
finally
|
|
|
|
|
{
|
|
|
|
|
// unregister uri redirection handler
|
|
|
|
|
remoteRunspace.URIRedirectionReported -= HandleURIDirectionReported;
|
|
|
|
|
// close the internal object stream after runspace is opened
|
|
|
|
|
// Runspace.Open() might throw exceptions..this will make sure
|
|
|
|
|
// the stream is always closed.
|
2016-07-29 13:02:49 -07:00
|
|
|
_stream.ObjectWriter.Close();
|
2016-03-30 14:20:52 -07:00
|
|
|
|
|
|
|
|
// make sure we dispose the temporary runspace if something bad happens
|
|
|
|
|
if (remoteRunspace.RunspaceStateInfo.State != RunspaceState.Opened)
|
|
|
|
|
{
|
|
|
|
|
remoteRunspace.Dispose();
|
|
|
|
|
remoteRunspace = null;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return remoteRunspace;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// Write error create remote runspace failed.
|
|
|
|
|
/// </summary>
|
|
|
|
|
private void WriteErrorCreateRemoteRunspaceFailed(Exception exception, object argument)
|
|
|
|
|
{
|
|
|
|
|
// set the transport message in the error detail so that
|
|
|
|
|
// the user can directly get to see the message without
|
|
|
|
|
// having to mine through the error record details
|
|
|
|
|
PSRemotingTransportException transException =
|
|
|
|
|
exception as PSRemotingTransportException;
|
|
|
|
|
String errorDetails = null;
|
|
|
|
|
if ((transException != null) &&
|
|
|
|
|
(transException.ErrorCode ==
|
|
|
|
|
System.Management.Automation.Remoting.Client.WSManNativeApi.ERROR_WSMAN_REDIRECT_REQUESTED))
|
|
|
|
|
{
|
|
|
|
|
// Handling a special case for redirection..we should talk about
|
|
|
|
|
// AllowRedirection parameter and WSManMaxRedirectionCount preference
|
|
|
|
|
// variables
|
|
|
|
|
string message = PSRemotingErrorInvariants.FormatResourceString(
|
|
|
|
|
RemotingErrorIdStrings.URIRedirectionReported,
|
|
|
|
|
transException.Message,
|
|
|
|
|
"MaximumConnectionRedirectionCount",
|
|
|
|
|
Microsoft.PowerShell.Commands.PSRemotingBaseCmdlet.DEFAULT_SESSION_OPTION,
|
|
|
|
|
"AllowRedirection");
|
|
|
|
|
|
|
|
|
|
errorDetails = message;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
ErrorRecord errorRecord = new ErrorRecord(exception, argument,
|
2016-07-29 13:02:49 -07:00
|
|
|
"CreateRemoteRunspaceFailed",
|
2016-03-30 14:20:52 -07:00
|
|
|
ErrorCategory.InvalidArgument,
|
|
|
|
|
null, null, null, null, null, errorDetails, null);
|
|
|
|
|
|
|
|
|
|
WriteError(errorRecord);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// Write invalid argument error.
|
|
|
|
|
/// </summary>
|
2016-07-29 13:02:49 -07:00
|
|
|
private void WriteInvalidArgumentError(PSRemotingErrorId errorId, string resourceString, object errorArgument)
|
2016-03-30 14:20:52 -07:00
|
|
|
{
|
|
|
|
|
String message = GetMessage(resourceString, errorArgument);
|
|
|
|
|
WriteError(new ErrorRecord(new ArgumentException(message), errorId.ToString(),
|
|
|
|
|
ErrorCategory.InvalidArgument, errorArgument));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// When the client remote session reports a URI redirection, this method will report the
|
|
|
|
|
/// message to the user as a Warning using Host method calls.
|
|
|
|
|
/// </summary>
|
|
|
|
|
/// <param name="sender"></param>
|
|
|
|
|
/// <param name="eventArgs"></param>
|
|
|
|
|
private void HandleURIDirectionReported(object sender, RemoteDataEventArgs<Uri> eventArgs)
|
|
|
|
|
{
|
|
|
|
|
string message = StringUtil.Format(RemotingErrorIdStrings.URIRedirectWarningToHost, eventArgs.Data.OriginalString);
|
2016-07-29 13:02:49 -07:00
|
|
|
Action<Cmdlet> streamObject = delegate (Cmdlet cmdlet)
|
2016-03-30 14:20:52 -07:00
|
|
|
{
|
|
|
|
|
cmdlet.WriteWarning(message);
|
|
|
|
|
};
|
2016-07-29 13:02:49 -07:00
|
|
|
_stream.Write(streamObject);
|
2016-03-30 14:20:52 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// Create runspace when computer name parameter specified.
|
|
|
|
|
/// </summary>
|
|
|
|
|
private RemoteRunspace CreateRunspaceWhenComputerNameParameterSpecified()
|
|
|
|
|
{
|
|
|
|
|
RemoteRunspace remoteRunspace = null;
|
2016-08-02 13:29:09 -07:00
|
|
|
string resolvedComputerName = ResolveComputerName(ComputerName);
|
2016-03-30 14:20:52 -07:00
|
|
|
try
|
|
|
|
|
{
|
|
|
|
|
WSManConnectionInfo connectionInfo = null;
|
|
|
|
|
connectionInfo = new WSManConnectionInfo();
|
|
|
|
|
string scheme = UseSSL.IsPresent ? WSManConnectionInfo.HttpsScheme : WSManConnectionInfo.HttpScheme;
|
|
|
|
|
connectionInfo.ComputerName = resolvedComputerName;
|
|
|
|
|
connectionInfo.Port = Port;
|
|
|
|
|
connectionInfo.AppName = ApplicationName;
|
|
|
|
|
connectionInfo.ShellUri = ConfigurationName;
|
|
|
|
|
connectionInfo.Scheme = scheme;
|
|
|
|
|
if (CertificateThumbprint != null)
|
|
|
|
|
{
|
|
|
|
|
connectionInfo.CertificateThumbprint = CertificateThumbprint;
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
connectionInfo.Credential = Credential;
|
2016-07-29 13:02:49 -07:00
|
|
|
}
|
2016-03-30 14:20:52 -07:00
|
|
|
|
|
|
|
|
connectionInfo.AuthenticationMechanism = Authentication;
|
|
|
|
|
UpdateConnectionInfo(connectionInfo);
|
|
|
|
|
|
|
|
|
|
connectionInfo.EnableNetworkAccess = EnableNetworkAccess;
|
|
|
|
|
|
|
|
|
|
remoteRunspace = CreateTemporaryRemoteRunspace(this.Host, connectionInfo);
|
|
|
|
|
}
|
|
|
|
|
catch (InvalidOperationException e)
|
|
|
|
|
{
|
|
|
|
|
WriteErrorCreateRemoteRunspaceFailed(e, resolvedComputerName);
|
|
|
|
|
}
|
|
|
|
|
catch (ArgumentException e)
|
|
|
|
|
{
|
|
|
|
|
WriteErrorCreateRemoteRunspaceFailed(e, resolvedComputerName);
|
|
|
|
|
}
|
|
|
|
|
catch (PSRemotingTransportException e)
|
|
|
|
|
{
|
|
|
|
|
WriteErrorCreateRemoteRunspaceFailed(e, resolvedComputerName);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return remoteRunspace;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// Create runspace when uri parameter specified.
|
|
|
|
|
/// </summary>
|
|
|
|
|
private RemoteRunspace CreateRunspaceWhenUriParameterSpecified()
|
|
|
|
|
{
|
|
|
|
|
RemoteRunspace remoteRunspace = null;
|
|
|
|
|
try
|
|
|
|
|
{
|
|
|
|
|
WSManConnectionInfo connectionInfo = new WSManConnectionInfo();
|
|
|
|
|
connectionInfo.ConnectionUri = ConnectionUri;
|
|
|
|
|
connectionInfo.ShellUri = ConfigurationName;
|
|
|
|
|
if (CertificateThumbprint != null)
|
|
|
|
|
{
|
|
|
|
|
connectionInfo.CertificateThumbprint = CertificateThumbprint;
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
connectionInfo.Credential = Credential;
|
|
|
|
|
}
|
|
|
|
|
connectionInfo.AuthenticationMechanism = Authentication;
|
|
|
|
|
UpdateConnectionInfo(connectionInfo);
|
|
|
|
|
connectionInfo.EnableNetworkAccess = EnableNetworkAccess;
|
|
|
|
|
remoteRunspace = CreateTemporaryRemoteRunspace(this.Host, connectionInfo);
|
|
|
|
|
}
|
|
|
|
|
catch (UriFormatException e)
|
|
|
|
|
{
|
|
|
|
|
WriteErrorCreateRemoteRunspaceFailed(e, ConnectionUri);
|
|
|
|
|
}
|
|
|
|
|
catch (InvalidOperationException e)
|
|
|
|
|
{
|
|
|
|
|
WriteErrorCreateRemoteRunspaceFailed(e, ConnectionUri);
|
|
|
|
|
}
|
|
|
|
|
catch (ArgumentException e)
|
|
|
|
|
{
|
|
|
|
|
WriteErrorCreateRemoteRunspaceFailed(e, ConnectionUri);
|
|
|
|
|
}
|
|
|
|
|
catch (PSRemotingTransportException e)
|
|
|
|
|
{
|
|
|
|
|
WriteErrorCreateRemoteRunspaceFailed(e, ConnectionUri);
|
|
|
|
|
}
|
|
|
|
|
catch (NotSupportedException e)
|
|
|
|
|
{
|
|
|
|
|
WriteErrorCreateRemoteRunspaceFailed(e, ConnectionUri);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return remoteRunspace;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// Get runspace matching condition.
|
|
|
|
|
/// </summary>
|
|
|
|
|
private RemoteRunspace GetRunspaceMatchingCondition(
|
2016-07-29 13:02:49 -07:00
|
|
|
Predicate<PSSession> condition,
|
|
|
|
|
PSRemotingErrorId tooFew,
|
|
|
|
|
PSRemotingErrorId tooMany,
|
2016-03-30 14:20:52 -07:00
|
|
|
string tooFewResourceString,
|
|
|
|
|
string tooManyResourceString,
|
|
|
|
|
object errorArgument)
|
|
|
|
|
{
|
|
|
|
|
// Find matches.
|
|
|
|
|
List<PSSession> matches = this.RunspaceRepository.Runspaces.FindAll(condition);
|
|
|
|
|
|
|
|
|
|
// Validate.
|
|
|
|
|
RemoteRunspace remoteRunspace = null;
|
|
|
|
|
if (matches.Count == 0)
|
|
|
|
|
{
|
|
|
|
|
WriteInvalidArgumentError(tooFew, tooFewResourceString, errorArgument);
|
|
|
|
|
}
|
|
|
|
|
else if (matches.Count > 1)
|
|
|
|
|
{
|
|
|
|
|
WriteInvalidArgumentError(tooMany, tooManyResourceString, errorArgument);
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
remoteRunspace = (RemoteRunspace)matches[0].Runspace;
|
|
|
|
|
Dbg.Assert(remoteRunspace != null, "Expected remoteRunspace != null");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return remoteRunspace;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// Get runspace matching runspace id.
|
|
|
|
|
/// </summary>
|
|
|
|
|
private RemoteRunspace GetRunspaceMatchingRunspaceId(Guid remoteRunspaceId)
|
|
|
|
|
{
|
2016-07-29 13:02:49 -07:00
|
|
|
Predicate<PSSession> condition = delegate (PSSession info)
|
2016-03-30 14:20:52 -07:00
|
|
|
{
|
|
|
|
|
return info.InstanceId == remoteRunspaceId;
|
|
|
|
|
};
|
|
|
|
|
PSRemotingErrorId tooFew = PSRemotingErrorId.RemoteRunspaceNotAvailableForSpecifiedRunspaceId;
|
|
|
|
|
PSRemotingErrorId tooMany = PSRemotingErrorId.RemoteRunspaceHasMultipleMatchesForSpecifiedRunspaceId;
|
|
|
|
|
string tooFewResourceString = RemotingErrorIdStrings.RemoteRunspaceNotAvailableForSpecifiedRunspaceId;
|
|
|
|
|
string tooManyResourceString = RemotingErrorIdStrings.RemoteRunspaceHasMultipleMatchesForSpecifiedRunspaceId;
|
|
|
|
|
return GetRunspaceMatchingCondition(condition, tooFew, tooMany, tooFewResourceString, tooManyResourceString, remoteRunspaceId);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// Get runspace matching session id.
|
|
|
|
|
/// </summary>
|
|
|
|
|
private RemoteRunspace GetRunspaceMatchingSessionId(int sessionId)
|
|
|
|
|
{
|
2016-07-29 13:02:49 -07:00
|
|
|
Predicate<PSSession> condition = delegate (PSSession info)
|
2016-03-30 14:20:52 -07:00
|
|
|
{
|
|
|
|
|
return info.Id == sessionId;
|
|
|
|
|
};
|
|
|
|
|
PSRemotingErrorId tooFew = PSRemotingErrorId.RemoteRunspaceNotAvailableForSpecifiedSessionId;
|
|
|
|
|
PSRemotingErrorId tooMany = PSRemotingErrorId.RemoteRunspaceHasMultipleMatchesForSpecifiedSessionId;
|
|
|
|
|
string tooFewResourceString = RemotingErrorIdStrings.RemoteRunspaceNotAvailableForSpecifiedSessionId;
|
|
|
|
|
string tooManyResourceString = RemotingErrorIdStrings.RemoteRunspaceHasMultipleMatchesForSpecifiedSessionId;
|
|
|
|
|
return GetRunspaceMatchingCondition(condition, tooFew, tooMany, tooFewResourceString, tooManyResourceString, sessionId);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// Get runspace matching name.
|
|
|
|
|
/// </summary>
|
|
|
|
|
private RemoteRunspace GetRunspaceMatchingName(string name)
|
|
|
|
|
{
|
2016-07-29 13:02:49 -07:00
|
|
|
Predicate<PSSession> condition = delegate (PSSession info)
|
2016-03-30 14:20:52 -07:00
|
|
|
{
|
|
|
|
|
// doing case-insensitive match for session name
|
|
|
|
|
return info.Name.Equals(name, StringComparison.OrdinalIgnoreCase);
|
|
|
|
|
};
|
|
|
|
|
PSRemotingErrorId tooFew = PSRemotingErrorId.RemoteRunspaceNotAvailableForSpecifiedName;
|
|
|
|
|
PSRemotingErrorId tooMany = PSRemotingErrorId.RemoteRunspaceHasMultipleMatchesForSpecifiedName;
|
|
|
|
|
string tooFewResourceString = RemotingErrorIdStrings.RemoteRunspaceNotAvailableForSpecifiedName;
|
|
|
|
|
string tooManyResourceString = RemotingErrorIdStrings.RemoteRunspaceHasMultipleMatchesForSpecifiedName;
|
|
|
|
|
return GetRunspaceMatchingCondition(condition, tooFew, tooMany, tooFewResourceString, tooManyResourceString, name);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private Job FindJobForRunspace(Guid id)
|
|
|
|
|
{
|
|
|
|
|
foreach (var repJob in this.JobRepository.Jobs)
|
|
|
|
|
{
|
|
|
|
|
foreach (Job childJob in repJob.ChildJobs)
|
|
|
|
|
{
|
|
|
|
|
PSRemotingChildJob remotingChildJob = childJob as PSRemotingChildJob;
|
|
|
|
|
|
|
|
|
|
if (remotingChildJob != null &&
|
|
|
|
|
remotingChildJob.Runspace != null &&
|
|
|
|
|
remotingChildJob.JobStateInfo.State == JobState.Running &&
|
|
|
|
|
remotingChildJob.Runspace.InstanceId.Equals(id))
|
|
|
|
|
{
|
|
|
|
|
return repJob;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return null;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private bool IsParameterSetForVM()
|
|
|
|
|
{
|
|
|
|
|
return ((ParameterSetName == VMIdParameterSet) ||
|
|
|
|
|
(ParameterSetName == VMNameParameterSet));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private bool IsParameterSetForContainer()
|
|
|
|
|
{
|
2016-04-28 13:41:25 -07:00
|
|
|
return (ParameterSetName == ContainerIdParameterSet);
|
2016-03-30 14:20:52 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// Whether the input is a session object or property that corresponds to
|
|
|
|
|
/// VM or container.
|
|
|
|
|
/// </summary>
|
|
|
|
|
private bool IsParameterSetForVMContainerSession()
|
|
|
|
|
{
|
|
|
|
|
RemoteRunspace remoteRunspace = null;
|
|
|
|
|
|
|
|
|
|
switch (ParameterSetName)
|
|
|
|
|
{
|
|
|
|
|
case SessionParameterSet:
|
|
|
|
|
if (this.Session != null)
|
|
|
|
|
{
|
|
|
|
|
remoteRunspace = (RemoteRunspace)this.Session.Runspace;
|
|
|
|
|
}
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case InstanceIdParameterSet:
|
|
|
|
|
remoteRunspace = GetRunspaceMatchingRunspaceId(this.InstanceId);
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case IdParameterSet:
|
|
|
|
|
remoteRunspace = GetRunspaceMatchingSessionId(this.Id);
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case NameParameterSet:
|
|
|
|
|
remoteRunspace = GetRunspaceMatchingName(this.Name);
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
default:
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if ((remoteRunspace != null) &&
|
|
|
|
|
(remoteRunspace.ConnectionInfo != null))
|
|
|
|
|
{
|
|
|
|
|
if ((remoteRunspace.ConnectionInfo is VMConnectionInfo) ||
|
|
|
|
|
(remoteRunspace.ConnectionInfo is ContainerConnectionInfo))
|
|
|
|
|
{
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// Create runspace for VM session.
|
|
|
|
|
/// </summary>
|
|
|
|
|
private RemoteRunspace GetRunspaceForVMSession()
|
|
|
|
|
{
|
|
|
|
|
RemoteRunspace remoteRunspace = null;
|
|
|
|
|
string command;
|
|
|
|
|
Collection<PSObject> results;
|
|
|
|
|
|
|
|
|
|
if (ParameterSetName == VMIdParameterSet)
|
|
|
|
|
{
|
|
|
|
|
command = "Get-VM -Id $args[0]";
|
|
|
|
|
|
|
|
|
|
try
|
|
|
|
|
{
|
|
|
|
|
results = this.InvokeCommand.InvokeScript(
|
|
|
|
|
command, false, PipelineResultTypes.None, null, this.VMId);
|
|
|
|
|
}
|
|
|
|
|
catch (CommandNotFoundException)
|
|
|
|
|
{
|
|
|
|
|
WriteError(
|
|
|
|
|
new ErrorRecord(
|
|
|
|
|
new ArgumentException(RemotingErrorIdStrings.HyperVModuleNotAvailable),
|
|
|
|
|
PSRemotingErrorId.HyperVModuleNotAvailable.ToString(),
|
|
|
|
|
ErrorCategory.NotInstalled,
|
|
|
|
|
null));
|
2016-07-29 13:02:49 -07:00
|
|
|
|
2016-03-30 14:20:52 -07:00
|
|
|
return null;
|
|
|
|
|
}
|
2016-07-29 13:02:49 -07:00
|
|
|
|
2016-03-30 14:20:52 -07:00
|
|
|
if (results.Count != 1)
|
|
|
|
|
{
|
|
|
|
|
WriteError(
|
|
|
|
|
new ErrorRecord(
|
|
|
|
|
new ArgumentException(RemotingErrorIdStrings.InvalidVMId),
|
|
|
|
|
PSRemotingErrorId.InvalidVMId.ToString(),
|
|
|
|
|
ErrorCategory.InvalidArgument,
|
|
|
|
|
null));
|
|
|
|
|
|
|
|
|
|
return null;
|
|
|
|
|
}
|
2016-04-28 13:41:25 -07:00
|
|
|
|
2016-03-30 14:20:52 -07:00
|
|
|
this.VMName = (string)results[0].Properties["VMName"].Value;
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
Dbg.Assert(ParameterSetName == VMNameParameterSet, "Expected ParameterSetName == VMName");
|
2016-07-29 13:02:49 -07:00
|
|
|
|
2016-03-30 14:20:52 -07:00
|
|
|
command = "Get-VM -Name $args";
|
|
|
|
|
|
|
|
|
|
try
|
|
|
|
|
{
|
|
|
|
|
results = this.InvokeCommand.InvokeScript(
|
|
|
|
|
command, false, PipelineResultTypes.None, null, this.VMName);
|
|
|
|
|
}
|
|
|
|
|
catch (CommandNotFoundException)
|
|
|
|
|
{
|
|
|
|
|
WriteError(
|
|
|
|
|
new ErrorRecord(
|
|
|
|
|
new ArgumentException(RemotingErrorIdStrings.HyperVModuleNotAvailable),
|
|
|
|
|
PSRemotingErrorId.HyperVModuleNotAvailable.ToString(),
|
|
|
|
|
ErrorCategory.NotInstalled,
|
|
|
|
|
null));
|
2016-07-29 13:02:49 -07:00
|
|
|
|
2016-03-30 14:20:52 -07:00
|
|
|
return null;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (results.Count == 0)
|
|
|
|
|
{
|
|
|
|
|
WriteError(
|
|
|
|
|
new ErrorRecord(
|
|
|
|
|
new ArgumentException(RemotingErrorIdStrings.InvalidVMNameNoVM),
|
|
|
|
|
PSRemotingErrorId.InvalidVMNameNoVM.ToString(),
|
|
|
|
|
ErrorCategory.InvalidArgument,
|
|
|
|
|
null));
|
|
|
|
|
|
|
|
|
|
return null;
|
|
|
|
|
}
|
|
|
|
|
else if (results.Count > 1)
|
|
|
|
|
{
|
|
|
|
|
WriteError(
|
|
|
|
|
new ErrorRecord(
|
|
|
|
|
new ArgumentException(RemotingErrorIdStrings.InvalidVMNameMultipleVM),
|
|
|
|
|
PSRemotingErrorId.InvalidVMNameMultipleVM.ToString(),
|
|
|
|
|
ErrorCategory.InvalidArgument,
|
|
|
|
|
null));
|
|
|
|
|
|
|
|
|
|
return null;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
this.VMId = (Guid)results[0].Properties["VMId"].Value;
|
|
|
|
|
this.VMName = (string)results[0].Properties["VMName"].Value;
|
|
|
|
|
}
|
2016-04-28 13:41:25 -07:00
|
|
|
|
|
|
|
|
//
|
|
|
|
|
// VM should be in running state.
|
|
|
|
|
//
|
|
|
|
|
if ((VMState)results[0].Properties["State"].Value != VMState.Running)
|
|
|
|
|
{
|
|
|
|
|
WriteError(
|
|
|
|
|
new ErrorRecord(
|
2016-07-29 13:02:49 -07:00
|
|
|
new ArgumentException(GetMessage(RemotingErrorIdStrings.InvalidVMState,
|
2016-04-28 13:41:25 -07:00
|
|
|
this.VMName)),
|
|
|
|
|
PSRemotingErrorId.InvalidVMState.ToString(),
|
|
|
|
|
ErrorCategory.InvalidArgument,
|
|
|
|
|
null));
|
|
|
|
|
|
|
|
|
|
return null;
|
|
|
|
|
}
|
2016-07-29 13:02:49 -07:00
|
|
|
|
2016-03-30 14:20:52 -07:00
|
|
|
try
|
|
|
|
|
{
|
|
|
|
|
VMConnectionInfo connectionInfo;
|
2016-03-31 17:27:44 -07:00
|
|
|
connectionInfo = new VMConnectionInfo(this.Credential, this.VMId, this.VMName, this.ConfigurationName);
|
2016-03-30 14:20:52 -07:00
|
|
|
|
|
|
|
|
remoteRunspace = CreateTemporaryRemoteRunspaceForPowerShellDirect(this.Host, connectionInfo);
|
|
|
|
|
}
|
|
|
|
|
catch (InvalidOperationException e)
|
|
|
|
|
{
|
|
|
|
|
ErrorRecord errorRecord = new ErrorRecord(e,
|
2016-07-29 13:02:49 -07:00
|
|
|
"CreateRemoteRunspaceForVMFailed",
|
2016-03-30 14:20:52 -07:00
|
|
|
ErrorCategory.InvalidOperation,
|
|
|
|
|
null);
|
2016-07-29 13:02:49 -07:00
|
|
|
|
2016-03-30 14:20:52 -07:00
|
|
|
WriteError(errorRecord);
|
|
|
|
|
}
|
|
|
|
|
catch (ArgumentException e)
|
|
|
|
|
{
|
|
|
|
|
ErrorRecord errorRecord = new ErrorRecord(e,
|
2016-07-29 13:02:49 -07:00
|
|
|
"CreateRemoteRunspaceForVMFailed",
|
2016-03-30 14:20:52 -07:00
|
|
|
ErrorCategory.InvalidArgument,
|
|
|
|
|
null);
|
2016-07-29 13:02:49 -07:00
|
|
|
|
2016-03-30 14:20:52 -07:00
|
|
|
WriteError(errorRecord);
|
|
|
|
|
}
|
|
|
|
|
catch (PSRemotingDataStructureException e)
|
2016-03-31 17:27:44 -07:00
|
|
|
{
|
|
|
|
|
ErrorRecord errorRecord;
|
|
|
|
|
|
|
|
|
|
//
|
|
|
|
|
// In case of PSDirectException, we should output the precise error message
|
|
|
|
|
// in inner exception instead of the generic one in outer exception.
|
|
|
|
|
//
|
|
|
|
|
if ((e.InnerException != null) && (e.InnerException is PSDirectException))
|
|
|
|
|
{
|
|
|
|
|
errorRecord = new ErrorRecord(e.InnerException,
|
2016-07-29 13:02:49 -07:00
|
|
|
"CreateRemoteRunspaceForVMFailed",
|
2016-03-31 17:27:44 -07:00
|
|
|
ErrorCategory.InvalidArgument,
|
2016-07-29 13:02:49 -07:00
|
|
|
null);
|
2016-03-31 17:27:44 -07:00
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
errorRecord = new ErrorRecord(e,
|
2016-07-29 13:02:49 -07:00
|
|
|
"CreateRemoteRunspaceForVMFailed",
|
2016-03-31 17:27:44 -07:00
|
|
|
ErrorCategory.InvalidOperation,
|
|
|
|
|
null);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
WriteError(errorRecord);
|
|
|
|
|
}
|
|
|
|
|
catch (Exception e)
|
2016-03-30 14:20:52 -07:00
|
|
|
{
|
|
|
|
|
ErrorRecord errorRecord = new ErrorRecord(e,
|
2016-07-29 13:02:49 -07:00
|
|
|
"CreateRemoteRunspaceForVMFailed",
|
2016-03-30 14:20:52 -07:00
|
|
|
ErrorCategory.InvalidOperation,
|
|
|
|
|
null);
|
2016-07-29 13:02:49 -07:00
|
|
|
|
2016-03-30 14:20:52 -07:00
|
|
|
WriteError(errorRecord);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return remoteRunspace;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// Create temporary remote runspace.
|
|
|
|
|
/// </summary>
|
|
|
|
|
private RemoteRunspace CreateTemporaryRemoteRunspaceForPowerShellDirect(PSHost host, RunspaceConnectionInfo connectionInfo)
|
|
|
|
|
{
|
|
|
|
|
// Create and open the runspace.
|
|
|
|
|
TypeTable typeTable = TypeTable.LoadDefaultTypeFiles();
|
|
|
|
|
RemoteRunspace remoteRunspace = RunspaceFactory.CreateRunspace(connectionInfo, host, typeTable) as RemoteRunspace;
|
|
|
|
|
remoteRunspace.Name = "PowerShellDirectAttach";
|
2016-07-29 13:02:49 -07:00
|
|
|
|
2016-03-30 14:20:52 -07:00
|
|
|
Dbg.Assert(remoteRunspace != null, "Expected remoteRunspace != null");
|
|
|
|
|
try
|
|
|
|
|
{
|
|
|
|
|
remoteRunspace.Open();
|
|
|
|
|
|
|
|
|
|
// Mark this temporary runspace so that it closes on pop.
|
|
|
|
|
remoteRunspace.ShouldCloseOnPop = true;
|
|
|
|
|
}
|
|
|
|
|
finally
|
|
|
|
|
{
|
|
|
|
|
// Make sure we dispose the temporary runspace if something bad happens.
|
|
|
|
|
if (remoteRunspace.RunspaceStateInfo.State != RunspaceState.Opened)
|
|
|
|
|
{
|
|
|
|
|
remoteRunspace.Dispose();
|
|
|
|
|
remoteRunspace = null;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return remoteRunspace;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// Set prompt for VM/Container sessions.
|
|
|
|
|
/// </summary>
|
|
|
|
|
private void SetRunspacePrompt(RemoteRunspace remoteRunspace)
|
|
|
|
|
{
|
|
|
|
|
if (IsParameterSetForVM() ||
|
|
|
|
|
IsParameterSetForContainer() ||
|
2016-07-29 13:02:49 -07:00
|
|
|
IsParameterSetForVMContainerSession())
|
2016-03-30 14:20:52 -07:00
|
|
|
{
|
|
|
|
|
string targetName = string.Empty;
|
|
|
|
|
|
|
|
|
|
switch (ParameterSetName)
|
|
|
|
|
{
|
|
|
|
|
case VMIdParameterSet:
|
|
|
|
|
case VMNameParameterSet:
|
|
|
|
|
targetName = this.VMName;
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case ContainerIdParameterSet:
|
2016-04-28 13:41:25 -07:00
|
|
|
targetName = (this.ContainerId.Length <= 15) ? this.ContainerId
|
|
|
|
|
: this.ContainerId.Remove(12) + "...";
|
2016-03-30 14:20:52 -07:00
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case SessionParameterSet:
|
|
|
|
|
targetName = (this.Session != null) ? this.Session.ComputerName : string.Empty;
|
|
|
|
|
break;
|
2016-07-29 13:02:49 -07:00
|
|
|
|
2016-03-30 14:20:52 -07:00
|
|
|
case InstanceIdParameterSet:
|
|
|
|
|
case IdParameterSet:
|
|
|
|
|
case NameParameterSet:
|
|
|
|
|
if ((remoteRunspace != null) &&
|
|
|
|
|
(remoteRunspace.ConnectionInfo != null))
|
|
|
|
|
{
|
|
|
|
|
targetName = remoteRunspace.ConnectionInfo.ComputerName;
|
|
|
|
|
}
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
default:
|
|
|
|
|
Dbg.Assert(false, "Unrecognized parameter set.");
|
|
|
|
|
break;
|
|
|
|
|
}
|
2016-07-29 13:02:49 -07:00
|
|
|
|
2016-03-30 14:20:52 -07:00
|
|
|
string promptFn = StringUtil.Format(RemotingErrorIdStrings.EnterVMSessionPrompt,
|
|
|
|
|
@"function global:prompt { """,
|
|
|
|
|
targetName,
|
|
|
|
|
@"PS $($executionContext.SessionState.Path.CurrentLocation)> "" }");
|
2016-07-29 13:02:49 -07:00
|
|
|
|
2016-03-30 14:20:52 -07:00
|
|
|
// Set prompt in pushed named pipe runspace.
|
|
|
|
|
using (System.Management.Automation.PowerShell ps = System.Management.Automation.PowerShell.Create())
|
|
|
|
|
{
|
|
|
|
|
ps.Runspace = remoteRunspace;
|
2016-07-29 13:02:49 -07:00
|
|
|
|
2016-03-30 14:20:52 -07:00
|
|
|
try
|
|
|
|
|
{
|
|
|
|
|
// Set pushed runspace prompt.
|
|
|
|
|
ps.AddScript(promptFn).Invoke();
|
|
|
|
|
}
|
|
|
|
|
catch (Exception e)
|
|
|
|
|
{
|
|
|
|
|
// Ignore all non-severe errors.
|
|
|
|
|
CommandProcessorBase.CheckForSevereException(e);
|
|
|
|
|
}
|
2016-07-29 13:02:49 -07:00
|
|
|
}
|
2016-03-30 14:20:52 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// Create runspace for container session.
|
|
|
|
|
/// </summary>
|
|
|
|
|
private RemoteRunspace GetRunspaceForContainerSession()
|
|
|
|
|
{
|
|
|
|
|
RemoteRunspace remoteRunspace = null;
|
|
|
|
|
|
|
|
|
|
try
|
|
|
|
|
{
|
2016-04-28 13:41:25 -07:00
|
|
|
Dbg.Assert(!String.IsNullOrEmpty(ContainerId), "ContainerId has to be set.");
|
|
|
|
|
|
2016-03-30 14:20:52 -07:00
|
|
|
ContainerConnectionInfo connectionInfo = null;
|
|
|
|
|
|
|
|
|
|
//
|
|
|
|
|
// Hyper-V container uses Hype-V socket as transport.
|
|
|
|
|
// Windows Server container uses named pipe as transport.
|
|
|
|
|
//
|
2016-04-28 13:41:25 -07:00
|
|
|
connectionInfo = ContainerConnectionInfo.CreateContainerConnectionInfo(ContainerId, RunAsAdministrator.IsPresent, this.ConfigurationName);
|
2016-03-30 14:20:52 -07:00
|
|
|
|
|
|
|
|
connectionInfo.CreateContainerProcess();
|
|
|
|
|
remoteRunspace = CreateTemporaryRemoteRunspaceForPowerShellDirect(this.Host, connectionInfo);
|
|
|
|
|
}
|
|
|
|
|
catch (InvalidOperationException e)
|
|
|
|
|
{
|
|
|
|
|
ErrorRecord errorRecord = new ErrorRecord(e,
|
2016-07-29 13:02:49 -07:00
|
|
|
"CreateRemoteRunspaceForContainerFailed",
|
2016-03-30 14:20:52 -07:00
|
|
|
ErrorCategory.InvalidOperation,
|
|
|
|
|
null);
|
2016-07-29 13:02:49 -07:00
|
|
|
|
2016-03-30 14:20:52 -07:00
|
|
|
WriteError(errorRecord);
|
|
|
|
|
}
|
|
|
|
|
catch (ArgumentException e)
|
|
|
|
|
{
|
|
|
|
|
ErrorRecord errorRecord = new ErrorRecord(e,
|
2016-07-29 13:02:49 -07:00
|
|
|
"CreateRemoteRunspaceForContainerFailed",
|
2016-03-30 14:20:52 -07:00
|
|
|
ErrorCategory.InvalidArgument,
|
|
|
|
|
null);
|
2016-07-29 13:02:49 -07:00
|
|
|
|
2016-03-30 14:20:52 -07:00
|
|
|
WriteError(errorRecord);
|
|
|
|
|
}
|
2016-03-31 17:27:44 -07:00
|
|
|
catch (PSRemotingDataStructureException e)
|
|
|
|
|
{
|
|
|
|
|
ErrorRecord errorRecord;
|
|
|
|
|
|
|
|
|
|
//
|
|
|
|
|
// In case of PSDirectException, we should output the precise error message
|
|
|
|
|
// in inner exception instead of the generic one in outer exception.
|
|
|
|
|
//
|
|
|
|
|
if ((e.InnerException != null) && (e.InnerException is PSDirectException))
|
|
|
|
|
{
|
|
|
|
|
errorRecord = new ErrorRecord(e.InnerException,
|
2016-07-29 13:02:49 -07:00
|
|
|
"CreateRemoteRunspaceForContainerFailed",
|
2016-03-31 17:27:44 -07:00
|
|
|
ErrorCategory.InvalidOperation,
|
2016-07-29 13:02:49 -07:00
|
|
|
null);
|
2016-03-31 17:27:44 -07:00
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
errorRecord = new ErrorRecord(e,
|
2016-07-29 13:02:49 -07:00
|
|
|
"CreateRemoteRunspaceForContainerFailed",
|
2016-03-31 17:27:44 -07:00
|
|
|
ErrorCategory.InvalidOperation,
|
|
|
|
|
null);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
WriteError(errorRecord);
|
|
|
|
|
}
|
2016-03-30 14:20:52 -07:00
|
|
|
catch (Exception e)
|
|
|
|
|
{
|
|
|
|
|
ErrorRecord errorRecord = new ErrorRecord(e,
|
2016-07-29 13:02:49 -07:00
|
|
|
"CreateRemoteRunspaceForContainerFailed",
|
2016-03-30 14:20:52 -07:00
|
|
|
ErrorCategory.InvalidOperation,
|
|
|
|
|
null);
|
2016-07-29 13:02:49 -07:00
|
|
|
|
2016-03-30 14:20:52 -07:00
|
|
|
WriteError(errorRecord);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return remoteRunspace;
|
|
|
|
|
}
|
|
|
|
|
|
2016-08-12 15:05:05 -07:00
|
|
|
/// <summary>
|
|
|
|
|
/// Create remote runspace for SSH session
|
|
|
|
|
/// </summary>
|
|
|
|
|
private RemoteRunspace GetRunspaceForSSHSession()
|
|
|
|
|
{
|
|
|
|
|
var sshConnectionInfo = new SSHConnectionInfo(this.UserName, this.HostName, this.KeyPath);
|
|
|
|
|
var typeTable = TypeTable.LoadDefaultTypeFiles();
|
|
|
|
|
var remoteRunspace = RunspaceFactory.CreateRunspace(sshConnectionInfo, this.Host, typeTable) as RemoteRunspace;
|
|
|
|
|
remoteRunspace.Open();
|
|
|
|
|
remoteRunspace.ShouldCloseOnPop = true;
|
|
|
|
|
|
|
|
|
|
return remoteRunspace;
|
|
|
|
|
}
|
|
|
|
|
|
2016-03-30 14:20:52 -07:00
|
|
|
#endregion
|
|
|
|
|
|
|
|
|
|
#region Internal Methods
|
|
|
|
|
|
|
|
|
|
internal static RemotePipeline ConnectRunningPipeline(RemoteRunspace remoteRunspace)
|
|
|
|
|
{
|
|
|
|
|
RemotePipeline cmd = null;
|
|
|
|
|
if (remoteRunspace.RemoteCommand != null)
|
|
|
|
|
{
|
|
|
|
|
// Reconstruct scenario.
|
|
|
|
|
// Newly connected pipeline object is added to the RemoteRunspace running
|
|
|
|
|
// pipeline list.
|
|
|
|
|
cmd = new RemotePipeline(remoteRunspace);
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
// Reconnect scenario.
|
|
|
|
|
cmd = remoteRunspace.GetCurrentlyRunningPipeline() as RemotePipeline;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Connect the runspace pipeline so that debugging and output data from
|
|
|
|
|
// remote server can continue.
|
|
|
|
|
if (cmd != null &&
|
|
|
|
|
cmd.PipelineStateInfo.State == PipelineState.Disconnected)
|
|
|
|
|
{
|
|
|
|
|
using (ManualResetEvent connected = new ManualResetEvent(false))
|
|
|
|
|
{
|
|
|
|
|
cmd.StateChanged += (sender, args) =>
|
|
|
|
|
{
|
|
|
|
|
if (args.PipelineStateInfo.State != PipelineState.Disconnected)
|
|
|
|
|
{
|
|
|
|
|
try
|
|
|
|
|
{
|
|
|
|
|
connected.Set();
|
|
|
|
|
}
|
|
|
|
|
catch (ObjectDisposedException) { }
|
|
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
cmd.ConnectAsync();
|
|
|
|
|
connected.WaitOne();
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return cmd;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
internal static void ContinueCommand(RemoteRunspace remoteRunspace, Pipeline cmd, PSHost host, bool inDebugMode, System.Management.Automation.ExecutionContext context)
|
|
|
|
|
{
|
|
|
|
|
RemotePipeline remotePipeline = cmd as RemotePipeline;
|
|
|
|
|
|
|
|
|
|
if (remotePipeline != null)
|
|
|
|
|
{
|
|
|
|
|
using (System.Management.Automation.PowerShell ps = System.Management.Automation.PowerShell.Create())
|
|
|
|
|
{
|
|
|
|
|
PSInvocationSettings settings = new PSInvocationSettings()
|
|
|
|
|
{
|
|
|
|
|
Host = host
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
PSDataCollection<PSObject> input = new PSDataCollection<PSObject>();
|
|
|
|
|
|
|
|
|
|
CommandInfo commandInfo = new CmdletInfo("Out-Default", typeof(OutDefaultCommand), null, null, context);
|
|
|
|
|
Command outDefaultCommand = new Command(commandInfo);
|
|
|
|
|
ps.AddCommand(outDefaultCommand);
|
|
|
|
|
IAsyncResult async = ps.BeginInvoke<PSObject>(input, settings, null, null);
|
|
|
|
|
|
|
|
|
|
RemoteDebugger remoteDebugger = remoteRunspace.Debugger as RemoteDebugger;
|
|
|
|
|
if (remoteDebugger != null)
|
|
|
|
|
{
|
|
|
|
|
// Update client with breakpoint information from pushed runspace.
|
|
|
|
|
// Information will be passed to the client via the Debugger.BreakpointUpdated event.
|
|
|
|
|
remoteDebugger.SendBreakpointUpdatedEvents();
|
|
|
|
|
|
|
|
|
|
if (!inDebugMode)
|
|
|
|
|
{
|
|
|
|
|
// Enter debug mode if remote runspace is in debug stop mode.
|
|
|
|
|
remoteDebugger.CheckStateAndRaiseStopEvent();
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Wait for debugged cmd to complete.
|
|
|
|
|
while (!remotePipeline.Output.EndOfPipeline)
|
|
|
|
|
{
|
|
|
|
|
remotePipeline.Output.WaitHandle.WaitOne();
|
|
|
|
|
while (remotePipeline.Output.Count > 0)
|
|
|
|
|
{
|
|
|
|
|
input.Add(remotePipeline.Output.Read());
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
input.Complete();
|
|
|
|
|
ps.EndInvoke(async);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#endregion
|
|
|
|
|
}
|
|
|
|
|
}
|