/// <summary> /// Default constructor for creating ServerSteppablePipelineDriver...Used by server to concurrently /// run 2 pipelines. /// </summary> /// <param name="powershell">Decoded powershell object.</param> /// <param name="noInput">Whether there is input for this powershell.</param> /// <param name="clientPowerShellId">The client powershell id.</param> /// <param name="clientRunspacePoolId">The client runspacepool id.</param> /// <param name="runspacePoolDriver">runspace pool driver /// which is creating this powershell driver</param> /// <param name="apartmentState">Apartment state for this powershell.</param> /// <param name="hostInfo">host info using which the host for /// this powershell will be constructed</param> /// <param name="streamOptions">Serialization options for the streams in this powershell.</param> /// <param name="addToHistory"> /// true if the command is to be added to history list of the runspace. false, otherwise. /// </param> /// <param name="rsToUse"> /// If not null, this Runspace will be used to invoke Powershell. /// If null, the RunspacePool pointed by <paramref name="runspacePoolDriver"/> will be used. /// </param> /// <param name="eventSubscriber"> /// Steppable pipeline event subscriber /// </param> /// <param name="powershellInput">Input collection of the PowerShell pipeline.</param> internal ServerSteppablePipelineDriver(PowerShell powershell, bool noInput, Guid clientPowerShellId, Guid clientRunspacePoolId, ServerRunspacePoolDriver runspacePoolDriver, ApartmentState apartmentState, HostInfo hostInfo, RemoteStreamOptions streamOptions, bool addToHistory, Runspace rsToUse, ServerSteppablePipelineSubscriber eventSubscriber, PSDataCollection <object> powershellInput) #endif { LocalPowerShell = powershell; InstanceId = clientPowerShellId; RunspacePoolId = clientRunspacePoolId; RemoteStreamOptions = streamOptions; #if !CORECLR // No ApartmentState In CoreCLR this.apartmentState = apartmentState; #endif NoInput = noInput; _addToHistory = addToHistory; _eventSubscriber = eventSubscriber; _powershellInput = powershellInput; Input = new PSDataCollection <object>(); InputEnumerator = Input.GetEnumerator(); Input.ReleaseOnEnumeration = true; DataStructureHandler = runspacePoolDriver.DataStructureHandler.CreatePowerShellDataStructureHandler(clientPowerShellId, clientRunspacePoolId, RemoteStreamOptions, null); RemoteHost = DataStructureHandler.GetHostAssociatedWithPowerShell(hostInfo, runspacePoolDriver.ServerRemoteHost); // subscribe to various data structure handler events DataStructureHandler.InputEndReceived += new EventHandler(HandleInputEndReceived); DataStructureHandler.InputReceived += new EventHandler <RemoteDataEventArgs <object> >(HandleInputReceived); DataStructureHandler.StopPowerShellReceived += new EventHandler(HandleStopReceived); DataStructureHandler.HostResponseReceived += new EventHandler <RemoteDataEventArgs <RemoteHostResponse> >(HandleHostResponseReceived); DataStructureHandler.OnSessionConnected += new EventHandler(HandleSessionConnected); if (rsToUse == null) { throw PSTraceSource.NewInvalidOperationException(RemotingErrorIdStrings.NestedPipelineMissingRunspace); } // else, set the runspace pool and invoke this powershell LocalPowerShell.Runspace = rsToUse; eventSubscriber.SubscribeEvents(this); PipelineState = PSInvocationState.NotStarted; }
/// <summary> /// Changes state and sends message to the client as needed. /// </summary> /// <param name="newState"></param> /// <param name="reason"></param> internal void SetState(PSInvocationState newState, Exception reason) { PSInvocationState copyState = PSInvocationState.NotStarted; bool shouldRaiseEvents = false; lock (SyncObject) { switch (PipelineState) { case PSInvocationState.NotStarted: { switch (newState) { case PSInvocationState.Running: case PSInvocationState.Stopping: case PSInvocationState.Completed: case PSInvocationState.Stopped: case PSInvocationState.Failed: copyState = newState; // NotStarted -> Running..we dont send // state back to client. break; } } break; case PSInvocationState.Running: { switch (newState) { case PSInvocationState.NotStarted: throw new InvalidOperationException(); case PSInvocationState.Running: break; case PSInvocationState.Stopping: copyState = newState; break; case PSInvocationState.Completed: case PSInvocationState.Stopped: case PSInvocationState.Failed: copyState = newState; shouldRaiseEvents = true; break; } } break; case PSInvocationState.Stopping: { switch (newState) { case PSInvocationState.Completed: case PSInvocationState.Failed: copyState = PSInvocationState.Stopped; shouldRaiseEvents = true; break; case PSInvocationState.Stopped: copyState = newState; shouldRaiseEvents = true; break; default: throw new InvalidOperationException(); } } break; case PSInvocationState.Stopped: case PSInvocationState.Completed: case PSInvocationState.Failed: break; } PipelineState = copyState; } if (shouldRaiseEvents) { // send the state change notification to the client DataStructureHandler.SendStateChangedInformationToClient( new PSInvocationStateInfo(copyState, reason)); } if (PipelineState == PSInvocationState.Completed || PipelineState == PSInvocationState.Stopped || PipelineState == PSInvocationState.Failed) { // Remove itself from the runspace pool DataStructureHandler.RaiseRemoveAssociationEvent(); } }
/// <summary> /// Default constructor for creating ServerPowerShellDrivers /// </summary> /// <param name="powershell">decoded powershell object</param> /// <param name="extraPowerShell">extra pipeline to be run after <paramref name="powershell"/> completes</param> /// <param name="noInput">whether there is input for this powershell</param> /// <param name="clientPowerShellId">the client powershell id</param> /// <param name="clientRunspacePoolId">the client runspacepool id</param> /// <param name="runspacePoolDriver">runspace pool driver /// which is creating this powershell driver</param> /// <param name="apartmentState">apartment state for this powershell</param> /// <param name="hostInfo">host info using which the host for /// this powershell will be constructed</param> /// <param name="streamOptions">serialization options for the streams in this powershell</param> /// <param name="addToHistory"> /// true if the command is to be added to history list of the runspace. false, otherwise. /// </param> /// <param name="rsToUse"> /// If not null, this Runspace will be used to invoke Powershell. /// If null, the RunspacePool pointed by <paramref name="runspacePoolDriver"/> will be used. /// </param> /// <param name="output"> /// If not null, this is used as another source of output sent to the client. /// </param> internal ServerPowerShellDriver(PowerShell powershell, PowerShell extraPowerShell, bool noInput, Guid clientPowerShellId, Guid clientRunspacePoolId, ServerRunspacePoolDriver runspacePoolDriver, ApartmentState apartmentState, HostInfo hostInfo, RemoteStreamOptions streamOptions, bool addToHistory, Runspace rsToUse, PSDataCollection <PSObject> output) #endif { InstanceId = clientPowerShellId; RunspacePoolId = clientRunspacePoolId; RemoteStreamOptions = streamOptions; #if !CORECLR // No ApartmentState In CoreCLR this.apartmentState = apartmentState; #endif LocalPowerShell = powershell; _extraPowerShell = extraPowerShell; _localPowerShellOutput = new PSDataCollection <PSObject>(); _noInput = noInput; _addToHistory = addToHistory; _psDriverInvoker = runspacePoolDriver; DataStructureHandler = runspacePoolDriver.DataStructureHandler.CreatePowerShellDataStructureHandler(clientPowerShellId, clientRunspacePoolId, RemoteStreamOptions, LocalPowerShell); _remoteHost = DataStructureHandler.GetHostAssociatedWithPowerShell(hostInfo, runspacePoolDriver.ServerRemoteHost); if (!noInput) { InputCollection = new PSDataCollection <object>(); InputCollection.ReleaseOnEnumeration = true; InputCollection.IdleEvent += new EventHandler <EventArgs>(HandleIdleEvent); } RegisterPipelineOutputEventHandlers(_localPowerShellOutput); if (LocalPowerShell != null) { RegisterPowerShellEventHandlers(LocalPowerShell); _datasent[0] = false; } if (extraPowerShell != null) { RegisterPowerShellEventHandlers(extraPowerShell); _datasent[1] = false; } RegisterDataStructureHandlerEventHandlers(DataStructureHandler); // set the runspace pool and invoke this powershell if (rsToUse != null) { LocalPowerShell.Runspace = rsToUse; if (extraPowerShell != null) { extraPowerShell.Runspace = rsToUse; } } else { LocalPowerShell.RunspacePool = runspacePoolDriver.RunspacePool; if (extraPowerShell != null) { extraPowerShell.RunspacePool = runspacePoolDriver.RunspacePool; } } if (output != null) { output.DataAdded += (sender, args) => { if (_localPowerShellOutput.IsOpen) { var items = output.ReadAll(); foreach (var item in items) { _localPowerShellOutput.Add(item); } } }; } }