/********************************************************************++
Copyright (c) Microsoft Corporation. All rights reserved.
--********************************************************************/
using System;
using System.Linq;
using System.Management.Automation;
using System.Management.Automation.Remoting;
using System.Management.Automation.Runspaces;
using System.Management.Automation.Internal;
using Dbg = System.Management.Automation.Diagnostics;
using System.Collections;
using System.Collections.ObjectModel;
using System.Collections.Generic;
using System.Diagnostics.CodeAnalysis;
using System.Management.Automation.Language;
namespace Microsoft.PowerShell.Commands
{
///
/// This class defines most of the common functionality used
/// across remoting cmdlets.
///
/// It contains tons of utility functions which are used all
/// across the remoting cmdlets
///
public abstract partial class PSRemotingCmdlet : PSCmdlet
{
#region Overrides
///
/// Verifies if remoting cmdlets can be used
///
protected override void BeginProcessing()
{
if (!_skipWinRMCheck)
{
RemotingCommandUtil.CheckRemotingCmdletPrerequisites();
}
}
#endregion Overrides
#region Utility functions
///
/// Handle the object obtained from an ObjectStream's reader
/// based on its type
///
internal void WriteStreamObject(Action action)
{
action(this);
}// WriteStreamObject
///
/// Resolve all the machine names provided. Basically, if a machine
/// name is '.' assume localhost
///
/// array of computer names to resolve
/// resolved array of machine names
protected void ResolveComputerNames(string[] computerNames, out string[] resolvedComputerNames)
{
if (computerNames == null)
{
resolvedComputerNames = new string[1];
resolvedComputerNames[0] = ResolveComputerName(".");
}
else if (computerNames.Length == 0)
{
resolvedComputerNames = Utils.EmptyArray();
}
else
{
resolvedComputerNames = new string[computerNames.Length];
for (int i = 0; i < resolvedComputerNames.Length; i++)
{
resolvedComputerNames[i] = ResolveComputerName(computerNames[i]);
}
}
}// ResolveComputerNames
///
/// Resolves a computer name. If its null or empty
/// its assumed to be localhost
///
/// computer name to resolve
/// resolved computer name
protected string ResolveComputerName(string computerName)
{
Diagnostics.Assert(computerName != null, "Null ComputerName");
if (String.Equals(computerName, ".", StringComparison.OrdinalIgnoreCase))
{
//tracer.WriteEvent(ref PSEventDescriptors.PS_EVENT_HOSTNAMERESOLVE);
//tracer.Dispose();
//tracer.OperationalChannel.WriteVerbose(PSEventId.HostNameResolve, PSOpcode.Method, PSTask.CreateRunspace);
return LOCALHOST;
}
else
{
return computerName;
}
}
///
/// Load the resource corresponding to the specified errorId and
/// return the message as a string
///
/// resource String which holds the message
///
/// Error message loaded from appropriate resouce cache
internal String GetMessage(string resourceString)
{
String message = GetMessage(resourceString, null);
return message;
}// GetMessage
///
///
///
///
///
///
internal String GetMessage(string resourceString, params object[] args)
{
String message;
if (args != null)
{
message = StringUtil.Format(resourceString, args);
}
else
{
message = resourceString;
}
return message;
}
#endregion Utility functions
#region Private Members
private static string LOCALHOST = "localhost";
//private PSETWTracer tracer = PSETWTracer.GetETWTracer(PSKeyword.Cmdlets);
#endregion Private Members
#region Protected Members
///
/// Computername parameter set
///
protected const string ComputerNameParameterSet = "ComputerName";
///
/// Computername with session instance ID parameter set
///
protected const string ComputerInstanceIdParameterSet = "ComputerInstanceId";
///
/// Container ID parameter set
///
protected const string ContainerIdParameterSet = "ContainerId";
///
/// Container name parameter set
///
protected const string ContainerNameParameterSet = "ContainerName";
///
/// VM guid parameter set
///
protected const string VMIdParameterSet = "VMId";
///
/// VM name parameter set
///
protected const string VMNameParameterSet = "VMName";
///
/// runspace parameter set
///
protected const string SessionParameterSet = "Session";
///
/// Default shellname
///
protected const string DefaultPowerShellRemoteShellName = System.Management.Automation.Remoting.Client.WSManNativeApi.ResourceURIPrefix + "Microsoft.PowerShell";
///
/// default application name for the connection uri
///
protected const string DefaultPowerShellRemoteShellAppName = "WSMan";
#endregion Protected Members
#region Internal Members
private bool _skipWinRMCheck = false;
///
/// Skip checking for WinRM
///
internal bool SkipWinRMCheck
{
get
{
return _skipWinRMCheck;
}
set
{
_skipWinRMCheck = value;
}
}
#endregion Internal Members
#region Protected Methods
///
/// Determines the shellname to use based on the following order:
/// 1. ShellName parameter specified
/// 2. DEFAULTREMOTESHELLNAME variable set
/// 3. PowerShell
///
/// The shell to launch in the remote machine
protected String ResolveShell(String shell)
{
String resolvedShell;
if (!String.IsNullOrEmpty(shell))
{
resolvedShell = shell;
}
else
{
resolvedShell = (string)SessionState.Internal.ExecutionContext.GetVariableValue(
SpecialVariables.PSSessionConfigurationNameVarPath, DefaultPowerShellRemoteShellName);
}
return resolvedShell;
}
///
/// Determines the appname to be used based on the following order:
/// 1. AppName parameter specified
/// 2. DEFAULTREMOTEAPPNAME variable set
/// 3. WSMan
///
/// application name to resolve
/// resolved appname
protected String ResolveAppName(String appName)
{
String resolvedAppName;
if (!String.IsNullOrEmpty(appName))
{
resolvedAppName = appName;
}
else
{
resolvedAppName = (string)SessionState.Internal.ExecutionContext.GetVariableValue(
SpecialVariables.PSSessionApplicationNameVarPath,
DefaultPowerShellRemoteShellAppName);
}
return resolvedAppName;
}
#endregion
}
///
/// Base class for any cmdlet which takes a -Session parameter
/// or a -ComputerName parameter (along with its other associated
/// parameters). The following cmdlets currently fall under this
/// category:
/// 1. New-PSSession
/// 2. Invoke-Expression
/// 3. Start-PSJob
///
public abstract partial class PSRemotingBaseCmdlet : PSRemotingCmdlet
{
#region Tracer
//PSETWTracer tracer = PSETWTracer.GetETWTracer(PSKeyword.Runspace);
#endregion Tracer
#region Properties
///
/// The PSSession object describing the remote runspace
/// using which the specified cmdlet operation will be performed
///
[Parameter(Position = 0,
ValueFromPipelineByPropertyName = true,
ParameterSetName = PSRemotingBaseCmdlet.SessionParameterSet)]
[ValidateNotNullOrEmpty]
[SuppressMessage("Microsoft.Performance", "CA1819:PropertiesShouldNotReturnArrays")]
public virtual PSSession[] Session
{
get
{
return remoteRunspaceInfos;
}
set
{
remoteRunspaceInfos = value;
}
}
private PSSession[] remoteRunspaceInfos;
///
/// This parameter represents the address(es) of the remote
/// computer(s). The following formats are supported:
/// (a) Computer name
/// (b) IPv4 address : 132.3.4.5
/// (c) IPv6 address: 3ffe:8311:ffff:f70f:0:5efe:172.30.162.18
///
///
[Parameter(Position = 0,
ValueFromPipelineByPropertyName = true,
ParameterSetName = PSRemotingBaseCmdlet.ComputerNameParameterSet)]
[Alias("Cn")]
public virtual String[] ComputerName
{
get
{
return computerNames;
}
set
{
computerNames = value;
}
}
private String[] computerNames;
///
/// Computer names after they have been resolved
/// (null, empty string, "." resolves to localhost)
///
/// If Null or empty string is specified, then localhost is assumed.
/// The ResolveComputerNames will include this.
///
protected String[] ResolvedComputerNames
{
get
{
return resolvedComputerNames;
}
set
{
resolvedComputerNames = value;
}
}
private String[] resolvedComputerNames;
///
/// Guid of target virtual machine.
///
[SuppressMessage("Microsoft.Performance", "CA1819:PropertiesShouldNotReturnArrays",
Justification = "This is by spec.")]
[Parameter(Position = 0,
Mandatory = true,
ValueFromPipelineByPropertyName = true,
ParameterSetName = PSRemotingBaseCmdlet.VMIdParameterSet)]
[ValidateNotNullOrEmpty]
[Alias("VMGuid")]
public virtual Guid[] VMId
{
get
{
return vmId;
}
set
{
vmId = value;
}
}
private Guid[] vmId;
///
/// Name of target virtual machine.
///
[SuppressMessage("Microsoft.Performance", "CA1819:PropertiesShouldNotReturnArrays",
Justification = "This is by spec.")]
[Parameter(Mandatory = true,
ValueFromPipelineByPropertyName = true,
ParameterSetName = PSRemotingBaseCmdlet.VMNameParameterSet)]
[ValidateNotNullOrEmpty]
public virtual string[] VMName
{
get
{
return vmName;
}
set
{
vmName = value;
}
}
private string[] vmName;
///
/// Specifies the credentials of the user to impersonate in the
/// remote machine. If this parameter is not specified then the
/// credentials of the current user process will be assumed.
///
[Parameter(ValueFromPipelineByPropertyName = true,
ParameterSetName = PSRemotingBaseCmdlet.ComputerNameParameterSet)]
[Parameter(ValueFromPipelineByPropertyName = true,
ParameterSetName = PSRemotingBaseCmdlet.UriParameterSet)]
[Parameter(ValueFromPipelineByPropertyName = true,
ParameterSetName = PSRemotingBaseCmdlet.VMIdParameterSet)]
[Parameter(ValueFromPipelineByPropertyName = true,
ParameterSetName = PSRemotingBaseCmdlet.VMNameParameterSet)]
[Credential()]
public virtual PSCredential Credential
{
get
{
return pscredential;
}
set
{
pscredential = value;
ValidateSpecifiedAuthentication(Credential, CertificateThumbprint, Authentication);
}
}
private PSCredential pscredential;
///
/// ID of target container.
///
[SuppressMessage("Microsoft.Performance", "CA1819:PropertiesShouldNotReturnArrays",
Justification = "This is by spec.")]
[Parameter(Mandatory = true,
ValueFromPipelineByPropertyName = true,
ParameterSetName = PSRemotingBaseCmdlet.ContainerIdParameterSet)]
[ValidateNotNullOrEmpty]
public virtual string[] ContainerId
{
get
{
return containerId;
}
set
{
containerId = value;
}
}
private string[] containerId;
///
/// Name of target container.
///
[SuppressMessage("Microsoft.Performance", "CA1819:PropertiesShouldNotReturnArrays",
Justification = "This is by spec.")]
[Parameter(Mandatory = true,
ValueFromPipelineByPropertyName = true,
ParameterSetName = PSRemotingBaseCmdlet.ContainerNameParameterSet)]
[ValidateNotNullOrEmpty]
public virtual string[] ContainerName
{
get
{
return containerName;
}
set
{
containerName = value;
}
}
private string[] containerName;
///
/// When set, PowerShell process inside container will be launched with
/// high privileged account.
/// Otherwise (default case), PowerShell process inside container will be launched
/// with low privileged account.
///
[Parameter(ParameterSetName = PSRemotingBaseCmdlet.ContainerIdParameterSet)]
[Parameter(ParameterSetName = PSRemotingBaseCmdlet.ContainerNameParameterSet)]
public virtual SwitchParameter RunAsAdministrator
{
get
{
return runAsAdministrator;
}
set
{
runAsAdministrator = value;
}
}
private SwitchParameter runAsAdministrator;
///
/// Port specifies the alternate port to be used in case the
/// default ports are not used for the transport mechanism
/// (port 80 for http and port 443 for useSSL)
///
///
/// Currently this is being accepted as a parameter. But in future
/// support will be added to make this a part of a policy setting.
/// When a policy setting is in place this parameter can be used
/// to override the policy setting
///
[Parameter(ParameterSetName = PSRemotingBaseCmdlet.ComputerNameParameterSet)]
[ValidateRange((Int32)1, (Int32)UInt16.MaxValue)]
public virtual Int32 Port
{
get
{
return port;
}
set
{
port = value;
}
}
private Int32 port;
///
/// This parameter suggests that the transport scheme to be used for
/// remote connections is useSSL instead of the default http.Since
/// there are only two possible transport schemes that are possible
/// at this point, a SwitchParameter is being used to switch between
/// the two.
///
[Parameter(ParameterSetName = PSRemotingBaseCmdlet.ComputerNameParameterSet)]
[SuppressMessage("Microsoft.Naming", "CA1709:IdentifiersShouldBeCasedCorrectly", MessageId = "SSL")]
public virtual SwitchParameter UseSSL
{
get
{
return useSSL;
}
set
{
useSSL = value;
}
}
private SwitchParameter useSSL;
///
/// This parameters specifies the appname which identifies the connection
/// end point on the remote machine. If this parameter is not specified
/// then the value specified in DEFAULTREMOTEAPPNAME will be used. If thats
/// not specified as well, then "WSMAN" will be used
///
[Parameter(ValueFromPipelineByPropertyName = true,
ParameterSetName = PSRemotingBaseCmdlet.ComputerNameParameterSet)]
public virtual String ApplicationName
{
get
{
return appName;
}
set
{
appName = ResolveAppName(value);
}
}
private String appName;
///
/// Allows the user of the cmdlet to specify a throttling value
/// for throttling the number of remote operations that can
/// be executed simultaneously
///
[Parameter(ParameterSetName = PSRemotingBaseCmdlet.ComputerNameParameterSet)]
[Parameter(ParameterSetName = PSRemotingBaseCmdlet.SessionParameterSet)]
[Parameter(ParameterSetName = PSRemotingBaseCmdlet.UriParameterSet)]
[Parameter(ParameterSetName = PSRemotingBaseCmdlet.ContainerIdParameterSet)]
[Parameter(ParameterSetName = PSRemotingBaseCmdlet.ContainerNameParameterSet)]
[Parameter(ParameterSetName = PSRemotingBaseCmdlet.VMIdParameterSet)]
[Parameter(ParameterSetName = PSRemotingBaseCmdlet.VMNameParameterSet)]
public virtual Int32 ThrottleLimit
{
set
{
throttleLimit = value;
}
get
{
return throttleLimit;
}
}
private int throttleLimit = 0;
///
/// A complete URI(s) specified for the remote computer and shell to
/// connect to and create runspace for
///
[Parameter(Position = 0, Mandatory = true,
ValueFromPipelineByPropertyName = true,
ParameterSetName = PSRemotingBaseCmdlet.UriParameterSet)]
[ValidateNotNullOrEmpty]
[Alias("URI", "CU")]
public virtual Uri[] ConnectionUri
{
get
{
return uris;
}
set
{
uris = value;
}
}
private Uri[] uris;
///
/// The AllowRediraction parameter enables the implicit redirection functionality
///
[Parameter(ParameterSetName = PSRemotingBaseCmdlet.UriParameterSet)]
public virtual SwitchParameter AllowRedirection
{
get { return this.allowRedirection; }
set { this.allowRedirection = value; }
}
private bool allowRedirection = false;
///
/// Extended Session Options for controlling the session creation. Use
/// "New-WSManSessionOption" cmdlet to supply value for this parameter.
///
[Parameter(ParameterSetName = PSRemotingBaseCmdlet.ComputerNameParameterSet)]
[Parameter(ParameterSetName = PSRemotingBaseCmdlet.UriParameterSet)]
[ValidateNotNull]
public virtual PSSessionOption SessionOption
{
get
{
if (this.sessionOption == null)
{
object tmp = this.SessionState.PSVariable.GetValue(DEFAULT_SESSION_OPTION);
if (tmp == null || !LanguagePrimitives.TryConvertTo(tmp, out this.sessionOption))
{
this.sessionOption = new PSSessionOption();
}
}
return this.sessionOption;
}
set { this.sessionOption = value; }
}
private PSSessionOption sessionOption;
internal const string DEFAULT_SESSION_OPTION = "PSSessionOption";
// Quota related variables.
///
/// Use basic authentication to authenticate the user.
///
[Parameter(ParameterSetName = PSRemotingBaseCmdlet.ComputerNameParameterSet)]
[Parameter(ParameterSetName = PSRemotingBaseCmdlet.UriParameterSet)]
public virtual AuthenticationMechanism Authentication
{
get
{
return authMechanism;
}
set
{
authMechanism = value;
// Validate if a user can specify this authentication.
ValidateSpecifiedAuthentication(Credential, CertificateThumbprint, Authentication);
}
}
private AuthenticationMechanism authMechanism = AuthenticationMechanism.Default;
///
/// Specifies the certificate thumbprint to be used to impersonate the user on the
/// remote machine.
///
[Parameter(ParameterSetName = NewPSSessionCommand.ComputerNameParameterSet)]
[Parameter(ParameterSetName = NewPSSessionCommand.UriParameterSet)]
public virtual string CertificateThumbprint
{
get { return thumbPrint; }
set
{
thumbPrint = value;
ValidateSpecifiedAuthentication(Credential, CertificateThumbprint, Authentication);
}
}
private string thumbPrint = null;
#endregion Properties
#region Internal Static Methods
///
/// Used to resolve authentication from the parameters chosen by the user.
/// User has the following options:
/// 1. AuthMechanism + Credential
/// 2. CertiticateThumbPrint
///
/// All the above are mutually exclusive.
///
///
/// If there is ambiguity as specified above.
///
internal static void ValidateSpecifiedAuthentication(PSCredential credential, string thumbprint, AuthenticationMechanism authentication)
{
if ((credential != null) && (thumbprint != null))
{
String message = PSRemotingErrorInvariants.FormatResourceString(
RemotingErrorIdStrings.NewRunspaceAmbiguosAuthentication,
"CertificateThumbPrint", "Credential");
throw new InvalidOperationException(message);
}
if ((authentication != AuthenticationMechanism.Default) && (thumbprint != null))
{
String message = PSRemotingErrorInvariants.FormatResourceString(
RemotingErrorIdStrings.NewRunspaceAmbiguosAuthentication,
"CertificateThumbPrint", authentication.ToString());
throw new InvalidOperationException(message);
}
if ((authentication == AuthenticationMechanism.NegotiateWithImplicitCredential) &&
(credential != null))
{
string message = PSRemotingErrorInvariants.FormatResourceString(
RemotingErrorIdStrings.NewRunspaceAmbiguosAuthentication,
"Credential", authentication.ToString());
throw new InvalidOperationException(message);
}
}
#endregion
#region Private Methods
///
/// Validate the PSSession objects specified and write
/// appropriate error records.
///
/// This function will lead in terminating errors when any of
/// the validations fail
protected void ValidateRemoteRunspacesSpecified()
{
Dbg.Assert(Session != null && Session.Length != 0,
"Remote Runspaces specified must not be null or empty");
// Check if there are duplicates in the specified PSSession objects
if (RemotingCommandUtil.HasRepeatingRunspaces(Session))
{
ThrowTerminatingError(new ErrorRecord(new ArgumentException(
GetMessage(RemotingErrorIdStrings.RemoteRunspaceInfoHasDuplicates)),
PSRemotingErrorId.RemoteRunspaceInfoHasDuplicates.ToString(),
ErrorCategory.InvalidArgument, Session));
}
//BUGBUG: The following is a bogus check
// Check if the number of PSSession objects specified is greater
// than the maximum allowable range
if (RemotingCommandUtil.ExceedMaximumAllowableRunspaces(Session))
{
ThrowTerminatingError(new ErrorRecord(new ArgumentException(
GetMessage(RemotingErrorIdStrings.RemoteRunspaceInfoLimitExceeded)),
PSRemotingErrorId.RemoteRunspaceInfoLimitExceeded.ToString(),
ErrorCategory.InvalidArgument, Session));
}
} // ValidateRemoteRunspacesSpecified
///
/// Updates connection info with the data read from cmdlet's parameters and
/// sessions variables.
/// The following data is updated:
/// 1. MaxURIRedirectionCount
/// 2. MaxRecvdDataSizePerSession
/// 3. MaxRecvdDataSizePerCommand
/// 4. MaxRecvdObjectSize
///
///
internal void UpdateConnectionInfo(WSManConnectionInfo connectionInfo)
{
Dbg.Assert(connectionInfo != null, "connectionInfo cannot be null.");
connectionInfo.SetSessionOptions(this.SessionOption);
if (!ParameterSetName.Equals(PSRemotingBaseCmdlet.UriParameterSet, StringComparison.OrdinalIgnoreCase))
{
// uri redirection is supported only with URI parmeter set
connectionInfo.MaximumConnectionRedirectionCount = 0;
}
if (!this.allowRedirection)
{
// uri redirection required explicit user consent
connectionInfo.MaximumConnectionRedirectionCount = 0;
}
}
///
/// Uri parameter set
///
protected const string UriParameterSet = "Uri";
///
/// Validates computer names to check if none of them
/// happen to be a Uri. If so this throws an error
///
/// collection of computer
/// names to validate
protected void ValidateComputerName(String[] computerNames)
{
foreach (String computerName in computerNames)
{
UriHostNameType nametype = Uri.CheckHostName(computerName);
if (!(nametype == UriHostNameType.Dns || nametype == UriHostNameType.IPv4 ||
nametype == UriHostNameType.IPv6))
{
ThrowTerminatingError(new ErrorRecord(
new ArgumentException(PSRemotingErrorInvariants.FormatResourceString(
RemotingErrorIdStrings.InvalidComputerName)), "PSSessionInvalidComputerName",
ErrorCategory.InvalidArgument, computerNames));
}
}
}
#endregion Private Methods
#region Overrides
///
/// Resolves shellname and appname
///
protected override void BeginProcessing()
{
base.BeginProcessing();
// Validate IdleTimeout parameter.
int idleTimeout = (int)SessionOption.IdleTimeout.TotalMilliseconds;
if (idleTimeout != BaseTransportManager.UseServerDefaultIdleTimeout &&
idleTimeout < BaseTransportManager.MinimumIdleTimeout)
{
throw new PSArgumentException(
StringUtil.Format(RemotingErrorIdStrings.InvalidIdleTimeoutOption,
idleTimeout / 1000, BaseTransportManager.MinimumIdleTimeout / 1000));
}
if (String.IsNullOrEmpty(appName))
{
appName = ResolveAppName(null);
}
}
#endregion Overrides
}
///
/// Base class for any cmdlet which has to execute a pipeline. The
/// following cmdlets currently fall under this category:
/// 1. Invoke-Expression
/// 2. Start-PSJob
///
public abstract partial class PSExecutionCmdlet : PSRemotingBaseCmdlet
{
#region Strings
///
/// VM guid file path parameter set.
///
protected const string FilePathVMIdParameterSet = "FilePathVMId";
///
/// VM name file path parameter set.
///
protected const string FilePathVMNameParameterSet = "FilePathVMName";
///
/// Container ID file path parameter set.
///
protected const string FilePathContainerIdParameterSet = "FilePathContainerId";
///
/// Container name file path parameter set.
///
protected const string FilePathContainerNameParameterSet = "FilePathContainerName";
#endregion
#region Parameters
///
/// Input object which gets assigned to $input when executed
/// on the remote machine. This is the only parameter in
/// this cmdlet which will bind with a ValueFromPipeline=true
///
[Parameter(ValueFromPipeline = true)]
public virtual PSObject InputObject
{
get
{
return inputObject;
}
set
{
inputObject = value;
}
}
private PSObject inputObject = AutomationNull.Value;
///
/// Command to execute specified as a string. This can be a single
/// cmdlet, an expression or anything that can be internally
/// converted into a ScriptBlock
///
public virtual ScriptBlock ScriptBlock
{
get
{
return scriptBlock;
}
set
{
scriptBlock = value;
}
}
private ScriptBlock scriptBlock;
///
/// The file containing the script that the user has specified in the
/// cmdlet. This will be converted to a powershell before
/// its actually sent to the remote end
///
[Parameter(Position = 1,
Mandatory = true,
ParameterSetName = FilePathComputerNameParameterSet)]
[Parameter(Position = 1,
Mandatory = true,
ParameterSetName = FilePathSessionParameterSet)]
[Parameter(Position = 1,
Mandatory = true,
ParameterSetName = FilePathUriParameterSet)]
[ValidateNotNull]
public virtual string FilePath
{
get
{
return filePath;
}
set
{
filePath = value;
}
}
private string filePath;
///
/// True if FilePath should be processed as a literal path
///
protected bool IsLiteralPath { get; set; }
///
/// Arguments that are passed to this scriptblock
///
[Parameter()]
[Alias("Args")]
[SuppressMessage("Microsoft.Performance", "CA1819:PropertiesShouldNotReturnArrays")]
public virtual Object[] ArgumentList
{
get
{
return args;
}
set
{
args = value;
}
}
private Object[] args;
///
/// Indicates that if a job/command is invoked remotely the connection should be severed
/// right have invocation of job/command.
///
///
protected bool InvokeAndDisconnect
{
get { return this.invokeAndDisconnect; }
set { this.invokeAndDisconnect = value; }
}
private bool invokeAndDisconnect = false;
///
/// Session names optionally provided for Disconnected parameter.
///
[SuppressMessage("Microsoft.Performance", "CA1819:PropertiesShouldNotReturnArrays")]
protected string[] DisconnectedSessionName
{
get { return sessionName; }
set { sessionName = value; }
}
private string[] sessionName;
///
/// 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.
///
public virtual SwitchParameter EnableNetworkAccess
{
get { return enableNetworkAccess; }
set { enableNetworkAccess = value; }
}
private SwitchParameter enableNetworkAccess;
///
/// Guid of target virtual machine.
///
[SuppressMessage("Microsoft.Performance", "CA1819:PropertiesShouldNotReturnArrays",
Justification = "This is by spec.")]
[Parameter(Position = 0, Mandatory = true,
ValueFromPipelineByPropertyName = true,
ParameterSetName = InvokeCommandCommand.VMIdParameterSet)]
[Parameter(Position = 0, Mandatory = true,
ValueFromPipelineByPropertyName = true,
ParameterSetName = InvokeCommandCommand.FilePathVMIdParameterSet)]
[ValidateNotNullOrEmpty]
[Alias("VMGuid")]
public override Guid[] VMId
{
get { return vmId; }
set { vmId = value; }
}
private Guid[] vmId;
///
/// Name of target virtual machine.
///
[SuppressMessage("Microsoft.Performance", "CA1819:PropertiesShouldNotReturnArrays",
Justification = "This is by spec.")]
[Parameter(Mandatory = true,
ValueFromPipelineByPropertyName = true,
ParameterSetName = InvokeCommandCommand.VMNameParameterSet)]
[Parameter(Mandatory = true,
ValueFromPipelineByPropertyName = true,
ParameterSetName = InvokeCommandCommand.FilePathVMNameParameterSet)]
[ValidateNotNullOrEmpty]
public override string[] VMName
{
get { return vmName; }
set { vmName = value; }
}
private string[] vmName;
///
/// ID of target container.
///
[SuppressMessage("Microsoft.Performance", "CA1819:PropertiesShouldNotReturnArrays",
Justification = "This is by spec.")]
[Parameter(Mandatory = true,
ValueFromPipelineByPropertyName = true,
ParameterSetName = InvokeCommandCommand.ContainerIdParameterSet)]
[Parameter(Mandatory = true,
ValueFromPipelineByPropertyName = true,
ParameterSetName = InvokeCommandCommand.FilePathContainerIdParameterSet)]
[ValidateNotNullOrEmpty]
public override string[] ContainerId
{
get { return containerId; }
set { containerId = value; }
}
private string[] containerId;
///
/// Name of target container.
///
[SuppressMessage("Microsoft.Performance", "CA1819:PropertiesShouldNotReturnArrays",
Justification = "This is by spec.")]
[Parameter(Mandatory = true,
ValueFromPipelineByPropertyName = true,
ParameterSetName = InvokeCommandCommand.ContainerNameParameterSet)]
[Parameter(Mandatory = true,
ValueFromPipelineByPropertyName = true,
ParameterSetName = InvokeCommandCommand.FilePathContainerNameParameterSet)]
[ValidateNotNullOrEmpty]
public override string[] ContainerName
{
get { return containerName; }
set { containerName = value; }
}
private string[] containerName;
///
/// For WSMan session:
/// 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.
///
[Parameter(ValueFromPipelineByPropertyName = true,
ParameterSetName = InvokeCommandCommand.ComputerNameParameterSet)]
[Parameter(ValueFromPipelineByPropertyName = true,
ParameterSetName = InvokeCommandCommand.UriParameterSet)]
[Parameter(ValueFromPipelineByPropertyName = true,
ParameterSetName = InvokeCommandCommand.FilePathComputerNameParameterSet)]
[Parameter(ValueFromPipelineByPropertyName = true,
ParameterSetName = InvokeCommandCommand.FilePathUriParameterSet)]
[Parameter(ValueFromPipelineByPropertyName = true,
ParameterSetName = InvokeCommandCommand.ContainerIdParameterSet)]
[Parameter(ValueFromPipelineByPropertyName = true,
ParameterSetName = InvokeCommandCommand.ContainerNameParameterSet)]
[Parameter(ValueFromPipelineByPropertyName = true,
ParameterSetName = InvokeCommandCommand.VMIdParameterSet)]
[Parameter(ValueFromPipelineByPropertyName = true,
ParameterSetName = InvokeCommandCommand.VMNameParameterSet)]
[Parameter(ValueFromPipelineByPropertyName = true,
ParameterSetName = InvokeCommandCommand.FilePathContainerIdParameterSet)]
[Parameter(ValueFromPipelineByPropertyName = true,
ParameterSetName = InvokeCommandCommand.FilePathContainerNameParameterSet)]
[Parameter(ValueFromPipelineByPropertyName = true,
ParameterSetName = InvokeCommandCommand.FilePathVMIdParameterSet)]
[Parameter(ValueFromPipelineByPropertyName = true,
ParameterSetName = InvokeCommandCommand.FilePathVMNameParameterSet)]
public virtual String ConfigurationName
{
get
{
return shell;
}
set
{
// Only InvokeCommandCommand may enter here,
// which will call ResolveShell() if needed.
shell = value;
}
}
private String shell;
#endregion Parameters
#region Private Methods
///
/// Creates helper objects with the command for the specified
/// remote computer names
///
protected virtual void CreateHelpersForSpecifiedComputerNames()
{
ValidateComputerName(ResolvedComputerNames);
// create helper objects for computer names
RemoteRunspace remoteRunspace = null;
string scheme = UseSSL.IsPresent ? WSManConnectionInfo.HttpsScheme : WSManConnectionInfo.HttpScheme;
for (int i = 0; i < ResolvedComputerNames.Length; i++)
{
try
{
WSManConnectionInfo connectionInfo = new WSManConnectionInfo();
connectionInfo.Scheme = scheme;
connectionInfo.ComputerName = ResolvedComputerNames[i];
connectionInfo.Port = Port;
connectionInfo.AppName = ApplicationName;
connectionInfo.ShellUri = ConfigurationName;
if (CertificateThumbprint != null)
{
connectionInfo.CertificateThumbprint = CertificateThumbprint;
}
else
{
connectionInfo.Credential = Credential;
}
connectionInfo.AuthenticationMechanism = Authentication;
UpdateConnectionInfo(connectionInfo);
connectionInfo.EnableNetworkAccess = EnableNetworkAccess;
// Use the provided session name or create one for this remote runspace so that
// it can be easily identified if it becomes disconnected and is queried on the server.
int rsId = PSSession.GenerateRunspaceId();
string rsName = (DisconnectedSessionName != null && DisconnectedSessionName.Length > i) ?
DisconnectedSessionName[i] : PSSession.ComposeRunspaceName(rsId);
remoteRunspace = new RemoteRunspace(Utils.GetTypeTableFromExecutionContextTLS(), connectionInfo,
this.Host, this.SessionOption.ApplicationArguments, rsName, rsId);
remoteRunspace.Events.ReceivedEvents.PSEventReceived += OnRunspacePSEventReceived;
}
catch (UriFormatException uriException)
{
ErrorRecord errorRecord = new ErrorRecord(uriException, "CreateRemoteRunspaceFailed",
ErrorCategory.InvalidArgument, ResolvedComputerNames[i]);
WriteError(errorRecord);
continue;
}
Pipeline pipeline = CreatePipeline(remoteRunspace);
IThrottleOperation operation =
new ExecutionCmdletHelperComputerName(remoteRunspace, pipeline, this.invokeAndDisconnect);
Operations.Add(operation);
}
}// CreateHelpersForSpecifiedComputerNames
///
/// Creates helper objects with the specified command for
/// the specified remote runspaceinfo objects
///
[SuppressMessage("Microsoft.Naming", "CA1704:IdentifiersShouldBeSpelledCorrectly", MessageId = "Runspaces")]
protected void CreateHelpersForSpecifiedRunspaces()
{
RemoteRunspace[] remoteRunspaces;
Pipeline[] pipelines;
// extract RemoteRunspace out of the PSSession objects
int length = Session.Length;
remoteRunspaces = new RemoteRunspace[length];
for (int i = 0; i < length; i++)
{
remoteRunspaces[i] = (RemoteRunspace)Session[i].Runspace;
}
// create the set of pipelines from the RemoteRunspace objects and
// create IREHelperRunspace helper class to create operations
pipelines = new Pipeline[length];
for (int i = 0; i < length; i++)
{
pipelines[i] = CreatePipeline(remoteRunspaces[i]);
// create the operation object
IThrottleOperation operation = new ExecutionCmdletHelperRunspace(pipelines[i]);
Operations.Add(operation);
}
} // CreateHelpersForSpecifiedRunspaces
///
/// Creates helper objects with the command for the specified
/// remote connection uris
///
protected void CreateHelpersForSpecifiedUris()
{
// create helper objects for computer names
RemoteRunspace remoteRunspace = null;
for (int i = 0; i < ConnectionUri.Length; i++)
{
try
{
WSManConnectionInfo connectionInfo = new WSManConnectionInfo();
connectionInfo.ConnectionUri = ConnectionUri[i];
connectionInfo.ShellUri = ConfigurationName;
if (CertificateThumbprint != null)
{
connectionInfo.CertificateThumbprint = CertificateThumbprint;
}
else
{
connectionInfo.Credential = Credential;
}
connectionInfo.AuthenticationMechanism = Authentication;
UpdateConnectionInfo(connectionInfo);
connectionInfo.EnableNetworkAccess = EnableNetworkAccess;
remoteRunspace = (RemoteRunspace)RunspaceFactory.CreateRunspace(connectionInfo, this.Host,
Utils.GetTypeTableFromExecutionContextTLS(),
this.SessionOption.ApplicationArguments);
Dbg.Assert(remoteRunspace != null,
"RemoteRunspace object created using URI is null");
remoteRunspace.Events.ReceivedEvents.PSEventReceived += OnRunspacePSEventReceived;
}
catch (UriFormatException e)
{
WriteErrorCreateRemoteRunspaceFailed(e, ConnectionUri[i]);
continue;
}
catch (InvalidOperationException e)
{
WriteErrorCreateRemoteRunspaceFailed(e, ConnectionUri[i]);
continue;
}
catch (ArgumentException e)
{
WriteErrorCreateRemoteRunspaceFailed(e, ConnectionUri[i]);
continue;
}
Pipeline pipeline = CreatePipeline(remoteRunspace);
IThrottleOperation operation =
new ExecutionCmdletHelperComputerName(remoteRunspace, pipeline, this.invokeAndDisconnect);
Operations.Add(operation);
}
} // CreateHelpersForSpecifiedUris
///
/// Creates helper objects with the command for the specified
/// VM GUIDs or VM names.
///
protected virtual void CreateHelpersForSpecifiedVMSession()
{
int inputArraySize;
int index;
string command;
Collection results;
if ((ParameterSetName == PSExecutionCmdlet.VMIdParameterSet) ||
(ParameterSetName == PSExecutionCmdlet.FilePathVMIdParameterSet))
{
inputArraySize = this.VMId.Length;
this.VMName = new string[inputArraySize];
for (index = 0; index < inputArraySize; index++)
{
command = "Get-VM -Id $args[0]";
try
{
results = this.InvokeCommand.InvokeScript(
command, false, PipelineResultTypes.None, null, this.VMId[index]);
}
catch (CommandNotFoundException)
{
ThrowTerminatingError(
new ErrorRecord(
new ArgumentException(RemotingErrorIdStrings.HyperVModuleNotAvailable),
PSRemotingErrorId.HyperVModuleNotAvailable.ToString(),
ErrorCategory.NotInstalled,
null));
return;
}
if (results.Count != 1)
{
this.VMName[index] = string.Empty;
}
else
{
this.VMName[index] = (string)results[0].Properties["VMName"].Value;
}
}
}
else
{
Dbg.Assert((ParameterSetName == PSExecutionCmdlet.VMNameParameterSet) ||
(ParameterSetName == PSExecutionCmdlet.FilePathVMNameParameterSet),
"Expected ParameterSetName == VMName or FilePathVMName");
inputArraySize = this.VMName.Length;
this.VMId = new Guid[inputArraySize];
for (index = 0; index < inputArraySize; index++)
{
command = "Get-VM -Name $args";
try
{
results = this.InvokeCommand.InvokeScript(
command, false, PipelineResultTypes.None, null, this.VMName[index]);
}
catch (CommandNotFoundException)
{
ThrowTerminatingError(
new ErrorRecord(
new ArgumentException(RemotingErrorIdStrings.HyperVModuleNotAvailable),
PSRemotingErrorId.HyperVModuleNotAvailable.ToString(),
ErrorCategory.NotInstalled,
null));
return;
}
if (results.Count != 1)
{
this.VMId[index] = Guid.Empty;
}
else
{
this.VMId[index] = (Guid)results[0].Properties["VMId"].Value;
this.VMName[index] = (string)results[0].Properties["VMName"].Value;
}
}
}
ResolvedComputerNames = this.VMName;
for (index = 0; index < ResolvedComputerNames.Length; index++)
{
if ((this.VMId[index] == Guid.Empty) &&
((ParameterSetName == PSExecutionCmdlet.VMNameParameterSet) ||
(ParameterSetName == PSExecutionCmdlet.FilePathVMNameParameterSet)))
{
WriteError(
new ErrorRecord(
new ArgumentException(GetMessage(RemotingErrorIdStrings.InvalidVMNameNotSingle,
this.VMName[index])),
PSRemotingErrorId.InvalidVMNameNotSingle.ToString(),
ErrorCategory.InvalidArgument,
null));
continue;
}
else if ((this.VMName[index] == string.Empty) &&
((ParameterSetName == PSExecutionCmdlet.VMIdParameterSet) ||
(ParameterSetName == PSExecutionCmdlet.FilePathVMIdParameterSet)))
{
WriteError(
new ErrorRecord(
new ArgumentException(GetMessage(RemotingErrorIdStrings.InvalidVMIdNotSingle,
this.VMId[index].ToString(null))),
PSRemotingErrorId.InvalidVMIdNotSingle.ToString(),
ErrorCategory.InvalidArgument,
null));
continue;
}
// create helper objects for VM GUIDs or names
RemoteRunspace remoteRunspace = null;
VMConnectionInfo connectionInfo;
try
{
connectionInfo = new VMConnectionInfo(this.Credential, this.VMId[index], this.VMName[index], this.ConfigurationName);
remoteRunspace = new RemoteRunspace(Utils.GetTypeTableFromExecutionContextTLS(),
connectionInfo, this.Host, null, null, -1);
remoteRunspace.Events.ReceivedEvents.PSEventReceived += OnRunspacePSEventReceived;
}
catch (InvalidOperationException e)
{
ErrorRecord errorRecord = new ErrorRecord(e,
"CreateRemoteRunspaceForVMFailed",
ErrorCategory.InvalidOperation,
null);
WriteError(errorRecord);
}
catch (ArgumentException e)
{
ErrorRecord errorRecord = new ErrorRecord(e,
"CreateRemoteRunspaceForVMFailed",
ErrorCategory.InvalidArgument,
null);
WriteError(errorRecord);
}
Pipeline pipeline = CreatePipeline(remoteRunspace);
IThrottleOperation operation =
new ExecutionCmdletHelperComputerName(remoteRunspace, pipeline, false);
Operations.Add(operation);
}
}// CreateHelpersForSpecifiedVMSession
///
/// Creates helper objects with the command for the specified
/// container IDs or names.
///
protected virtual void CreateHelpersForSpecifiedContainerSession()
{
string[] inputArray;
bool isContainerIdSet = false;
List resolvedNameList = new List();
if ((ParameterSetName == PSExecutionCmdlet.ContainerIdParameterSet) ||
(ParameterSetName == PSExecutionCmdlet.FilePathContainerIdParameterSet))
{
inputArray = ContainerId;
isContainerIdSet = true;
}
else
{
Dbg.Assert((ParameterSetName == PSExecutionCmdlet.ContainerNameParameterSet) ||
(ParameterSetName == PSExecutionCmdlet.FilePathContainerNameParameterSet),
"Expected ParameterSetName == ContainerId, ContainerName, FilePathContainerId or FilePathContainerName");
inputArray = ContainerName;
}
foreach (var input in inputArray)
{
//
// Create helper objects for container ID or name.
//
RemoteRunspace remoteRunspace = null;
ContainerConnectionInfo connectionInfo = null;
try
{
//
// Hyper-V container uses Hype-V socket as transport.
// Windows Server container uses named pipe as transport.
//
if (isContainerIdSet)
{
connectionInfo = ContainerConnectionInfo.CreateContainerConnectionInfoById(input, RunAsAdministrator.IsPresent, this.ConfigurationName);
}
else
{
connectionInfo = ContainerConnectionInfo.CreateContainerConnectionInfoByName(input, RunAsAdministrator.IsPresent, this.ConfigurationName);
}
resolvedNameList.Add(connectionInfo.ComputerName);
connectionInfo.CreateContainerProcess();
remoteRunspace = new RemoteRunspace(Utils.GetTypeTableFromExecutionContextTLS(),
connectionInfo, this.Host, null, null, -1);
remoteRunspace.Events.ReceivedEvents.PSEventReceived += OnRunspacePSEventReceived;
}
catch (InvalidOperationException e)
{
ErrorRecord errorRecord = new ErrorRecord(e,
"CreateRemoteRunspaceForContainerFailed",
ErrorCategory.InvalidOperation,
null);
WriteError(errorRecord);
continue;
}
catch (ArgumentException e)
{
ErrorRecord errorRecord = new ErrorRecord(e,
"CreateRemoteRunspaceForContainerFailed",
ErrorCategory.InvalidArgument,
null);
WriteError(errorRecord);
continue;
}
catch (Exception e)
{
ErrorRecord errorRecord = new ErrorRecord(e,
"CreateRemoteRunspaceForContainerFailed",
ErrorCategory.InvalidOperation,
null);
WriteError(errorRecord);
continue;
}
Pipeline pipeline = CreatePipeline(remoteRunspace);
IThrottleOperation operation =
new ExecutionCmdletHelperComputerName(remoteRunspace, pipeline, false);
Operations.Add(operation);
}
ResolvedComputerNames = resolvedNameList.ToArray();
}// CreateHelpersForSpecifiedContainerSession
///
/// Creates a pipeline from the powershell
///
/// runspace on which to create the pipeline
/// a pipeline
internal Pipeline CreatePipeline(RemoteRunspace remoteRunspace)
{
// The fix to WinBlue#475223 changed how UsingExpression is handled on the client/server sides, if the remote end is PSv5
// or later, we send the dictionary-form using values to the remote end. If the remote end is PSv3 or PSv4, then we send
// the array-form using values if all UsingExpressions are in the same scope, otherwise, we handle the UsingExpression as
// if the remote end is PSv2.
string serverPsVersion = GetRemoteServerPsVersion(remoteRunspace);
System.Management.Automation.PowerShell powershellToUse = (serverPsVersion == PSv2)
? GetPowerShellForPSv2()
: GetPowerShellForPSv3OrLater(serverPsVersion);
Pipeline pipeline =
remoteRunspace.CreatePipeline(powershellToUse.Commands.Commands[0].CommandText, true);
pipeline.Commands.Clear();
foreach (Command command in powershellToUse.Commands.Commands)
{
pipeline.Commands.Add(command);
}
pipeline.RedirectShellErrorOutputPipe = true;
return pipeline;
}
///
/// Check the powershell version of the remote server
///
private string GetRemoteServerPsVersion(RemoteRunspace remoteRunspace)
{
if (remoteRunspace.ConnectionInfo is NewProcessConnectionInfo)
{
// This is for Start-Job. The remote end is actually a child local powershell process, so it must be PSv5 or later
return PSv5OrLater;
}
PSPrimitiveDictionary psApplicationPrivateData = remoteRunspace.GetApplicationPrivateData();
if (psApplicationPrivateData == null)
{
// The remote runspace is not opened yet, or it's disconnected before the private data is retrieved.
// In this case we cannot validate if the remote server is running PSv5 or later, so for safety purpose,
// we will handle the $using expressions as if the remote server is PSv2.
return PSv2;
}
// Unfortunately, the PSVersion value in the private data from PSv3 and PSv4 server is always 2.0.
// This got fixed in PSv5, so a PSv5 server will return 5.0. That means we need other way to tell
// if the remote server is PSv2 or PSv3+. After PSv3, remote runspace supports connect/disconnect,
// so we can use it to differentiate PSv2 from PSv3+.
if (remoteRunspace.CanDisconnect)
{
Version serverPsVersion = null;
PSPrimitiveDictionary.TryPathGet(
psApplicationPrivateData,
out serverPsVersion,
PSVersionInfo.PSVersionTableName,
PSVersionInfo.PSVersionName);
if (serverPsVersion != null)
{
return serverPsVersion.Major >= 5 ? PSv5OrLater : PSv3Orv4;
}
// The private data is available but we failed to get the server powershell version.
// This should never happen, but in case it happens, handle the $using expressions
// as if the remote server is PSv2.
Dbg.Assert(false, "Application private data is available but we failed to get the server powershell version. This should never happen.");
}
return PSv2;
}
///
/// Adds forwarded events to the local queue
///
internal void OnRunspacePSEventReceived(object sender, PSEventArgs e)
{
if(this.Events != null)
this.Events.AddForwardedEvent(e);
}
#endregion Private Methods
#region Protected Members / Methods
///
/// List of operations
///
internal List Operations
{
get
{
return operations;
}
}
private List operations =
new List();
///
/// Closes the input streams on all the pipelines
///
protected void CloseAllInputStreams()
{
foreach (IThrottleOperation operation in Operations)
{
ExecutionCmdletHelper helper = (ExecutionCmdletHelper)operation;
helper.Pipeline.Input.Close();
}
} // CloseAllInputStreams
///
/// Writes an error record specifying that creation of remote runspace
/// failed
///
/// exception which is causing this error record
/// to be written
/// Uri which caused this exception
private void WriteErrorCreateRemoteRunspaceFailed(Exception e, Uri uri)
{
Dbg.Assert(e is UriFormatException || e is InvalidOperationException ||
e is ArgumentException,
"Exception has to be of type UriFormatException or InvalidOperationException or ArgumentException");
ErrorRecord errorRecord = new ErrorRecord(e, "CreateRemoteRunspaceFailed",
ErrorCategory.InvalidArgument, uri);
WriteError(errorRecord);
} // WriteErrorCreateRemoteRunspaceFailed
///
/// FilePathComputername parameter set
///
protected const string FilePathComputerNameParameterSet = "FilePathComputerName";
///
/// LiteralFilePathComputername parameter set
///
protected const string LiteralFilePathComputerNameParameterSet = "LiteralFilePathComputerName";
///
/// FilePathRunspace parameter set
///
[SuppressMessage("Microsoft.Naming", "CA1704:IdentifiersShouldBeSpelledCorrectly", MessageId = "Runspace")]
protected const string FilePathSessionParameterSet = "FilePathRunspace";
///
/// FilePathUri parameter set
///
protected const string FilePathUriParameterSet = "FilePathUri";
///
/// PS version of the remote server
///
private const string PSv5OrLater = "PSv5OrLater";
private const string PSv3Orv4 = "PSv3Orv4";
private const string PSv2 = "PSv2";
private System.Management.Automation.PowerShell _powershellV2;
private System.Management.Automation.PowerShell _powershellV3;
///
/// Reads content of file and converts it to a scriptblock
///
///
///
///
protected ScriptBlock GetScriptBlockFromFile(string filePath, bool isLiteralPath)
{
//Make sure filepath doesn't contain wildcards
if ((! isLiteralPath) && WildcardPattern.ContainsWildcardCharacters(filePath))
{
throw new ArgumentException(PSRemotingErrorInvariants.FormatResourceString(RemotingErrorIdStrings.WildCardErrorFilePathParameter), "filePath");
}
if (!filePath.EndsWith(".ps1", StringComparison.OrdinalIgnoreCase))
{
throw new ArgumentException(PSRemotingErrorInvariants.FormatResourceString(RemotingErrorIdStrings.FilePathShouldPS1Extension), "filePath");
}
//Resolve file path
PathResolver resolver = new PathResolver();
string resolvedPath = resolver.ResolveProviderAndPath(filePath, isLiteralPath, this, false, RemotingErrorIdStrings.FilePathNotFromFileSystemProvider);
//read content of file
ExternalScriptInfo scriptInfo = new ExternalScriptInfo(filePath, resolvedPath, this.Context);
// Skip ShouldRun check for .psd1 files.
// Use ValidateScriptInfo() for explicitly validating the checkpolicy for psd1 file.
//
if (!filePath.EndsWith(".psd1", StringComparison.OrdinalIgnoreCase))
{
this.Context.AuthorizationManager.ShouldRunInternal(scriptInfo, CommandOrigin.Internal, this.Context.EngineHostInterface);
}
return scriptInfo.ScriptBlock;
}
#endregion Protected Members / Methods
#region Overrides
///
/// Creates the helper classes for the specified
/// parameter set
///
protected override void BeginProcessing()
{
if ((ParameterSetName == PSExecutionCmdlet.VMIdParameterSet) ||
(ParameterSetName == PSExecutionCmdlet.VMNameParameterSet) ||
(ParameterSetName == PSExecutionCmdlet.ContainerIdParameterSet) ||
(ParameterSetName == PSExecutionCmdlet.ContainerNameParameterSet) ||
(ParameterSetName == PSExecutionCmdlet.FilePathVMIdParameterSet) ||
(ParameterSetName == PSExecutionCmdlet.FilePathVMNameParameterSet) ||
(ParameterSetName == PSExecutionCmdlet.FilePathContainerIdParameterSet) ||
(ParameterSetName == PSExecutionCmdlet.FilePathContainerNameParameterSet))
{
SkipWinRMCheck = true;
}
base.BeginProcessing();
if (filePath != null)
{
scriptBlock = GetScriptBlockFromFile(filePath, IsLiteralPath);
}
switch (ParameterSetName)
{
case PSExecutionCmdlet.FilePathComputerNameParameterSet:
case PSExecutionCmdlet.LiteralFilePathComputerNameParameterSet:
case PSExecutionCmdlet.ComputerNameParameterSet:
{
String[] resolvedComputerNames = null;
ResolveComputerNames(ComputerName, out resolvedComputerNames);
ResolvedComputerNames = resolvedComputerNames;
CreateHelpersForSpecifiedComputerNames();
}
break;
case PSExecutionCmdlet.FilePathSessionParameterSet:
case PSExecutionCmdlet.SessionParameterSet:
{
ValidateRemoteRunspacesSpecified();
CreateHelpersForSpecifiedRunspaces();
}
break;
case PSExecutionCmdlet.FilePathUriParameterSet:
case PSExecutionCmdlet.UriParameterSet:
{
CreateHelpersForSpecifiedUris();
}
break;
case PSExecutionCmdlet.VMIdParameterSet:
case PSExecutionCmdlet.VMNameParameterSet:
case PSExecutionCmdlet.FilePathVMIdParameterSet:
case PSExecutionCmdlet.FilePathVMNameParameterSet:
{
CreateHelpersForSpecifiedVMSession();
}
break;
case PSExecutionCmdlet.ContainerIdParameterSet:
case PSExecutionCmdlet.ContainerNameParameterSet:
case PSExecutionCmdlet.FilePathContainerIdParameterSet:
case PSExecutionCmdlet.FilePathContainerNameParameterSet:
{
CreateHelpersForSpecifiedContainerSession();
}
break;
}
}
#endregion Overrides
#region "Get PowerShell instance"
///
/// Get the PowerShell instance for the PSv2 remote end
/// Generate the PowerShell instance by using the text of the scriptblock
///
///
/// PSv2 doesn't understand the '$using' prefix. To make UsingExpression work on PSv2 remote end, we will have to
/// alter the script, and send the altered script to the remote end. Since the script is altered, when there is an
/// error, the error message will show the altered script, and that could be confusing to the user. So if the remote
/// server is PSv3 or later version, we will use a different approach to handle UsingExpression so that we can keep
/// the script unchanged.
///
/// However, on PSv3 and PSv4 remote server, it's not well supported if UsingExpressions are used in different scopes (fixed in PSv5).
/// If the remote end is PSv3 or PSv4, and there are UsingExpressions in different scopes, then we have to revert back to the approach
/// used for PSv2 remote server.
///
///
private System.Management.Automation.PowerShell GetPowerShellForPSv2()
{
if (_powershellV2 != null) { return _powershellV2; }
// Try to convert the scriptblock to powershell commands.
_powershellV2 = ConvertToPowerShell();
if (_powershellV2 != null)
{
// Look for EndOfStatement tokens.
foreach (var command in _powershellV2.Commands.Commands)
{
if (command.IsEndOfStatement)
{
// PSv2 cannot process this. Revert to sending script.
_powershellV2 = null;
break;
}
}
if (_powershellV2 != null) { return _powershellV2; }
}
List newParameterNames;
List