Files
PowerShell/src/System.Management.Automation/engine/hostifaces/Connection.cs
T
2016-04-13 09:41:34 -07:00

1958 lines
70 KiB
C#
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
/********************************************************************++
Copyright (c) Microsoft Corporation. All rights reserved.
--********************************************************************/
using System;
using System.Diagnostics.CodeAnalysis;
using System.Runtime.Serialization;
using System.Threading;
using System.Management.Automation.Host;
using System.Management.Automation.Internal;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using Dbg = System.Management.Automation.Diagnostics;
#if CORECLR
// Use stub for SerializableAttribute, NonSerializedAttribute and ISerializable related types
using Microsoft.PowerShell.CoreClr.Stubs;
#endif
namespace System.Management.Automation.Runspaces
{
#region Exceptions
/// <summary>
/// Exception thrown when state of the runspace is different from
/// expected state of runspace.
/// </summary>
[Serializable]
public class InvalidRunspaceStateException : SystemException
{
/// <summary>
/// Initializes a new instance of InvalidRunspaceStateException
/// </summary>
public InvalidRunspaceStateException ()
:base
(
StringUtil.Format(RunspaceStrings.InvalidRunspaceStateGeneral)
)
{
}
/// <summary>
/// Initializes a new instance of InvalidRunspaceStateException with a specified error message.
/// </summary>
/// <param name="message">
/// The message that describes the error.
/// </param>
public InvalidRunspaceStateException (string message)
:base(message)
{
}
/// <summary>
/// Initializes a new instance of the InvalidRunspaceStateException class
/// with a specified error message and a reference to the inner exception
/// that is the cause of this exception.
/// </summary>
/// <param name="message">
/// The message that describes the error.
/// </param>
/// <param name="innerException">
/// The exception that is the cause of the current exception.
/// </param>
public InvalidRunspaceStateException (string message, Exception innerException)
:base(message, innerException)
{
}
/// <summary>
/// Initializes a new instance of the InvalidRunspaceStateException
/// with a specified error message and current and expected state.
/// </summary>
/// <param name="message">The message that describes the error. </param>
/// <param name="currentState">Current state of runspace</param>
/// <param name="expectedState">Expected states of runspace</param>
internal InvalidRunspaceStateException
(
string message,
RunspaceState currentState,
RunspaceState expectedState
)
:base(message)
{
_expectedState = expectedState;
_currentState = currentState;
}
#region ISerializable Members
// 2005/04/20-JonN No need to implement GetObjectData
// if all fields are static or [NonSerialized]
/// <summary>
/// Initializes a new instance of the <see cref="InvalidRunspaceStateException"/>
/// class with serialized data.
/// </summary>
/// <param name="info">
/// The <see cref="SerializationInfo"/> that holds the serialized object
/// data about the exception being thrown.
/// </param>
/// <param name="context">
/// The <see cref="StreamingContext"/> that contains contextual information
/// about the source or destination.
/// </param>
protected InvalidRunspaceStateException(SerializationInfo info, StreamingContext context)
: base(info, context)
{
}
#endregion
/// <summary>
/// Access CurrentState of the runspace.
/// </summary>
/// <remarks>This is the state of the runspace when exception was thrown.
/// </remarks>
public RunspaceState CurrentState
{
get
{
return _currentState;
}
internal set
{
_currentState = value;
}
}
/// <summary>
/// Expected state of runspace by the operation which has thrown this exception.
/// </summary>
public RunspaceState ExpectedState
{
get
{
return _expectedState;
}
internal set
{
_expectedState = value;
}
}
/// <summary>
/// State of the runspace when exception was thrown.
/// </summary>
[NonSerialized]
private RunspaceState _currentState = 0;
/// <summary>
/// States of the runspace expected in method which throws this exception.
/// </summary>
[NonSerialized]
private RunspaceState _expectedState = 0;
}
#endregion Exceptions
#region Runspace state
/// <summary>
/// Defines various states of runspace.
/// </summary>
public enum RunspaceState
{
/// <summary>
/// Beginning state upon creation
/// </summary>
BeforeOpen = 0,
/// <summary>
/// A runspace is being established.
/// </summary>
Opening = 1,
/// <summary>
/// The runspace is established and valid.
/// </summary>
Opened = 2,
/// <summary>
/// The runspace is closed or has not been established.
/// </summary>
Closed = 3,
/// <summary>
/// The runspace is being closed
/// </summary>
Closing = 4,
/// <summary>
/// The runspace has been disconnected abnormally.
/// </summary>
Broken = 5,
/// <summary>
/// The runspace is being disconnected.
/// </summary>
Disconnecting = 6,
/// <summary>
/// The runspace is disconnected.
/// </summary>
Disconnected = 7,
/// <summary>
/// The runspace is Connecting.
/// </summary>
Connecting = 8
}
/// <summary>
/// These options control whether a new thread is created when a command is executed within a runspace
/// </summary>
public enum PSThreadOptions
{
/// <summary>
/// Use the default options: UseNewThread for local Runspace, ReuseThread for local RunspacePool, server settings for remote Runspace and RunspacePool
/// </summary>
Default = 0,
/// <summary>
/// Creates a new thread for each invocation
/// </summary>
UseNewThread = 1,
/// <summary>
/// Creates a new thread for the first invocation and then re-uses
/// that thread in subsequent invocations.
/// </summary>
ReuseThread = 2,
/// <summary>
/// Doesn’t create a new thread; the execution occurs on the
/// thread that calls Invoke.
/// </summary>
/// <remarks>
/// This option is not valid for asynchronous calls
/// </remarks>
UseCurrentThread = 3
};
/// <summary>
/// Defines type which has information about RunspaceState and
/// Exception associated with RunspaceState
/// </summary>
public sealed class RunspaceStateInfo
{
#region constructors
/// <summary>
/// Constructor for state changes not resulting from an error.
/// </summary>
/// <param name="state">The state of the runspace.</param>
internal RunspaceStateInfo (RunspaceState state)
: this (state, null)
{
}
/// <summary>
/// Constructor for state changes with an optional error
/// </summary>
/// <param name="state">The state of runspace.</param>
/// <param name="reason">A non-null exception if the state change was
/// caused by an error, otherwise; null.
/// </param>
internal RunspaceStateInfo (RunspaceState state, Exception reason)
: base()
{
_state = state;
_reason = reason;
}
/// <summary>
/// Copy constructor to support cloning.
/// </summary>
/// <param name="runspaceStateInfo">The source
/// RunspaceStateInfo
/// </param>
internal RunspaceStateInfo (RunspaceStateInfo runspaceStateInfo)
{
_state = runspaceStateInfo.State;
_reason = runspaceStateInfo.Reason;
}
#endregion constructors
#region public_properties
/// <summary>
/// The state of the runspace.
/// </summary>
public RunspaceState State
{
get
{
return _state;
}
}
/// <summary>
/// The reason for the state change, if caused by an error.
/// </summary>
/// <remarks>
/// The value of this property is non-null if the state
/// changed due to an error. Otherwise, the value of this
/// property is null.
/// </remarks>
public Exception Reason
{
get
{
return _reason;
}
}
#endregion public_properties
/// <summary>
/// override for ToString()
/// </summary>
/// <returns></returns>
public override string ToString()
{
return _state.ToString();
}
/// <summary>
/// Clones current object
/// </summary>
/// <returns>Cloned object</returns>
internal RunspaceStateInfo Clone()
{
return new RunspaceStateInfo(this);
}
#region private_fields
/// <summary>
/// State of runspace
/// </summary>
private RunspaceState _state;
/// <summary>
/// The reason for the state change, if caused by an error.
/// </summary>
private Exception _reason;
#endregion private_fields
}
/// <summary>
/// Defines Event arguments passed to RunspaceStateEvent handler
/// <see cref="Runspace.StateChanged"/> event.
/// </summary>
public sealed class RunspaceStateEventArgs : EventArgs
{
#region constructors
/// <summary>
/// Constructs RunspaceStateEventArgs using RunspaceStateInfo
/// </summary>
/// <param name="runspaceStateInfo">The information about
/// current state of the runspace.</param>
/// <exception cref="ArgumentNullException">runspaceStateInfo is null
/// </exception>
internal RunspaceStateEventArgs (RunspaceStateInfo runspaceStateInfo)
{
if (runspaceStateInfo == null)
{
throw PSTraceSource.NewArgumentNullException ("runspaceStateInfo");
}
_runspaceStateInfo = runspaceStateInfo;
}
#endregion constructors
#region public_properties
/// <summary>
/// Information about state of the runspace
/// </summary>
/// <remarks>
/// This value indicates the state of the runspace after the
/// change.
/// </remarks>
public RunspaceStateInfo RunspaceStateInfo
{
get
{
return _runspaceStateInfo;
}
}
#endregion public_properties
/// <summary>
/// RunspaceStateInfo when event raised.
/// </summary>
private RunspaceStateInfo _runspaceStateInfo;
}
/// <summary>
/// Enum to indicate whether a Runspace is busy or available
/// </summary>
public enum RunspaceAvailability
{
/// <summary>
/// The Runspace is not been in the Opened state
/// </summary>
None = 0,
/// <summary>
/// The Runspace is available to execute commands
/// </summary>
Available,
/// <summary>
/// The Runspace is available to execute nested commands
/// </summary>
AvailableForNestedCommand,
/// <summary>
/// The Runspace is busy executing a command
/// </summary>
Busy,
/// <summary>
/// Applies only to remote runspace case. The remote runspace
/// is currently in a Debugger Stop mode and requires a debugger
/// SetDebuggerAction() call to continue.
/// </summary>
RemoteDebug
}
/// <summary>
/// Defines the event arguments passed to the AvailabilityChanged <see cref="Runspace.AvailabilityChanged"/> event.
/// </summary>
public sealed class RunspaceAvailabilityEventArgs : EventArgs
{
internal RunspaceAvailabilityEventArgs(RunspaceAvailability runspaceAvailability)
{
_runspaceAvailability = runspaceAvailability;
}
/// <summary>
/// Whether the Runspace is available to execute commands
/// </summary>
public RunspaceAvailability RunspaceAvailability
{
get
{
return _runspaceAvailability;
}
}
private RunspaceAvailability _runspaceAvailability;
}
#endregion Runspace state
#region Runspace capabilities
/// <summary>
/// Defines runspace capabilities.
/// </summary>
public enum RunspaceCapability
{
/// <summary>
/// No additional capabilites beyond a default runspace.
/// </summary>
Default = 0x0,
/// <summary>
/// Runspace and remoting layer supports disconnect/connect feature.
/// </summary>
SupportsDisconnect = 0x1,
/// <summary>
/// Runspace is based on a named pipe transport.
/// </summary>
NamedPipeTransport = 0x2,
/// <summary>
/// Runspace is based on a VM socket transport.
/// </summary>
VMSocketTransport = 0x4
}
#endregion
/// <summary>
/// Public interface to Msh Runtime. Provides APIs for creating pipelines,
/// access session state etc.
/// </summary>
public abstract class Runspace : IDisposable
{
#region Private Data
private static int _globalId;
private Stack<PowerShell> _runningPowerShells;
private PowerShell _baseRunningPowerShell;
private object _syncObject;
#endregion
#region constructor
/// <summary>
/// Explicit default constructor
/// </summary>
internal Runspace()
{
// Create the default Runspace Id and friendly name.
Id = System.Threading.Interlocked.Increment(ref _globalId);
Name = "Runspace" + Id.ToString(System.Globalization.NumberFormatInfo.InvariantInfo);
_runningPowerShells = new Stack<PowerShell>();
_syncObject = new object();
// Keep track of this runspace until it is disposed.
lock (s_syncObject)
{
s_runspaceDictionary.Add(Id, new WeakReference<Runspace>(this));
}
}
/// <summary>
/// Static Constructor
/// </summary>
static Runspace()
{
s_syncObject = new object();
s_runspaceDictionary = new SortedDictionary<int, WeakReference<Runspace>>();
_globalId = 0;
}
#endregion constructor
#region properties
/// <summary>
/// Used to store Runspace reference on per thread basis. Used by
/// various PowerShell engine features to get access to TypeTable
/// etc.
/// </summary>
[ThreadStatic]
private static Runspace ThreadSpecificDefaultRunspace = null;
/// <summary>
/// Gets and sets the default Runspace used to evaluate scripts
/// </summary>
/// <remarks>The Runspace used to set this property should not be shared between different threads.</remarks>
public static Runspace DefaultRunspace
{
get
{
return ThreadSpecificDefaultRunspace;
}
set
{
if ( value == null || ! value.RunspaceIsRemote )
{
ThreadSpecificDefaultRunspace = value;
}
else
{
throw new InvalidOperationException(RunspaceStrings.RunspaceNotLocal);
}
}
}
/// <summary>
/// Returns true if Runspace.DefaultRunspace can be used to
/// create an instance of the PowerShell class with
/// 'UseCurrentRunspace = true'.
/// </summary>
public static bool CanUseDefaultRunspace
{
// can use default runspace in a thread safe manner only if
// 1. we have a default runspace
// 2. we recognize the type of current runspace and current pipeline
// 3. the pipeline executes on the same thread as this method
// we don't return "true" for
// 1. we have a default runspace
// 2. no currently executing pipeline
// to avoid a race condition where a pipeline is started
// after this property getter did all the checks
get
{
RunspaceBase runspace = Runspace.DefaultRunspace as RunspaceBase;
if (runspace != null)
{
Pipeline currentPipeline = runspace.GetCurrentlyRunningPipeline();
LocalPipeline localPipeline = currentPipeline as LocalPipeline;
if ((localPipeline != null) && (localPipeline.NestedPipelineExecutionThread != null))
{
return
(localPipeline.NestedPipelineExecutionThread.ManagedThreadId
== Threading.Thread.CurrentThread.ManagedThreadId);
}
}
return false;
}
}
#if !CORECLR // No ApartmentState In CoreCLR
internal const ApartmentState DefaultApartmentState = ApartmentState.Unknown;
/// <summary>
/// ApartmentState of the thread used to execute commands within this Runspace
/// </summary>
/// <remarks>
/// Any updates to the value of this property must be done before the Runspace is opened
/// </remarks>
/// <exception cref="InvalidRunspaceStateException">
/// An attempt to change this property was made after opening the Runspace
/// </exception>
public ApartmentState ApartmentState
{
get
{
return this.apartmentState;
}
set
{
if (this.RunspaceStateInfo.State != RunspaceState.BeforeOpen)
{
throw new InvalidRunspaceStateException(StringUtil.Format(RunspaceStrings.ChangePropertyAfterOpen));
}
this.apartmentState = value;
}
}
private ApartmentState apartmentState = Runspace.DefaultApartmentState;
#endif
/// <summary>
/// This property determines whether a new thread is create for each invocation
/// </summary>
/// <remarks>
/// Any updates to the value of this property must be done before the Runspace is opened
/// </remarks>
/// <exception cref="InvalidRunspaceStateException">
/// An attempt to change this property was made after opening the Runspace
/// </exception>
/// <exception cref="InvalidOperationException">
/// The thread options cannot be changed to the requested value
/// </exception>
public abstract PSThreadOptions ThreadOptions
{
get;
set;
}
/// <summary>
/// Return version of this runspace
/// </summary>
public abstract Version Version
{
get;
}
/// <summary>
/// Return whether the Runspace is Remote
/// We can determine this by whether the runspace is an implementation of LocalRunspace
/// or infer it from whether the ConnectionInfo property is null
/// If it happens to be an instance of a LocalRunspace, but has a non-null ConnectionInfo
/// we declare it to be remote
/// </summary>
public bool RunspaceIsRemote
{
get
{
return ! ( this is LocalRunspace || ConnectionInfo == null);
}
}
/// <summary>
/// Retrieve information about current state of the runspace
/// </summary>
public abstract RunspaceStateInfo RunspaceStateInfo
{
get;
}
/// <summary>
/// Gets the current availability of the Runspace
/// </summary>
public abstract RunspaceAvailability RunspaceAvailability
{
get;
protected set;
}
private Guid _instanceId = Guid.NewGuid();
/// <summary>
/// RunspaceConfiguration information for this runspace.
/// </summary>
public abstract RunspaceConfiguration RunspaceConfiguration
{
get;
}
/// <summary>
/// InitialSessionState information for this runspace.
/// </summary>
public abstract InitialSessionState InitialSessionState
{
get;
}
/// <summary>
/// Get unqiue id for this instance of runspace. It is primarily used
/// for logging purposes
/// </summary>
public Guid InstanceId
{
get
{
return _instanceId;
}
// This id is also used to identify proxy and remote runspace objects.
// We need to set this when reconstructing a remote runspace to connect
// to an existing remote runspace.
internal set
{
_instanceId = value;
}
}
/// <summary>
/// Gets execution context.
/// </summary>
/// <exception cref="InvalidRunspaceStateException">Runspace is not opened.
/// </exception>
internal System.Management.Automation.ExecutionContext ExecutionContext
{
get
{
return GetExecutionContext;
}
}
bool _skipUserProfile = false;
/// <summary>
/// Skip user profile on engine initialization
/// </summary>
internal bool SkipUserProfile
{
get
{
return _skipUserProfile;
}
set
{
_skipUserProfile = value;
}
}
/// <summary>
/// Connection information for remote Runspaces, null for local Runspaces
/// </summary>
public abstract RunspaceConnectionInfo ConnectionInfo {get;}
/// <summary>
/// ConnectionInfo originally supplied by the user
/// </summary>
public abstract RunspaceConnectionInfo OriginalConnectionInfo { get; }
/// <summary>
/// Manager for JobSourceAdapters registered in this runspace.
/// </summary>
public abstract JobManager JobManager { get; }
/// <summary>
/// DisconnectedOn property applies to remote runspaces that have
/// been disconnected.
/// </summary>
public DateTime? DisconnectedOn
{
get;
internal set;
}
/// <summary>
/// ExpiresOn property applies to remote runspaces that have been
/// disconnected.
/// </summary>
public DateTime? ExpiresOn
{
get;
internal set;
}
/// <summary>
/// Gets and sets a friendly name for the Runspace.
/// </summary>
public string Name
{
get;
set;
}
/// <summary>
/// Gets the Runspace Id.
/// </summary>
public int Id
{
get;
private set;
}
/// <summary>
/// Returns protocol version that the remote server uses for PS remoting
/// </summary>
internal Version GetRemoteProtocolVersion()
{
Version remoteProtocolVersionDeclaredByServer;
bool isServerDeclarationValid = PSPrimitiveDictionary.TryPathGet(
this.GetApplicationPrivateData(),
out remoteProtocolVersionDeclaredByServer,
PSVersionInfo.PSVersionTableName,
PSVersionInfo.PSRemotingProtocolVersionName);
if (isServerDeclarationValid)
{
return remoteProtocolVersionDeclaredByServer;
}
else
{
return RemotingConstants.ProtocolVersion;
}
}
/// <summary>
/// Engine activity id (for ETW tracing)
/// </summary>
internal Guid EngineActivityId
{
get { return _engineActivityId; }
set { _engineActivityId = value; }
}
private Guid _engineActivityId = Guid.Empty;
/// <summary>
/// Returns a read only runspace dictionary.
/// </summary>
internal static ReadOnlyDictionary<int, WeakReference<Runspace>> RunspaceDictionary
{
get
{
lock (s_syncObject)
{
return new ReadOnlyDictionary<int,WeakReference<Runspace>>(new Dictionary<int, WeakReference<Runspace>>(s_runspaceDictionary));
}
}
}
private static SortedDictionary<int, WeakReference<Runspace>> s_runspaceDictionary;
private static object s_syncObject;
/// <summary>
/// Returns a read only list of runspaces.
/// </summary>
internal static IReadOnlyList<Runspace> RunspaceList
{
get
{
List<Runspace> runspaceList = new List<Runspace>();
lock (s_syncObject)
{
foreach (var item in s_runspaceDictionary.Values)
{
Runspace runspace;
if (item.TryGetTarget(out runspace))
{
runspaceList.Add(runspace);
}
}
}
return new ReadOnlyCollection<Runspace>(runspaceList);
}
}
#endregion properties
#region events
/// <summary>
/// Event raised when RunspaceState changes.
/// </summary>
public abstract event EventHandler<RunspaceStateEventArgs> StateChanged;
/// <summary>
/// Event raised when the availability of the Runspace changes.
/// </summary>
public abstract event EventHandler<RunspaceAvailabilityEventArgs> AvailabilityChanged;
/// <summary>
/// Returns true if there are any subscribers to the AvailabilityChanged event
/// </summary>
internal abstract bool HasAvailabilityChangedSubscribers
{
get;
}
/// <summary>
/// Raises the AvailabilityChanged event
/// </summary>
protected abstract void OnAvailabilityChanged(RunspaceAvailabilityEventArgs e);
/// <summary>
/// Used to raise the AvailabilityChanged event when the state of the currently executing pipeline changes
/// </summary>
/// <remarks>
/// The possible pipeline states are
/// NotStarted
/// Running
/// Disconnected
/// Stopping
/// Stopped
/// Completed
/// Failed
/// </remarks>
internal void UpdateRunspaceAvailability(PipelineState pipelineState, bool raiseEvent, Guid? cmdInstanceId = null)
{
RunspaceAvailability oldAvailability = this.RunspaceAvailability;
switch (oldAvailability)
{
// Because of disconnect/connect support runspace availability can now transition
// in and out of "None" state.
case RunspaceAvailability.None:
switch (pipelineState)
{
case PipelineState.Running:
this.RunspaceAvailability = RunspaceAvailability.Busy;
break;
// Otherwise no change.
}
break;
case RunspaceAvailability.Available:
switch (pipelineState)
{
case PipelineState.Running:
this.RunspaceAvailability = RunspaceAvailability.Busy;
break;
case PipelineState.Disconnected:
this.RunspaceAvailability = Runspaces.RunspaceAvailability.None;
break;
}
break;
case RunspaceAvailability.AvailableForNestedCommand:
switch (pipelineState)
{
case PipelineState.Running:
this.RunspaceAvailability = RunspaceAvailability.Busy;
break;
case PipelineState.Completed: // a nested pipeline caused the host to exit nested prompt
this.RunspaceAvailability = (this.InNestedPrompt || (this._runningPowerShells.Count > 1)) ?
RunspaceAvailability.AvailableForNestedCommand : RunspaceAvailability.Available;
break;
default:
break; // no change in the availability
}
break;
case RunspaceAvailability.Busy:
case RunspaceAvailability.RemoteDebug:
switch (pipelineState)
{
case PipelineState.Disconnected:
if (oldAvailability == Runspaces.RunspaceAvailability.RemoteDebug)
{
this.RunspaceAvailability = RunspaceAvailability.RemoteDebug;
}
else
{
this.RunspaceAvailability = RunspaceAvailability.None;
}
break;
case PipelineState.Stopping:
break; // no change in the availability
case PipelineState.Completed:
case PipelineState.Stopped:
case PipelineState.Failed:
if (this.InNestedPrompt || !(this is RemoteRunspace) && this.Debugger.InBreakpoint)
{
this.RunspaceAvailability = RunspaceAvailability.AvailableForNestedCommand;
}
else
{
RemoteRunspace remoteRunspace = this as RemoteRunspace;
RemoteDebugger remoteDebugger = (remoteRunspace != null) ? remoteRunspace.Debugger as RemoteDebugger : null;
Internal.ConnectCommandInfo remoteCommand = (remoteRunspace != null) ? remoteRunspace.RemoteCommand : null;
if (((pipelineState == PipelineState.Completed) || (pipelineState == PipelineState.Failed) ||
((pipelineState == PipelineState.Stopped) && (this.RunspaceStateInfo.State == RunspaceState.Opened)))
&& (remoteCommand != null) && (cmdInstanceId != null) && (remoteCommand.CommandId == cmdInstanceId))
{
// Completed, Failed, and Stopped with Runspace.Opened states are command finish states and we know
// that the command is finished on the server.
// Setting ConnectCommands to null indicates that the runspace is free to run other
// commands.
remoteRunspace.RunspacePool.RemoteRunspacePoolInternal.ConnectCommands = null;
remoteCommand = null;
if ((remoteDebugger != null) && (pipelineState == PipelineState.Stopped))
{
// Notify remote debugger of a stop in case the stop occurred while command was in debug stop.
remoteDebugger.OnCommandStopped();
}
}
Pipeline currentPipeline = this.GetCurrentlyRunningPipeline();
RemotePipeline remotePipeline = currentPipeline as RemotePipeline;
Guid? pipeLineCmdInstance = (remotePipeline != null && remotePipeline.PowerShell != null) ? remotePipeline.PowerShell.InstanceId : (Guid?)null;
if (currentPipeline == null)
{
// A runspace is available:
// - if there is no currently running pipeline
// and for remote runspaces:
// - if there is no remote command associated with it.
// - if the remote runspace pool is marked as available for connection.
if (remoteCommand == null)
{
if (remoteRunspace != null)
{
if ((remoteDebugger != null) && (pipelineState == PipelineState.Stopped))
{
// Notify remote debugger of a stop in case the stop occurred while command was in debug stop.
remoteDebugger.OnCommandStopped();
}
this.RunspaceAvailability =
remoteRunspace.RunspacePool.RemoteRunspacePoolInternal.AvailableForConnection ?
RunspaceAvailability.Available : Runspaces.RunspaceAvailability.Busy;
}
else
{
this.RunspaceAvailability = RunspaceAvailability.Available;
}
}
}
else if ((cmdInstanceId != null) && (pipeLineCmdInstance != null) && (cmdInstanceId == pipeLineCmdInstance))
{
if ((remoteDebugger != null) && (pipelineState == PipelineState.Stopped))
{
// Notify remote debugger of a stop in case the stop occurred while command was in debug stop.
remoteDebugger.OnCommandStopped();
}
this.RunspaceAvailability = RunspaceAvailability.Available;
}
else // a nested pipeline completed, but the parent pipeline is still running
{
if (oldAvailability == Runspaces.RunspaceAvailability.RemoteDebug)
{
this.RunspaceAvailability = Runspaces.RunspaceAvailability.RemoteDebug;
}
else if ((currentPipeline.PipelineStateInfo.State == PipelineState.Running) || (this._runningPowerShells.Count > 1))
{
// Either the current pipeline is running or there are other nested commands to run in the Runspace.
this.RunspaceAvailability = RunspaceAvailability.Busy;
}
else
{
this.RunspaceAvailability = RunspaceAvailability.Available;
}
}
}
break;
case PipelineState.Running: // this can happen if a nested pipeline is created without entering a nested prompt
break; // no change in the availability
default:
break; // no change in the availability
}
break;
default:
Diagnostics.Assert(false, "Invalid RunspaceAvailability");
break;
}
if (raiseEvent && this.RunspaceAvailability != oldAvailability)
{
OnAvailabilityChanged(new RunspaceAvailabilityEventArgs(this.RunspaceAvailability));
}
}
/// <summary>
/// Used to update the runspace availability when the state of the currently executing PowerShell instance changes
/// </summary>
/// <remarks>
/// The possible invocation states are
/// NotStarted
/// Running
/// Stopping
/// Stopped
/// Completed
/// Failed
/// </remarks>
internal void UpdateRunspaceAvailability(PSInvocationState invocationState, bool raiseEvent, Guid cmdInstanceId)
{
switch (invocationState)
{
case PSInvocationState.NotStarted:
UpdateRunspaceAvailability(PipelineState.NotStarted, raiseEvent, cmdInstanceId);
break;
case PSInvocationState.Running:
UpdateRunspaceAvailability(PipelineState.Running, raiseEvent, cmdInstanceId);
break;
case PSInvocationState.Completed:
UpdateRunspaceAvailability(PipelineState.Completed, raiseEvent, cmdInstanceId);
break;
case PSInvocationState.Failed:
UpdateRunspaceAvailability(PipelineState.Failed, raiseEvent, cmdInstanceId);
break;
case PSInvocationState.Stopping:
UpdateRunspaceAvailability(PipelineState.Stopping, raiseEvent, cmdInstanceId);
break;
case PSInvocationState.Stopped:
UpdateRunspaceAvailability(PipelineState.Stopped, raiseEvent, cmdInstanceId);
break;
case PSInvocationState.Disconnected:
UpdateRunspaceAvailability(PipelineState.Disconnected, raiseEvent, cmdInstanceId);
break;
default:
Diagnostics.Assert(false, "Invalid PSInvocationState");
break;
}
}
/// <summary>
/// Used to update the runspace availability event when the state of the runspace changes
/// </summary>
/// <remarks>
/// The possible runspace states are:
/// BeforeOpen
/// Opening
/// Opened
/// Closed
/// Closing
/// Broken
/// </remarks>
protected void UpdateRunspaceAvailability(RunspaceState runspaceState, bool raiseEvent)
{
RunspaceAvailability oldAvailability = this.RunspaceAvailability;
RemoteRunspace remoteRunspace = this as RemoteRunspace;
Internal.ConnectCommandInfo remoteCommand = null;
bool remoteDebug = false;
if (remoteRunspace != null)
{
remoteCommand = remoteRunspace.RemoteCommand;
RemoteDebugger remoteDebugger = remoteRunspace.Debugger as RemoteDebugger;
remoteDebug = (remoteDebugger != null) && remoteDebugger.IsRemoteDebug;
}
switch (oldAvailability)
{
case RunspaceAvailability.None:
switch (runspaceState)
{
case RunspaceState.Opened:
if (remoteDebug)
{
this.RunspaceAvailability = Runspaces.RunspaceAvailability.RemoteDebug;
}
else
{
this.RunspaceAvailability = (remoteCommand == null && GetCurrentlyRunningPipeline() == null) ?
RunspaceAvailability.Available : RunspaceAvailability.Busy;
}
break;
default:
break; // no change in the availability
}
break;
case RunspaceAvailability.Available:
case RunspaceAvailability.AvailableForNestedCommand:
case RunspaceAvailability.RemoteDebug:
case RunspaceAvailability.Busy:
switch (runspaceState)
{
case RunspaceState.Closing:
case RunspaceState.Closed:
case RunspaceState.Broken:
case RunspaceState.Disconnected:
this.RunspaceAvailability = RunspaceAvailability.None;
break;
default:
break; // no change in the availability
}
break;
default:
Diagnostics.Assert(false, "Invalid RunspaceAvailability");
break;
}
if (raiseEvent && this.RunspaceAvailability != oldAvailability)
{
OnAvailabilityChanged(new RunspaceAvailabilityEventArgs(this.RunspaceAvailability));
}
}
/// <summary>
/// Used to update the runspace availability from Enter/ExitNestedPrompt and the debugger
/// </summary>
internal void UpdateRunspaceAvailability(RunspaceAvailability availability, bool raiseEvent)
{
RunspaceAvailability oldAvailability = this.RunspaceAvailability;
this.RunspaceAvailability = availability;
if (raiseEvent && this.RunspaceAvailability != oldAvailability)
{
OnAvailabilityChanged(new RunspaceAvailabilityEventArgs(this.RunspaceAvailability));
}
}
/// <summary>
/// Raises the AvailabilityChanged event
/// </summary>
internal void RaiseAvailabilityChangedEvent(RunspaceAvailability availability)
{
OnAvailabilityChanged(new RunspaceAvailabilityEventArgs(availability));
}
#endregion events
#region Public static methods
/// <summary>
/// Queries the server for disconnected runspaces and creates an array of runspace
/// objects associated with each disconnected runspace on the server. Each
/// runspace object in the returned array is in the Disconnected state and can be
/// connected to the server by calling the Connect() method on the runspace.
/// </summary>
/// <param name="connectionInfo">Connection object for the target server.</param>
/// <returns>Array of Runspace objects each in the Disconnected state.</returns>
[SuppressMessage("Microsoft.Naming", "CA1704:IdentifiersShouldBeSpelledCorrectly", MessageId = "Runspaces")]
public static Runspace[] GetRunspaces(RunspaceConnectionInfo connectionInfo)
{
return GetRunspaces(connectionInfo, null, null);
}
/// <summary>
/// Queries the server for disconnected runspaces and creates an array of runspace
/// objects associated with each disconnected runspace on the server. Each
/// runspace object in the returned array is in the Disconnected state and can be
/// connected to the server by calling the Connect() method on the runspace.
/// </summary>
/// <param name="connectionInfo">Connection object for the target server.</param>
/// <param name="host">Client host object.</param>
/// <returns>Array of Runspace objects each in the Disconnected state.</returns>
[SuppressMessage("Microsoft.Naming", "CA1704:IdentifiersShouldBeSpelledCorrectly", MessageId = "Runspaces")]
public static Runspace[] GetRunspaces(RunspaceConnectionInfo connectionInfo, PSHost host)
{
return GetRunspaces(connectionInfo, host, null);
}
/// <summary>
/// Queries the server for disconnected runspaces and creates an array of runspace
/// objects associated with each disconnected runspace on the server. Each
/// runspace object in the returned array is in the Disconnected state and can be
/// connected to the server by calling the Connect() method on the runspace.
/// </summary>
/// <param name="connectionInfo">Connection object for the target server.</param>
/// <param name="host">Client host object.</param>
/// <param name="typeTable">TypeTable object.</param>
/// <returns>Array of Runspace objects each in the Disconnected state.</returns>
[SuppressMessage("Microsoft.Naming", "CA1704:IdentifiersShouldBeSpelledCorrectly", MessageId = "Runspaces")]
public static Runspace[] GetRunspaces(RunspaceConnectionInfo connectionInfo, PSHost host, TypeTable typeTable)
{
return RemoteRunspace.GetRemoteRunspaces(connectionInfo, host, typeTable);
}
/// <summary>
/// Returns a single disconnected Runspace object targeted to the remote computer and remote
/// session as specified by the connection, session Id, and command Id parameters.
/// </summary>
/// <param name="connectionInfo">Connection object for the target server.</param>
/// <param name="sessionId">Id of a disconnected remote session on the target server.</param>
/// <param name="commandId">Optional Id of a disconnected command running in the disconnected remote session on the target server.</param>
/// <param name="host">Optional client host object.</param>
/// <param name="typeTable">Optional TypeTable object.</param>
/// <returns>Disconnected runspace corresponding to the provided session Id.</returns>
public static Runspace GetRunspace(RunspaceConnectionInfo connectionInfo, Guid sessionId, Guid? commandId, PSHost host, TypeTable typeTable)
{
return RemoteRunspace.GetRemoteRunspace(connectionInfo, sessionId, commandId, host, typeTable);
}
#endregion
#region public Disconnect-Connect methods
/// <summary>
/// Disconnects the runspace synchronously.
/// </summary>
/// <remarks>
/// Disconnects the remote runspace and any running command from the server
/// machine. Any data generated by the running command on the server is
/// cached on the server machine. This runspace object goes to the disconnected
/// state. This object can be reconnected to the server by calling the
/// Connect() method.
/// If the remote runspace on the server remains disconnected for the IdleTimeout
/// value (as defined in the WSManConnectionInfo object) then it is closed and
/// torn down on the server.
/// </remarks>
/// <exception cref="InvalidRunspaceStateException">
/// RunspaceState is not Opened.
/// </exception>
public abstract void Disconnect();
/// <summary>
/// Disconnects the runspace asynchronously.
/// </summary>
/// <remarks>
/// Disconnects the remote runspace and any running command from the server
/// machine. Any data generated by the running command on the server is
/// cached on the server machine. This runspace object goes to the disconnected
/// state. This object can be reconnected to the server by calling the
/// Connect() method.
/// If the remote runspace on the server remains disconnected for the IdleTimeout
/// value (as defined in the WSManConnectionInfo object) then it is closed and
/// torn down on the server.
/// </remarks>
/// <exception cref="InvalidRunspaceStateException">
/// RunspaceState is not Opened.
/// </exception>
public abstract void DisconnectAsync();
/// <summary>
/// Connects the runspace to its remote counterpart synchronously.
/// </summary>
/// <remarks>
/// Connects the runspace object to its corresponding runspace on the target
/// server machine. The target server machine is identified by the connection
/// object passed in during construction. The remote runspace is identified
/// by the internal runspace Guid value.
/// </remarks>
/// <exception cref="InvalidRunspaceStateException">
/// RunspaceState is not Disconnected.
/// </exception>
public abstract void Connect();
/// <summary>
/// Connects a runspace to its remote counterpart asynchronously.
/// </summary>
/// <remarks>
/// Connects the runspace object to its corresponding runspace on the target
/// server machine. The target server machine is identified by the connection
/// object passed in during construction. The remote runspace is identified
/// by the internal runspace Guid value.
/// </remarks>
/// <exception cref="InvalidRunspaceStateException">
/// RunspaceState is not Disconnected.
/// </exception>
public abstract void ConnectAsync();
/// <summary>
/// Creates a PipeLine object in the disconnected state for the currently disconnected
/// remote running command associated with this runspace.
/// </summary>
/// <returns>Pipeline object in disconnected state.</returns>
public abstract Pipeline CreateDisconnectedPipeline();
/// <summary>
/// Creates a PowerShell object in the disconnected state for the currently disconnected
/// remote running command associated with this runspace.
/// </summary>
/// <returns>PowerShell object in disconnected state.</returns>
public abstract PowerShell CreateDisconnectedPowerShell();
/// <summary>
/// Returns Runspace capabilities.
/// </summary>
/// <returns>RunspaceCapability</returns>
public abstract RunspaceCapability GetCapabilities();
#endregion
#region methods
/// <summary>
/// Opens the runspace synchronously. Runspace must be opened before it can be used.
/// </summary>
/// <exception cref="InvalidRunspaceStateException">
/// RunspaceState is not BeforeOpen
/// </exception>
public abstract void Open();
/// <summary>
/// Open the runspace Asynchronously.
/// </summary>
/// <exception cref="InvalidRunspaceStateException">
/// RunspaceState is not BeforeOpen
/// </exception>
public abstract void OpenAsync();
/// <summary>
/// Close the runspace synchronously.
/// </summary>
/// <remarks>
/// Attempts to execute pipelines after a call to close will fail.
/// </remarks>
/// <exception cref="InvalidRunspaceStateException">
/// RunspaceState is BeforeOpen or Opening
/// </exception>
public abstract void Close();
/// <summary>
/// Close the runspace Asynchronously.
/// </summary>
/// <remarks>
/// Attempts to execute pipelines after a call to
/// close will fail.
/// </remarks>
/// <exception cref="InvalidRunspaceStateException">
/// RunspaceState is BeforeOpen or Opening
/// </exception>
public abstract void CloseAsync();
/// <summary>
/// Create an empty pipeline
/// </summary>
/// <returns>An empty pipeline</returns>
public abstract Pipeline CreatePipeline();
/// <summary>
/// Creates a pipeline for specified command string
/// </summary>
/// <param name="command">A valid command string</param>
/// <returns>
/// A pipline pre-filled with a <see cref="Command"/> object for specified command parameter.
/// </returns>
/// <exception cref="ArgumentNullException">
/// command is null
/// </exception>
public abstract Pipeline CreatePipeline(string command);
/// <summary>
/// Create a pipeline from a command string.
/// </summary>
/// <param name="command">A valid command string</param>
/// <param name="addToHistory">if true command is added to history</param>
/// <returns>
/// A pipline pre-filled with a <see cref="Command"/> object for specified command parameter.
/// </returns>
/// <exception cref="ArgumentNullException">
/// command is null
/// </exception>
public abstract Pipeline CreatePipeline(string command, bool addToHistory);
/// <summary>
/// Creates a nested pipeline.
/// </summary>
/// <remarks>
/// Nested pipelines are needed for nested prompt scenario. Nested
/// prompt requires that we execute new pipelines( child pipelines)
/// while current pipeline (lets call it parent pipeline) is blocked.
/// </remarks>
public abstract Pipeline CreateNestedPipeline();
/// <summary>
/// Creates a nested pipeline.
/// </summary>
/// <param name="command">A valid command string</param>
/// <param name="addToHistory">if true command is added to history</param>
/// <returns>
/// A pipline pre-filled with Command specified in commandString.
/// </returns>
/// <exception cref="ArgumentNullException">
/// command is null
/// </exception>
public abstract Pipeline CreateNestedPipeline(string command, bool addToHistory);
/// <summary>
/// Returns the currently executing pipeline, or null if no pipeline is executing
/// </summary>
internal abstract Pipeline GetCurrentlyRunningPipeline();
/// <summary>
/// Private data to be used by applications built on top of PowerShell.
///
/// Local runspace is created with application private data set to an empty <see cref="PSPrimitiveDictionary"/>.
///
/// Remote runspace gets its application private data from the server (set when creating a remote runspace pool)
/// Calling this method on a remote runspace will block until the data is received from the server.
/// The server will send application private data before reaching <see cref="RunspacePoolState.Opened"/> state.
///
/// Runspaces that are part of a <see cref="RunspacePool"/> inherit application private data from the pool.
/// </summary>
public abstract PSPrimitiveDictionary GetApplicationPrivateData();
/// <summary>
/// A method that runspace pools can use to propagate application private data into runspaces
/// </summary>
/// <param name="applicationPrivateData"></param>
internal abstract void SetApplicationPrivateData(PSPrimitiveDictionary applicationPrivateData);
/// <summary>
/// Push a running PowerShell onto the stack.
/// </summary>
/// <param name="ps">PowerShell</param>
internal void PushRunningPowerShell(PowerShell ps)
{
Dbg.Assert(ps != null, "Caller should not pass in null reference.");
lock (_syncObject)
{
_runningPowerShells.Push(ps);
if (_runningPowerShells.Count == 1)
{
_baseRunningPowerShell = ps;
}
}
}
/// <summary>
/// Pop the currently running PowerShell from stack.
/// </summary>
/// <returns>PowerShell</returns>
internal PowerShell PopRunningPowerShell()
{
lock (_syncObject)
{
int count = _runningPowerShells.Count;
if (count > 0)
{
if (count == 1) { _baseRunningPowerShell = null; }
return _runningPowerShells.Pop();
}
}
return null;
}
internal PowerShell GetCurrentBasePowerShell()
{
return _baseRunningPowerShell;
}
#endregion methods
#region SessionStateProxy
/// <summary>
/// Gets session state proxy
/// </summary>
public SessionStateProxy SessionStateProxy
{
get
{
return GetSessionStateProxy();
}
}
internal abstract SessionStateProxy GetSessionStateProxy();
#endregion SessionStateProxy
#region IDisposable Members
/// <summary>
/// Disposes this runspace instance. Dispose will close the runspace if not closed already.
/// </summary>
public void Dispose()
{
Dispose(true);
GC.SuppressFinalize(this);
}
/// <summary>
/// Protected dispose which can be overridden by derived classes.
/// </summary>
/// <param name="disposing"></param>
protected virtual void Dispose(bool disposing)
{
lock (s_syncObject)
{
s_runspaceDictionary.Remove(Id);
}
}
#endregion IDisposable Members
/// <summary>
/// Gets the execution context
/// </summary>
internal abstract System.Management.Automation.ExecutionContext GetExecutionContext
{
get;
}
/// <summary>
/// Returns true if the internal host is in a nested prompt
/// </summary>
internal abstract bool InNestedPrompt
{
get;
}
/// <summary>
/// Gets the debugger
/// </summary>
public virtual Debugger Debugger
{
get
{
var context = GetExecutionContext;
return (context != null) ? context.Debugger : null;
}
}
/// <summary>
/// InternalDebugger
/// </summary>
internal Debugger InternalDebugger
{
get;
set;
}
/// <summary>
/// Gets the event manager
/// </summary>
public abstract PSEventManager Events
{
get;
}
#if !CORECLR // Transaction Not Supported On CSS
/// <summary>
/// Sets the base transaction for the runspace; any transactions created on this runspace will be nested to this instance
/// </summary>
///<param name="transaction">The base transaction</param>
///<remarks>This overload uses RollbackSeverity.Error; i.e. the transaction will be rolled back automatically on a non-terminating error or worse</remarks>
public void SetBaseTransaction(System.Transactions.CommittableTransaction transaction)
{
this.ExecutionContext.TransactionManager.SetBaseTransaction(transaction, RollbackSeverity.Error);
}
/// <summary>
/// Sets the base transaction for the runspace; any transactions created on this runspace will be nested to this instance
/// </summary>
///<param name="transaction">The base transaction</param>
///<param name="severity">The severity of error that causes PowerShell to automatically rollback the transaction</param>
///
public void SetBaseTransaction(System.Transactions.CommittableTransaction transaction, RollbackSeverity severity)
{
this.ExecutionContext.TransactionManager.SetBaseTransaction(transaction, severity);
}
/// <summary>
/// Clears the transaction set by SetBaseTransaction()
/// </summary>
///
public void ClearBaseTransaction()
{
this.ExecutionContext.TransactionManager.ClearBaseTransaction();
}
#endif
/// <summary>
/// Resets the variable table for the runspace to the default state.
/// </summary>
public virtual void ResetRunspaceState()
{
throw new NotImplementedException("ResetRunspaceState");
}
// Used for pipeline id generation.
private long _pipelineIdSeed;
//Generate pipeline id unique to this runspace
internal long GeneratePipelineId()
{
return System.Threading.Interlocked.Increment(ref _pipelineIdSeed);
}
}
/// <summary>
/// This class provides subset of functionality provided by
/// session state.
/// </summary>
public class SessionStateProxy
{
internal SessionStateProxy()
{
}
RunspaceBase _runspace;
internal SessionStateProxy(RunspaceBase runspace)
{
Dbg.Assert(runspace != null, "Caller should validate the parameter");
_runspace = runspace;
}
/// <summary>
/// Set a variable in session state.
/// </summary>
///
/// <param name="name">
/// The name of the item to set.
/// </param>
///
/// <param name="value">
/// The new value of the item being set.
/// </param>
///
/// <exception cref="ArgumentNullException">
/// name is null
/// </exception>
///
/// <exception cref="InvalidRunspaceStateException">
/// Runspace is not open.
/// </exception>
///
/// <exception cref="InvalidOperationException">
/// Another SessionStateProxy call or another pipeline is in progress.
/// </exception>
public virtual void SetVariable(string name, object value)
{
if (name == null)
{
throw PSTraceSource.NewArgumentNullException("name");
}
_runspace.SetVariable(name, value);
}
/// <summary>
/// Get a variable out of session state.
/// </summary>
///
/// <param name="name">
/// name of variable to look up
/// </param>
///
/// <returns>
/// The value of the specified variable.
/// </returns>
///
/// <exception cref="ArgumentNullException">
/// name is null
/// </exception>
///
/// <exception cref="InvalidRunspaceStateException">
/// Runspace is not open.
/// </exception>
///
/// <exception cref="InvalidOperationException">
/// Another SessionStateProxy call or another pipeline is in progress.
/// </exception>
public virtual object GetVariable(string name)
{
if (name == null)
{
throw PSTraceSource.NewArgumentNullException("name");
}
if (name.Equals(string.Empty))
{
return null;
}
return _runspace.GetVariable(name);
}
/// <summary>
/// Get the list of applications out of session state.
/// </summary>
///
/// <exception cref="InvalidRunspaceStateException">
/// Runspace is not open.
/// </exception>
///
/// <exception cref="InvalidOperationException">
/// Another SessionStateProxy call or another pipeline is in progress.
/// </exception>
public virtual List<string> Applications
{
get
{
return _runspace.Applications;
}
}
/// <summary>
/// Get the list of scripts out of session state.
/// </summary>
///
/// <exception cref="InvalidRunspaceStateException">
/// Runspace is not open.
/// </exception>
///
/// <exception cref="InvalidOperationException">
/// Another SessionStateProxy call or another pipeline is in progress.
/// </exception>
public virtual List<string> Scripts
{
get
{
return _runspace.Scripts;
}
}
/// <summary>
/// Get the APIs to access drives out of session state
/// </summary>
///
/// <exception cref="InvalidRunspaceStateException">
/// Runspace is not open.
/// </exception>
///
/// <exception cref="InvalidOperationException">
/// Another SessionStateProxy call or another pipeline is in progress.
/// </exception>
public virtual DriveManagementIntrinsics Drive
{
get { return _runspace.Drive; }
}
/// <summary>
/// Get/Set the language mode out of session state.
/// </summary>
///
/// <exception cref="InvalidRunspaceStateException">
/// Runspace is not open.
/// </exception>
///
/// <exception cref="InvalidOperationException">
/// Another SessionStateProxy call or another pipeline is in progress.
/// </exception>
public virtual PSLanguageMode LanguageMode
{
get { return _runspace.LanguageMode; }
set { _runspace.LanguageMode = value; }
}
/// <summary>
/// Get the module info out of session state.
/// </summary>
///
/// <exception cref="InvalidRunspaceStateException">
/// Runspace is not open.
/// </exception>
///
/// <exception cref="InvalidOperationException">
/// Another SessionStateProxy call or another pipeline is in progress.
/// </exception>
[SuppressMessage("Microsoft.Naming", "CA1716:IdentifiersShouldNotMatchKeywords", Justification="Shipped this way in V2 before becoming virtual.")]
public virtual PSModuleInfo Module
{
get { return _runspace.Module; }
}
/// <summary>
/// Get the APIs to access paths and locations out of session state.
/// </summary>
///
/// <exception cref="InvalidRunspaceStateException">
/// Runspace is not open.
/// </exception>
///
/// <exception cref="InvalidOperationException">
/// Another SessionStateProxy call or another pipeline is in progress.
/// </exception>
public virtual PathIntrinsics Path
{
get { return _runspace.PathIntrinsics; }
}
/// <summary>
/// Get the APIs to access a provider out of session state.
/// </summary>
///
/// <exception cref="InvalidRunspaceStateException">
/// Runspace is not open.
/// </exception>
///
/// <exception cref="InvalidOperationException">
/// Another SessionStateProxy call or another pipeline is in progress.
/// </exception>
public virtual CmdletProviderManagementIntrinsics Provider
{
get { return _runspace.Provider; }
}
/// <summary>
/// Get the APIs to access variables out of session state.
/// </summary>
///
/// <exception cref="InvalidRunspaceStateException">
/// Runspace is not open.
/// </exception>
///
/// <exception cref="InvalidOperationException">
/// Another SessionStateProxy call or another pipeline is in progress.
/// </exception>
public virtual PSVariableIntrinsics PSVariable
{
get { return _runspace.PSVariable; }
}
/// <summary>
/// Get the APIs to build script blocks and execute script out of session state.
/// </summary>
///
/// <exception cref="InvalidRunspaceStateException">
/// Runspace is not open.
/// </exception>
///
/// <exception cref="InvalidOperationException">
/// Another SessionStateProxy call or another pipeline is in progress.
/// </exception>
public virtual CommandInvocationIntrinsics InvokeCommand
{
get { return _runspace.InvokeCommand; }
}
/// <summary>
/// Gets the instance of the provider interface APIs out of session state.
/// </summary>
///
/// <exception cref="InvalidRunspaceStateException">
/// Runspace is not open.
/// </exception>
///
/// <exception cref="InvalidOperationException">
/// Another SessionStateProxy call or another pipeline is in progress.
/// </exception>
public virtual ProviderIntrinsics InvokeProvider
{
get { return _runspace.InvokeProvider; }
}
}
}