/********************************************************************++ * Copyright (c) Microsoft Corporation. All rights reserved. * --********************************************************************/ using System.IO; using System.Collections; using System.Collections.Generic; using System.Collections.ObjectModel; using System.Threading; using System.Runtime.Serialization; using System.Management.Automation.Host; using System.Management.Automation.Remoting; using Microsoft.PowerShell.Commands; using System.Management.Automation.Internal; using System.Diagnostics.CodeAnalysis; // for fxcop using Dbg = System.Management.Automation.Diagnostics; using System.Diagnostics; using System.Linq; using Microsoft.PowerShell.Telemetry.Internal; #pragma warning disable 1634, 1691 // Stops compiler from warning about unknown warnings namespace System.Management.Automation.Runspaces { /// /// Runspace class for local runspace /// internal sealed partial class LocalRunspace : RunspaceBase { #region constructors /// /// Construct an instance of an Runspace using a custom implementation /// of PSHost. /// /// /// The explicit PSHost implementation /// /// /// configuration information for this minshell. /// [SuppressMessage("Microsoft.Maintainability", "CA1505:AvoidUnmaintainableCode")] internal LocalRunspace(PSHost host, RunspaceConfiguration runspaceConfig) : base(host, runspaceConfig) { } /// /// Construct an instance of an Runspace using a custom implementation /// of PSHost. /// /// /// The explicit PSHost implementation /// /// /// configuration information for this minshell. /// /// /// If true, don't make a copy of the initial session state object /// [SuppressMessage("Microsoft.Maintainability", "CA1505:AvoidUnmaintainableCode")] internal LocalRunspace(PSHost host, InitialSessionState initialSessionState, bool suppressClone) : base(host, initialSessionState, suppressClone) { } /// /// Construct an instance of an Runspace using a custom implementation /// of PSHost. /// /// /// The explicit PSHost implementation /// /// /// configuration information for this minshell. /// [SuppressMessage("Microsoft.Maintainability", "CA1505:AvoidUnmaintainableCode")] internal LocalRunspace(PSHost host, InitialSessionState initialSessionState) : base(host, initialSessionState) { } #endregion constructors /// /// Private data to be used by applications built on top of PowerShell. /// /// Local runspace pool is created with application private data set to an empty . /// /// Runspaces that are part of a inherit application private data from the pool. /// public override PSPrimitiveDictionary GetApplicationPrivateData() { // if we didn't get applicationPrivateData from a runspace pool, // then we create a new one if (_applicationPrivateData == null) { lock (this.SyncRoot) { if (_applicationPrivateData == null) { _applicationPrivateData = new PSPrimitiveDictionary(); } } } return _applicationPrivateData; } /// /// A method that runspace pools can use to propagate application private data into runspaces /// /// internal override void SetApplicationPrivateData(PSPrimitiveDictionary applicationPrivateData) { _applicationPrivateData = applicationPrivateData; } private PSPrimitiveDictionary _applicationPrivateData; /// /// Gets the event manager /// public override PSEventManager Events { get { System.Management.Automation.ExecutionContext context = this.GetExecutionContext; if (context == null) { return null; } return context.Events; } } /// /// This property determines whether a new thread is create for each invocation /// /// /// Any updates to the value of this property must be done before the Runspace is opened /// /// /// An attempt to change this property was made after opening the Runspace /// /// /// The thread options cannot be changed to the requested value /// public override PSThreadOptions ThreadOptions { get { return _createThreadOptions; } set { lock (this.SyncRoot) { if (value != _createThreadOptions) { if (this.RunspaceStateInfo.State != RunspaceState.BeforeOpen) { #if CORECLR // No ApartmentState.STA Support In CoreCLR bool allowed = value == PSThreadOptions.ReuseThread; #else // if the runspace is already opened we only allow changing the options if // the apartment state is MTA and the new value is ReuseThread bool allowed = (this.ApartmentState == ApartmentState.MTA || this.ApartmentState == ApartmentState.Unknown) // Unknown is the same as MTA && value == PSThreadOptions.ReuseThread; #endif if (!allowed) { throw new InvalidOperationException(StringUtil.Format(RunspaceStrings.InvalidThreadOptionsChange)); } } _createThreadOptions = value; } } } } private PSThreadOptions _createThreadOptions = PSThreadOptions.Default; /// /// Resets the runspace state to allow for fast reuse. Not all of the runspace /// elements are reset. The goal is to minimize the chance of the user taking /// accidental dependencies on prior runspace state. /// public override void ResetRunspaceState() { PSInvalidOperationException invalidOperation = null; if (this.InitialSessionState == null) { invalidOperation = PSTraceSource.NewInvalidOperationException(); } else if (this.RunspaceState != Runspaces.RunspaceState.Opened) { invalidOperation = PSTraceSource.NewInvalidOperationException( RunspaceStrings.RunspaceNotInOpenedState, this.RunspaceState); } else if (this.RunspaceAvailability != Runspaces.RunspaceAvailability.Available) { invalidOperation = PSTraceSource.NewInvalidOperationException( RunspaceStrings.ConcurrentInvokeNotAllowed); } if (invalidOperation != null) { invalidOperation.Source = "ResetRunspaceState"; throw invalidOperation; } this.InitialSessionState.ResetRunspaceState(this.ExecutionContext); // Finally, reset history for this runspace. This needs to be done // last to so that changes to the default MaximumHistorySize will be picked up. _history = new History(this.ExecutionContext); } #region protected_methods /// /// Create a pipeline from a command string /// /// A valid command string. Can be null /// if true command is added to history /// True for nested pipeline /// /// A pipeline pre-filled with Commands specified in commandString. /// protected override Pipeline CoreCreatePipeline(string command, bool addToHistory, bool isNested) { // NTRAID#Windows Out Of Band Releases-915851-2005/09/13 if (_disposed) { throw PSTraceSource.NewObjectDisposedException("runspace"); } return (Pipeline)new LocalPipeline(this, command, addToHistory, isNested); } #endregion protected_methods #region protected_properties /// /// Gets the execution context /// internal override System.Management.Automation.ExecutionContext GetExecutionContext { get { if (_engine == null) return null; else return _engine.Context; } } /// /// Returns true if the internal host is in a nested prompt /// internal override bool InNestedPrompt { get { System.Management.Automation.ExecutionContext context = this.GetExecutionContext; if (context == null) { return false; } return context.InternalHost.HostInNestedPrompt(); } } #endregion protected_properties #region internal_properties /// /// CommandFactory object for this runspace. /// internal CommandFactory CommandFactory { get { return _commandFactory; } } /// /// Gets history manager for this runspace /// /// internal History History { get { return _history; } } /// /// Gets transcription data for this runspace /// /// internal TranscriptionData TranscriptionData { get { return _transcriptionData; } } private TranscriptionData _transcriptionData = null; private JobRepository _jobRepository; /// /// List of jobs in this runspace /// internal JobRepository JobRepository { get { return _jobRepository; } } private JobManager _jobManager; /// /// Manager for JobSourceAdapters registered in this runspace. /// public override JobManager JobManager { get { return _jobManager; } } private RunspaceRepository _runspaceRepository; /// /// List of remote runspaces in this runspace /// internal RunspaceRepository RunspaceRepository { get { return _runspaceRepository; } } #endregion internal_properties #region Debugger /// /// Debugger /// public override Debugger Debugger { get { return InternalDebugger ?? base.Debugger; } } private static string s_debugPreferenceCachePath = Path.Combine(Path.Combine(Platform.GetFolderPath(Environment.SpecialFolder.ProgramFiles), "WindowsPowerShell"), "DebugPreference.clixml"); private static object s_debugPreferenceLockObject = new object(); /// /// DebugPreference serves as a property bag to keep /// track of all process specific debug preferences. /// public class DebugPreference { public string[] AppDomainNames; } /// /// CreateDebugPerfStruct is a helper method to populate DebugPreference /// /// App Domain Names /// DebugPreference private static DebugPreference CreateDebugPreference(string[] AppDomainNames) { DebugPreference DebugPreference = new DebugPreference(); DebugPreference.AppDomainNames = AppDomainNames; return DebugPreference; } /// /// SetDebugPreference is a helper method used to enable and disable debug preference. /// /// Process Name /// App Domain Name /// Indicates if the debug preference has to be enabled or disabled. internal static void SetDebugPreference(string processName, List appDomainName, bool enable) { lock (s_debugPreferenceLockObject) { bool iscacheUpdated = false; Hashtable debugPreferenceCache = null; string[] appDomainNames = null; if (appDomainName != null) { appDomainNames = appDomainName.ToArray(); } if (!File.Exists(LocalRunspace.s_debugPreferenceCachePath)) { if (enable) { DebugPreference DebugPreference = CreateDebugPreference(appDomainNames); debugPreferenceCache = new Hashtable(); debugPreferenceCache.Add(processName, DebugPreference); iscacheUpdated = true; } } else { debugPreferenceCache = GetDebugPreferenceCache(null); if (debugPreferenceCache != null) { if (enable) { // Debug preference is set to enable. // If the cache does not contain the process name, then we just update the cache. if (!debugPreferenceCache.ContainsKey(processName)) { DebugPreference DebugPreference = CreateDebugPreference(appDomainNames); debugPreferenceCache.Add(processName, DebugPreference); iscacheUpdated = true; } else { // In this case, the cache contains the process name, hence we check the list of // app domains for which the debug preference is set to enable. DebugPreference processDebugPreference = GetProcessSpecificDebugPreference(debugPreferenceCache[processName]); // processDebugPreference would point to null if debug preference is enabled for all app domains. // If processDebugPreference is not null then it means that user has selected specific // appdomins for which the debug preference has to be enabled. if (processDebugPreference != null) { List cachedAppDomainNames = null; if (processDebugPreference.AppDomainNames != null && processDebugPreference.AppDomainNames.Length > 0) { cachedAppDomainNames = new List(processDebugPreference.AppDomainNames); foreach (string currentAppDomainName in appDomainName) { if (!cachedAppDomainNames.Contains(currentAppDomainName, StringComparer.OrdinalIgnoreCase)) { cachedAppDomainNames.Add(currentAppDomainName); iscacheUpdated = true; } } } if (iscacheUpdated) { DebugPreference DebugPreference = CreateDebugPreference(cachedAppDomainNames.ToArray()); debugPreferenceCache[processName] = DebugPreference; } } } } else { // Debug preference is set to disable. if (debugPreferenceCache.ContainsKey(processName)) { if (appDomainName == null) { debugPreferenceCache.Remove(processName); iscacheUpdated = true; } else { DebugPreference processDebugPreference = GetProcessSpecificDebugPreference(debugPreferenceCache[processName]); // processDebugPreference would point to null if debug preference is enabled for all app domains. // If processDebugPreference is not null then it means that user has selected specific // appdomins for which the debug preference has to be enabled. if (processDebugPreference != null) { List cachedAppDomainNames = null; if (processDebugPreference.AppDomainNames != null && processDebugPreference.AppDomainNames.Length > 0) { cachedAppDomainNames = new List(processDebugPreference.AppDomainNames); foreach (string currentAppDomainName in appDomainName) { if (cachedAppDomainNames.Contains(currentAppDomainName, StringComparer.OrdinalIgnoreCase)) { // remove requested appdomains debug preference details. cachedAppDomainNames.Remove(currentAppDomainName); iscacheUpdated = true; } } } if (iscacheUpdated) { DebugPreference DebugPreference = CreateDebugPreference(cachedAppDomainNames.ToArray()); debugPreferenceCache[processName] = DebugPreference; } } } } } } else { // For whatever reason, cache is corrupted. Hence override the cache content. if (enable) { debugPreferenceCache = new Hashtable(); DebugPreference DebugPreference = CreateDebugPreference(appDomainNames); debugPreferenceCache.Add(processName, DebugPreference); iscacheUpdated = true; } } } if (iscacheUpdated) { using (PowerShell ps = PowerShell.Create()) { ps.AddCommand("Export-Clixml").AddParameter("Path", LocalRunspace.s_debugPreferenceCachePath).AddParameter("InputObject", debugPreferenceCache); ps.Invoke(); } } } } /// /// GetDebugPreferenceCache is a helper method used to fetch /// the debug preference cache contents as a Hashtable. /// /// Runspace /// If the Debug preference is persisted then a hashtable containing /// the debug preference is returned or else Null is returned. private static Hashtable GetDebugPreferenceCache(Runspace runspace) { Hashtable debugPreferenceCache = null; using (PowerShell ps = PowerShell.Create()) { if (runspace != null) { ps.Runspace = runspace; } ps.AddCommand("Import-Clixml").AddParameter("Path", LocalRunspace.s_debugPreferenceCachePath); Collection psObjects = ps.Invoke(); if (psObjects != null && psObjects.Count == 1) { debugPreferenceCache = psObjects[0].BaseObject as Hashtable; } } return debugPreferenceCache; } /// /// GetProcessSpecificDebugPreference is a helper method used to fetch persisted process specific debug preference. /// /// /// private static DebugPreference GetProcessSpecificDebugPreference(object debugPreference) { DebugPreference processDebugPreference = null; if (debugPreference != null) { PSObject debugPreferencePsObject = debugPreference as PSObject; if (debugPreferencePsObject != null) { processDebugPreference = LanguagePrimitives.ConvertTo(debugPreferencePsObject); } } return processDebugPreference; } #endregion /// /// Open the runspace /// /// /// parameter which control if Open is done synchronously or asynchronously /// protected override void OpenHelper(bool syncCall) { if (syncCall) { //Open runspace synchronously DoOpenHelper(); } else { //Open runspace in another thread Thread asyncThread = new Thread(new ThreadStart(this.OpenThreadProc)); asyncThread.Start(); } } /// /// Start method for asynchronous open /// private void OpenThreadProc() { #pragma warning disable 56500 try { DoOpenHelper(); } catch (Exception) { //This exception is reported by raising RunspaceState //change event. } #pragma warning restore 56500 } /// /// Helper function used for opening a runspace /// private void DoOpenHelper() { // NTRAID#Windows Out Of Band Releases-915851-2005/09/13 if (_disposed) { throw PSTraceSource.NewObjectDisposedException("runspace"); } bool startLifeCycleEventWritten = false; s_runspaceInitTracer.WriteLine("begin open runspace"); try { _transcriptionData = new TranscriptionData(); if (InitialSessionState != null) { // All ISS-based configuration of the engine itself is done by AutomationEngine, // which calls InitialSessionState.Bind(). Anything that doesn't // require an active and open runspace should be done in ISS.Bind() _engine = new AutomationEngine(Host, null, InitialSessionState); } else { _engine = new AutomationEngine(Host, RunspaceConfiguration, null); } _engine.Context.CurrentRunspace = this; //Log engine for start of engine life MshLog.LogEngineLifecycleEvent(_engine.Context, EngineState.Available); startLifeCycleEventWritten = true; _commandFactory = new CommandFactory(_engine.Context); _history = new History(_engine.Context); _jobRepository = new JobRepository(); _jobManager = new JobManager(); _runspaceRepository = new RunspaceRepository(); s_runspaceInitTracer.WriteLine("initializing built-in aliases and variable information"); InitializeDefaults(); } catch (Exception exception) { s_runspaceInitTracer.WriteLine("Runspace open failed"); //Log engine health event LogEngineHealthEvent(exception); //Log engine for end of engine life if (startLifeCycleEventWritten) { Dbg.Assert(_engine.Context != null, "if startLifeCycleEventWritten is true, ExecutionContext must be present"); MshLog.LogEngineLifecycleEvent(_engine.Context, EngineState.Stopped); } //Open failed. Set the RunspaceState to Broken. SetRunspaceState(RunspaceState.Broken, exception); //Raise the event RaiseRunspaceStateEvents(); //Rethrow the exception. For asynchronous execution, //OpenThreadProc will catch it. For synchronous execution //caller of open will catch it. throw; } SetRunspaceState(RunspaceState.Opened); RunspaceOpening.Set(); //Raise the event RaiseRunspaceStateEvents(); s_runspaceInitTracer.WriteLine("runspace opened successfully"); // Now do initial state configuration that requires an active runspace if (InitialSessionState != null) { Exception initError = InitialSessionState.BindRunspace(this, s_runspaceInitTracer); if (initError != null) { // Log engine health event LogEngineHealthEvent(initError); // Log engine for end of engine life Debug.Assert(_engine.Context != null, "if startLifeCycleEventWritten is true, ExecutionContext must be present"); MshLog.LogEngineLifecycleEvent(_engine.Context, EngineState.Stopped); // Open failed. Set the RunspaceState to Broken. SetRunspaceState(RunspaceState.Broken, initError); // Raise the event RaiseRunspaceStateEvents(); // Throw the exception. For asynchronous execution, // OpenThreadProc will catch it. For synchronous execution // caller of open will catch it. throw initError; } } TelemetryAPI.ReportLocalSessionCreated(InitialSessionState, TranscriptionData); } /// /// Logs engine health event /// internal void LogEngineHealthEvent(Exception exception) { LogEngineHealthEvent( exception, Severity.Error, MshLog.EVENT_ID_CONFIGURATION_FAILURE, null); } /// /// Logs engine health event /// internal void LogEngineHealthEvent(Exception exception, Severity severity, int id, Dictionary additionalInfo) { Dbg.Assert(exception != null, "Caller should validate the parameter"); LogContext logContext = new LogContext(); logContext.EngineVersion = Version.ToString(); logContext.HostId = Host.InstanceId.ToString(); logContext.HostName = Host.Name; logContext.HostVersion = Host.Version.ToString(); logContext.RunspaceId = InstanceId.ToString(); logContext.Severity = severity.ToString(); if (this.RunspaceConfiguration == null) { logContext.ShellId = Utils.DefaultPowerShellShellID; } else { logContext.ShellId = this.RunspaceConfiguration.ShellId; } MshLog.LogEngineHealthEvent( logContext, id, exception, additionalInfo); } /// /// Returns the thread that must be used to execute pipelines when CreateThreadOptions is ReuseThread /// /// /// The pipeline calls this function after ensuring there is a single thread in the pipeline, so no locking is necessary /// internal PipelineThread GetPipelineThread() { if (_pipelineThread == null) { #if CORECLR // No ApartmentState In CoreCLR _pipelineThread = new PipelineThread(); #else _pipelineThread = new PipelineThread(this.ApartmentState); #endif } return _pipelineThread; } private PipelineThread _pipelineThread = null; protected override void CloseHelper(bool syncCall) { if (syncCall) { //Do close synchronously DoCloseHelper(); } else { //Do close asynchronously Thread asyncThread = new Thread(new ThreadStart(this.CloseThreadProc)); asyncThread.Start(); } } /// /// Start method for asynchronous close /// private void CloseThreadProc() { #pragma warning disable 56500 try { DoCloseHelper(); } catch (Exception) { } #pragma warning restore 56500 } /// /// Close the runspace. /// /// /// Attempts to create/execute pipelines after a call to /// close will fail. /// private void DoCloseHelper() { // Stop any transcription if we're the last runspace to exit ExecutionContext executionContext = this.GetExecutionContext; if (executionContext != null) { Runspace hostRunspace = null; try { hostRunspace = executionContext.EngineHostInterface.Runspace; } catch (PSNotImplementedException) { // EngineHostInterface.Runspace throws PSNotImplementedException if there // is no interactive host. } if ((hostRunspace == null) || (this == hostRunspace)) { PSHostUserInterface host = executionContext.EngineHostInterface.UI; if (host != null) { host.StopAllTranscribing(); } } } // Generate the shutdown event if (Events != null) Events.GenerateEvent(PSEngineEvent.Exiting, null, new object[] { }, null, true, false); //Stop all running pipelines //Note:Do not perform the Cancel in lock. Reason is //Pipeline executes in separate thread, say threadP. //When pipeline is canceled/failed/completed in //Pipeline.ExecuteThreadProc it removes the pipeline //from the list of running pipelines. threadP will need //lock to remove the pipelines from the list of running pipelines //And we will deadlock. //Note:It is possible that one or more pipelines in the list //of active pipelines have completed before we call cancel. //That is fine since Pipeline.Cancel handles that( It ignores //the cancel request if pipeline execution has already //completed/failed/canceled. StopPipelines(); // Disconnect all disconnectable jobs in the job repository. StopOrDisconnectAllJobs(); // Close or disconnect all the remote runspaces available in the // runspace repository. CloseOrDisconnectAllRemoteRunspaces(() => { List runspaces = new List(); foreach (PSSession psSession in this.RunspaceRepository.Runspaces) { runspaces.Add(psSession.Runspace as RemoteRunspace); } return runspaces; }); //Notify Engine components that that runspace is closing. _engine.Context.RunspaceClosingNotification(); //Log engine lifecycle event. MshLog.LogEngineLifecycleEvent(_engine.Context, EngineState.Stopped); // Uninitialize the AMSI scan interface AmsiUtils.Uninitialize(); //All pipelines have been canceled. Close the runspace. _engine = null; _commandFactory = null; SetRunspaceState(RunspaceState.Closed); //Raise Event RaiseRunspaceStateEvents(); // Report telemetry if we have no more open runspaces. bool allRunspacesClosed = true; bool hostProvidesExitTelemetry = false; foreach (var r in Runspace.RunspaceList) { if (r.RunspaceStateInfo.State != RunspaceState.Closed) { allRunspacesClosed = false; break; } var localRunspace = r as LocalRunspace; if (localRunspace != null && localRunspace.Host is IHostProvidesTelemetryData) { hostProvidesExitTelemetry = true; break; } } if (allRunspacesClosed && !hostProvidesExitTelemetry) { TelemetryAPI.ReportExitTelemetry(null); } } /// /// Closes or disconnects all the remote runspaces passed in by the getRunspace /// function. If a remote runspace supports disconnect then it will be disconnected /// rather than closed. /// private void CloseOrDisconnectAllRemoteRunspaces(Func> getRunspaces) { List runspaces = getRunspaces(); if (runspaces.Count == 0) { return; } // whether the close of all remoterunspaces completed using (ManualResetEvent remoteRunspaceCloseCompleted = new ManualResetEvent(false)) { ThrottleManager throttleManager = new ThrottleManager(); throttleManager.ThrottleComplete += delegate (object sender, EventArgs e) { remoteRunspaceCloseCompleted.Set(); }; foreach (RemoteRunspace remoteRunspace in runspaces) { IThrottleOperation operation = new CloseOrDisconnectRunspaceOperationHelper(remoteRunspace); throttleManager.AddOperation(operation); } throttleManager.EndSubmitOperations(); remoteRunspaceCloseCompleted.WaitOne(); } } /// /// Disconnects all disconnectable jobs listed in the JobRepository. /// private void StopOrDisconnectAllJobs() { if (JobRepository.Jobs.Count == 0) { return; } List disconnectRunspaces = new List(); using (ManualResetEvent jobsStopCompleted = new ManualResetEvent(false)) { ThrottleManager throttleManager = new ThrottleManager(); throttleManager.ThrottleComplete += delegate (object sender, EventArgs e) { jobsStopCompleted.Set(); }; foreach (Job job in this.JobRepository.Jobs) { // Only stop or disconnect PowerShell jobs. if (job is PSRemotingJob == false) { continue; } if (!job.CanDisconnect) { // If the job cannot be disconnected then add it to // the stop list. throttleManager.AddOperation(new StopJobOperationHelper(job)); } else if (job.JobStateInfo.State == JobState.Running) { // Otherwise add disconnectable runspaces to list so that // they can be disconnected. IEnumerable jobRunspaces = job.GetRunspaces(); if (jobRunspaces != null) { disconnectRunspaces.AddRange(jobRunspaces); } } } // foreach job // Stop jobs. throttleManager.EndSubmitOperations(); jobsStopCompleted.WaitOne(); } // using jobsStopCompleted // Disconnect all disconnectable job runspaces found. CloseOrDisconnectAllRemoteRunspaces(() => { return disconnectRunspaces; }); } internal void ReleaseDebugger() { Debugger debugger = Debugger; if (debugger != null) { try { if (debugger.UnhandledBreakpointMode == UnhandledBreakpointProcessingMode.Wait) { // Sets the mode and also releases a held debug stop. debugger.UnhandledBreakpointMode = UnhandledBreakpointProcessingMode.Ignore; } } catch (PSNotImplementedException) { } } } #region SessionStateProxy protected override void DoSetVariable(string name, object value) { // NTRAID#Windows Out Of Band Releases-915851-2005/09/13 if (_disposed) { throw PSTraceSource.NewObjectDisposedException("runspace"); } _engine.Context.EngineSessionState.SetVariableValue(name, value, CommandOrigin.Internal); } protected override object DoGetVariable(string name) { // NTRAID#Windows Out Of Band Releases-915851-2005/09/13 if (_disposed) { throw PSTraceSource.NewObjectDisposedException("runspace"); } return _engine.Context.EngineSessionState.GetVariableValue(name); } protected override List DoApplications { get { if (_disposed) { throw PSTraceSource.NewObjectDisposedException("runspace"); } return _engine.Context.EngineSessionState.Applications; } } protected override List DoScripts { get { if (_disposed) { throw PSTraceSource.NewObjectDisposedException("runspace"); } return _engine.Context.EngineSessionState.Scripts; } } protected override DriveManagementIntrinsics DoDrive { get { if (_disposed) { throw PSTraceSource.NewObjectDisposedException("runspace"); } return _engine.Context.SessionState.Drive; } } protected override PSLanguageMode DoLanguageMode { get { if (_disposed) { throw PSTraceSource.NewObjectDisposedException("runspace"); } return _engine.Context.SessionState.LanguageMode; } set { if (_disposed) { throw PSTraceSource.NewObjectDisposedException("runspace"); } _engine.Context.SessionState.LanguageMode = value; } } protected override PSModuleInfo DoModule { get { if (_disposed) { throw PSTraceSource.NewObjectDisposedException("runspace"); } return _engine.Context.EngineSessionState.Module; } } protected override PathIntrinsics DoPath { get { if (_disposed) { throw PSTraceSource.NewObjectDisposedException("runspace"); } return _engine.Context.SessionState.Path; } } protected override CmdletProviderManagementIntrinsics DoProvider { get { if (_disposed) { throw PSTraceSource.NewObjectDisposedException("runspace"); } return _engine.Context.SessionState.Provider; } } protected override PSVariableIntrinsics DoPSVariable { get { if (_disposed) { throw PSTraceSource.NewObjectDisposedException("runspace"); } return _engine.Context.SessionState.PSVariable; } } protected override CommandInvocationIntrinsics DoInvokeCommand { get { if (_disposed) { throw PSTraceSource.NewObjectDisposedException("runspace"); } return _engine.Context.EngineIntrinsics.InvokeCommand; } } protected override ProviderIntrinsics DoInvokeProvider { get { if (_disposed) { throw PSTraceSource.NewObjectDisposedException("runspace"); } return _engine.Context.EngineIntrinsics.InvokeProvider; } } #endregion SessionStateProxy #region IDisposable Members /// /// Set to true when object is disposed /// private bool _disposed; /// /// Protected dispose which can be overridden by derived classes. /// /// [SuppressMessage("Microsoft.Usage", "CA2213:DisposableFieldsShouldBeDisposed", MessageId = "pipelineThread", Justification = "pipelineThread is disposed in Close()")] protected override void Dispose(bool disposing) { try { if (_disposed) { return; } lock (SyncRoot) { if (_disposed) { return; } _disposed = true; } if (disposing) { Close(); _engine = null; _history = null; _transcriptionData = null; _jobManager = null; _jobRepository = null; _runspaceRepository = null; if (RunspaceOpening != null) { RunspaceOpening.Dispose(); RunspaceOpening = null; } Platform.RemoveTemporaryDirectory(); // Dispose the event manager if (this.ExecutionContext != null && this.ExecutionContext.Events != null) { try { this.ExecutionContext.Events.Dispose(); } catch (ObjectDisposedException) { ; } } } } finally { base.Dispose(disposing); } } /// /// Close the runspace /// public override void Close() { // Do not put cleanup activities in here, as they aren't // captured in CloseAsync() case. Instead, put them in // DoCloseHelper() base.Close(); // call base.Close() first to make it stop the pipeline if (_pipelineThread != null) { _pipelineThread.Close(); } } #endregion IDisposable Members #region private fields /// /// CommandFactory for creating Command objects /// private CommandFactory _commandFactory; /// /// AutomationEngine instance for this runspace /// private AutomationEngine _engine; internal AutomationEngine Engine { get { return _engine; } } /// /// Manages history for this runspace /// private History _history; [TraceSource("RunspaceInit", "Initialization code for Runspace")] private static PSTraceSource s_runspaceInitTracer = PSTraceSource.GetTracer("RunspaceInit", "Initialization code for Runspace", false); /// /// This ensures all processes have a server/listener. /// private static RemoteSessionNamedPipeServer s_IPCNamedPipeServer = RemoteSessionNamedPipeServer.IPCNamedPipeServer; #endregion private fields } #region Helper Class /// /// Helper class to stop a running job. /// internal sealed class StopJobOperationHelper : IThrottleOperation { private Job _job; /// /// Internal constructor /// /// Job object to stop. internal StopJobOperationHelper(Job job) { _job = job; _job.StateChanged += new EventHandler(HandleJobStateChanged); } /// /// Handles the Job state change event. /// /// Originator of event, unused /// Event arguments containing Job state. private void HandleJobStateChanged(object sender, JobStateEventArgs eventArgs) { if (_job.IsFinishedState(_job.JobStateInfo.State)) { // We are done when the job is in the finished state. RaiseOperationCompleteEvent(); } } /// /// Override method to start the operation. /// internal override void StartOperation() { if (_job.IsFinishedState(_job.JobStateInfo.State)) { // The job is already in the finished state and so cannot be stopped. RaiseOperationCompleteEvent(); } else { // Otherwise stop the job. _job.StopJob(); } } /// /// Override method to stop the operation. Not used, stop operation must /// run to completion. /// internal override void StopOperation() { } /// /// Event to signal ThrottleManager when the operation is complete. /// internal override event EventHandler OperationComplete; /// /// Raise the OperationComplete event. /// private void RaiseOperationCompleteEvent() { _job.StateChanged -= new EventHandler(HandleJobStateChanged); OperationStateEventArgs operationStateArgs = new OperationStateEventArgs(); operationStateArgs.OperationState = OperationState.StartComplete; operationStateArgs.BaseEvent = EventArgs.Empty; OperationComplete.SafeInvoke(this, operationStateArgs); } } /// /// Helper class to disconnect a runspace if the runspace supports disconnect /// semantics or otherwise close the runspace. /// internal sealed class CloseOrDisconnectRunspaceOperationHelper : IThrottleOperation { private RemoteRunspace _remoteRunspace; /// /// Internal constructor /// /// internal CloseOrDisconnectRunspaceOperationHelper(RemoteRunspace remoteRunspace) { _remoteRunspace = remoteRunspace; _remoteRunspace.StateChanged += new EventHandler(HandleRunspaceStateChanged); } /// /// Handle the runspace state changed event /// /// sender of this information, unused /// runspace event args private void HandleRunspaceStateChanged(object sender, RunspaceStateEventArgs eventArgs) { switch (eventArgs.RunspaceStateInfo.State) { case RunspaceState.BeforeOpen: case RunspaceState.Closing: case RunspaceState.Opened: case RunspaceState.Opening: case RunspaceState.Disconnecting: return; } //remoteRunspace.Dispose(); //remoteRunspace = null; RaiseOperationCompleteEvent(); } /// /// Start the operation of closing the runspace /// internal override void StartOperation() { if (_remoteRunspace.RunspaceStateInfo.State == RunspaceState.Closed || _remoteRunspace.RunspaceStateInfo.State == RunspaceState.Broken || _remoteRunspace.RunspaceStateInfo.State == RunspaceState.Disconnected) { // If the runspace is currently in a disconnected state then leave it // as is. // in this case, calling a close won't raise any events. Simply raise // the OperationCompleted event. After the if check, but before we // get to this point if the state was changed, then the StateChanged // event handler will anyway raise the event and so we are fine RaiseOperationCompleteEvent(); } else { // If the runspace supports disconnect semantics and is running a command, // then disconnect it rather than closing it. if (_remoteRunspace.CanDisconnect && _remoteRunspace.GetCurrentlyRunningPipeline() != null) { _remoteRunspace.DisconnectAsync(); } else { _remoteRunspace.CloseAsync(); } } } /// /// There is no scenario where we are going to cancel this close /// Hence this method is intentionally empty /// internal override void StopOperation() { } /// /// Event raised when the required operation is complete /// internal override event EventHandler OperationComplete; /// /// Raise the operation completed event /// private void RaiseOperationCompleteEvent() { _remoteRunspace.StateChanged -= new EventHandler(HandleRunspaceStateChanged); OperationStateEventArgs operationStateEventArgs = new OperationStateEventArgs(); operationStateEventArgs.OperationState = OperationState.StartComplete; operationStateEventArgs.BaseEvent = EventArgs.Empty; OperationComplete.SafeInvoke(this, operationStateEventArgs); } } /// /// Defines the exception thrown an error loading modules occurs while opening the runspace. It /// contains a list of all of the module errors that have occurred /// [Serializable] public class RunspaceOpenModuleLoadException : RuntimeException { #region ctor /// /// Initializes a new instance of ScriptBlockToPowerShellNotSupportedException /// with the message set to typeof(ScriptBlockToPowerShellNotSupportedException).FullName /// public RunspaceOpenModuleLoadException() : base(typeof(ScriptBlockToPowerShellNotSupportedException).FullName) { } /// /// Initializes a new instance of ScriptBlockToPowerShellNotSupportedException setting the message /// /// the exception's message public RunspaceOpenModuleLoadException(string message) : base(message) { } /// /// Initializes a new instance of ScriptBlockToPowerShellNotSupportedException setting the message and innerException /// /// the exception's message /// the exceptions's inner exception public RunspaceOpenModuleLoadException(string message, Exception innerException) : base(message, innerException) { } /// /// Recommended constructor for the class /// /// The name of the module that cause the error /// The collection of errors that occurred during module processing internal RunspaceOpenModuleLoadException( string moduleName, PSDataCollection errors) : base(StringUtil.Format(RunspaceStrings.ErrorLoadingModulesOnRunspaceOpen, moduleName, (errors != null && errors.Count > 0 && errors[0] != null) ? errors[0].ToString() : String.Empty), null) { _errors = errors; this.SetErrorId("ErrorLoadingModulesOnRunspaceOpen"); this.SetErrorCategory(ErrorCategory.OpenError); } #endregion ctor /// /// The collection of error records generated while loading the modules. /// public PSDataCollection ErrorRecords { get { return _errors; } } private PSDataCollection _errors; #region Serialization /// /// Initializes a new instance of RunspaceOpenModuleLoadException with serialization parameters /// /// serialization information /// streaming context protected RunspaceOpenModuleLoadException(SerializationInfo info, StreamingContext context) : base(info, context) { } /// /// Populates a with the /// data needed to serialize the RunspaceOpenModuleLoadException object. /// /// The to populate with data. /// The destination for this serialization. public override void GetObjectData(SerializationInfo info, StreamingContext context) { if (info == null) { throw new PSArgumentNullException("info"); } base.GetObjectData(info, context); } #endregion Serialization } // RunspaceOpenException #endregion Helper Class }