mirror of
https://github.com/aphrody-labs/PowerShell.git
synced 2026-10-17 20:56:02 +00:00
1952 lines
70 KiB
C#
1952 lines
70 KiB
C#
/********************************************************************++
|
||||
|
|
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
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
#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; }
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
}
|