internal ServerSteppablePipelineDriver(PowerShell powershell, bool noInput, Guid clientPowerShellId, Guid clientRunspacePoolId, ServerRunspacePoolDriver runspacePoolDriver, ApartmentState apartmentState, HostInfo hostInfo, System.Management.Automation.RemoteStreamOptions streamOptions, bool addToHistory, Runspace rsToUse, ServerSteppablePipelineSubscriber eventSubscriber, PSDataCollection<object> powershellInput) { this.localPowerShell = powershell; this.clientPowerShellId = clientPowerShellId; this.clientRunspacePoolId = clientRunspacePoolId; this.remoteStreamOptions = streamOptions; this.apartmentState = apartmentState; this.noInput = noInput; this.addToHistory = addToHistory; this.eventSubscriber = eventSubscriber; this.powershellInput = powershellInput; this.input = new PSDataCollection<object>(); this.inputEnumerator = this.input.GetEnumerator(); this.input.ReleaseOnEnumeration = true; this.dsHandler = runspacePoolDriver.DataStructureHandler.CreatePowerShellDataStructureHandler(clientPowerShellId, clientRunspacePoolId, this.remoteStreamOptions, null); this.remoteHost = this.dsHandler.GetHostAssociatedWithPowerShell(hostInfo, runspacePoolDriver.ServerRemoteHost); this.dsHandler.InputEndReceived += new EventHandler(this.HandleInputEndReceived); this.dsHandler.InputReceived += new EventHandler<RemoteDataEventArgs<object>>(this.HandleInputReceived); this.dsHandler.StopPowerShellReceived += new EventHandler(this.HandleStopReceived); this.dsHandler.HostResponseReceived += new EventHandler<RemoteDataEventArgs<RemoteHostResponse>>(this.HandleHostResponseReceived); this.dsHandler.OnSessionConnected += new EventHandler(this.HandleSessionConnected); if (rsToUse == null) { throw PSTraceSource.NewInvalidOperationException("RemotingErrorIdStrings", "NestedPipelineMissingRunspace", new object[0]); } this.localPowerShell.Runspace = rsToUse; eventSubscriber.SubscribeEvents(this); this.stateOfSteppablePipeline = PSInvocationState.NotStarted; }
private void HandleStopReceived(object sender, EventArgs eventArgs) { lock (this.syncObject) { this.stateOfSteppablePipeline = PSInvocationState.Stopping; } this.PerformStop(); if (this.powershellInput != null) { this.powershellInput.Pulse(); } }
internal void UpdateRunspaceAvailability(PSInvocationState invocationState, bool raiseEvent) { switch (invocationState) { case PSInvocationState.NotStarted: this.UpdateRunspaceAvailability(PipelineState.NotStarted, raiseEvent); return; case PSInvocationState.Running: this.UpdateRunspaceAvailability(PipelineState.Running, raiseEvent); return; case PSInvocationState.Stopping: this.UpdateRunspaceAvailability(PipelineState.Stopping, raiseEvent); return; case PSInvocationState.Stopped: this.UpdateRunspaceAvailability(PipelineState.Stopped, raiseEvent); return; case PSInvocationState.Completed: this.UpdateRunspaceAvailability(PipelineState.Completed, raiseEvent); return; case PSInvocationState.Failed: this.UpdateRunspaceAvailability(PipelineState.Failed, raiseEvent); return; case PSInvocationState.Disconnected: this.UpdateRunspaceAvailability(PipelineState.Disconnected, raiseEvent); return; } }
public PSTerminalStateException(PSInvocationState state, string message, Exception exception) : base(message, exception) { State = state; }
private bool IsFinished(PSInvocationState state) { return(state == PSInvocationState.Completed || state == PSInvocationState.Failed || state == PSInvocationState.Stopped); }
internal PSInvocationStateInfo(PSInvocationState state, Exception reason) { this.executionState = state; this.exceptionReason = reason; }
/// <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(); } }
internal InvalidPowerShellStateException(PSInvocationState currentState) : base(StringUtil.Format(PowerShellStrings.InvalidPowerShellStateGeneral, new object[0])) { this.currState = currentState; }
internal PSInvocationStateInfo(PipelineStateInfo pipelineStateInfo) { this.executionState = (PSInvocationState)pipelineStateInfo.State; this.exceptionReason = pipelineStateInfo.Reason; }
internal void UpdateStatus(PSInvocationState state, Collection<ErrorRecord> errors) { if ((errors == null || errors.Count == 0) && state == PSInvocationState.Completed) { this.Status = PipelineState.Completed; TraceHelper.Current.PipelineComplete(this.ID); return; } else { this.Status = PipelineState.Error; if (errors == null || errors.Count < 1) { TraceHelper.Current.OperationalPipelineError(this.ID, this.Command, 0, Resources.UnknownPipelineError); TraceHelper.Current.PipelineError(this.ID, this.Command, 0, Resources.UnknownPipelineError); return; } else { TraceHelper.Current.OperationalPipelineError(this.ID, this.Command, errors.Count, errors[0].ToString()); TraceHelper.Current.PipelineError(this.ID, this.Command, errors.Count, errors[0].ToString()); return; } } }
//MTH: This is done in a constructor and not a function to make sure the consumer either gets a working instance or no instance (null) at all. protected internal ExecutionResult(PowerShell psInstance, HashSet<VariablePlain> vars, PSDataCollection<PSObject> psOutput, Exception additionalException) { Successful = false; SuccessfulNoError = false; //It can happen that PSInstance is NULL if (psInstance != null) { _pipelineState = psInstance.InvocationStateInfo.State; //Check if we have an inner or outer exception if (additionalException == null && psInstance.InvocationStateInfo.Reason == null) { FailedException = null; } else { //At least one excpetion has been detected. The additonal exception is raised by the the call of .EndInvoke() and is therefore considered to be more important. if (additionalException != null) { FailedException = additionalException; } else { FailedException = psInstance.InvocationStateInfo.Reason; } } } else { //PSInstance is null - execution can not be successful in this case _pipelineState = PSInvocationState.NotStarted; if (additionalException != null) { FailedException = additionalException; } else { //OK, this is strange. We do not have a PSInstance but also no AdditonalException. Set a default value. FailedException = new Exception("No detailed exception available"); } } //If FailedException is not set, we can check if the execution was successful if (FailedException == null) { //No exception detected, if State is Complete we have a succesful execution. if (psInstance.InvocationStateInfo.State == PSInvocationState.Completed) { Successful = true; //Now also check the ERROR stream. If there are no error reported, we also have a SuccessfulNoError status if (psInstance.Streams.Error != null) { if (psInstance.Streams.Error.Count == 0) { SuccessfulNoError = true; } } else { //Error stream is NULL, hence no problem SuccessfulNoError = true; } } } //MTH: Assign the stream collections to our internal properties or create empty one if they are null. //This will make using this object easier since the consumer does not need to check if the collections are null. StreamOutput = psOutput ?? new PSDataCollection<PSObject>(); //MTH: I didn't created a default value for all the StreamXXX properties here because PSDataCollection implements IDisposable. Therefore this odd looking code. if (psInstance == null) { //When PS Instance is NULL, set all values to default StreamError = new PSDataCollection<ErrorRecord>(); //http://msdn.microsoft.com/en-us/library/System.Management.Automation.ErrorRecord%28v=vs.85%29.aspx StreamWarning = new PSDataCollection<WarningRecord>(); //http://msdn.microsoft.com/en-us/library/system.management.automation.warningrecord%28v=vs.85%29.aspx StreamVerbose = new PSDataCollection<VerboseRecord>(); //http://msdn.microsoft.com/en-us/library/system.management.automation.verboserecord%28v=vs.85%29.aspx StreamDebug = new PSDataCollection<DebugRecord>(); //http://msdn.microsoft.com/en-us/library/system.management.automation.debugrecord%28v=vs.85%29.aspx //Set the variables to the same collection which was passed in Variables = vars; } else { //PSInstance is not null, so we can check the streams StreamError = psInstance.Streams.Error ?? new PSDataCollection<ErrorRecord>(); StreamWarning = psInstance.Streams.Warning ?? new PSDataCollection<WarningRecord>(); StreamVerbose = psInstance.Streams.Verbose ?? new PSDataCollection<VerboseRecord>(); StreamDebug = psInstance.Streams.Debug ?? new PSDataCollection<DebugRecord>(); //Return the current value of the Variables that were passed in. Variables = new HashSet<VariablePlain>(); if (vars.Count > 0) { foreach (VariablePlain var in vars) { //If the value was marked as ReadOnly, we simply take it from the original hashset because PowerShell can't change it anyway if (var.ReadOnly) { Variables.Add(var); } else { //The variable could have been changed by the script, so retrieve it from PowerShell /* MTH: There are two functions to read variables from PowerShell: * PSVariable psv = PSInstance.Runspace.SessionStateProxy.PSVariable.Get("aTestVar"); //Docs: http://msdn.microsoft.com/en-us/library/system.management.automation.runspaces.sessionstateproxy.psvariable%28v=vs.85%29.aspx * Object obj = PSInstance.Runspace.SessionStateProxy.GetVariable("aTestVar"); //Docs: http://msdn.microsoft.com/en-us/library/system.management.automation.runspaces.sessionstateproxy.getvariable%28v=vs.85%29.aspx * I assume that the second one is the short-circuit version of the first one. Since we only want the value, we use it. */ Object value = psInstance.Runspace.SessionStateProxy.GetVariable(var.Name); VariablePlain new_var = new VariablePlain(var.Name, value); Variables.Add(new_var); } } } } }
internal void SetState(PSInvocationState newState, Exception reason) { PSInvocationState notStarted = PSInvocationState.NotStarted; bool flag = false; lock (this.syncObject) { switch (this.stateOfSteppablePipeline) { case PSInvocationState.NotStarted: goto Label_00C7; case PSInvocationState.Running: switch (newState) { case PSInvocationState.NotStarted: throw new InvalidOperationException(); case PSInvocationState.Stopping: goto Label_0091; case PSInvocationState.Stopped: case PSInvocationState.Completed: case PSInvocationState.Failed: goto Label_0095; } goto Label_00C7; case PSInvocationState.Stopping: switch (newState) { case PSInvocationState.Stopped: goto Label_00BB; case PSInvocationState.Completed: case PSInvocationState.Failed: goto Label_00B5; } throw new InvalidOperationException(); default: goto Label_00C7; } notStarted = newState; goto Label_00C7; Label_0091: notStarted = newState; goto Label_00C7; Label_0095: notStarted = newState; flag = true; goto Label_00C7; Label_00B5: notStarted = PSInvocationState.Stopped; flag = true; goto Label_00C7; Label_00BB: notStarted = newState; flag = true; Label_00C7: this.stateOfSteppablePipeline = notStarted; } if (flag) { this.dsHandler.SendStateChangedInformationToClient(new PSInvocationStateInfo(notStarted, reason)); } if (((this.stateOfSteppablePipeline == PSInvocationState.Completed) || (this.stateOfSteppablePipeline == PSInvocationState.Stopped)) || (this.stateOfSteppablePipeline == PSInvocationState.Failed)) { this.dsHandler.RaiseRemoveAssociationEvent(); } }
private bool IsFinished(PSInvocationState state) { if ((state != PSInvocationState.Completed) && (state != PSInvocationState.Failed)) { return (state == PSInvocationState.Stopped); } return true; }
internal void Start() { this.stateOfSteppablePipeline = PSInvocationState.Running; this.eventSubscriber.FireStartSteppablePipeline(this); if (this.powershellInput != null) { this.powershellInput.Pulse(); } }
//MTH: This is done in a constructor and not a function to make sure the consumer either gets a working instance or no instance (null) at all. protected internal ExecutionResult(PowerShell psInstance, HashSet <VariablePlain> vars, PSDataCollection <PSObject> psOutput, Exception additionalException) { Successful = false; SuccessfulNoError = false; //It can happen that PSInstance is NULL if (psInstance != null) { _pipelineState = psInstance.InvocationStateInfo.State; //Check if we have an inner or outer exception if (additionalException == null && psInstance.InvocationStateInfo.Reason == null) { FailedException = null; } else { //At least one excpetion has been detected. The additonal exception is raised by the the call of .EndInvoke() and is therefore considered to be more important. if (additionalException != null) { FailedException = additionalException; } else { FailedException = psInstance.InvocationStateInfo.Reason; } } } else { //PSInstance is null - execution can not be successful in this case _pipelineState = PSInvocationState.NotStarted; if (additionalException != null) { FailedException = additionalException; } else { //OK, this is strange. We do not have a PSInstance but also no AdditonalException. Set a default value. FailedException = new Exception("No detailed exception available"); } } //If FailedException is not set, we can check if the execution was successful if (FailedException == null) { //No exception detected, if State is Complete we have a succesful execution. if (psInstance.InvocationStateInfo.State == PSInvocationState.Completed) { Successful = true; //Now also check the ERROR stream. If there are no error reported, we also have a SuccessfulNoError status if (psInstance.Streams.Error != null) { if (psInstance.Streams.Error.Count == 0) { SuccessfulNoError = true; } } else { //Error stream is NULL, hence no problem SuccessfulNoError = true; } } } //MTH: Assign the stream collections to our internal properties or create empty one if they are null. //This will make using this object easier since the consumer does not need to check if the collections are null. StreamOutput = psOutput ?? new PSDataCollection <PSObject>(); //MTH: I didn't created a default value for all the StreamXXX properties here because PSDataCollection implements IDisposable. Therefore this odd looking code. if (psInstance == null) { //When PS Instance is NULL, set all values to default StreamError = new PSDataCollection <ErrorRecord>(); //http://msdn.microsoft.com/en-us/library/System.Management.Automation.ErrorRecord%28v=vs.85%29.aspx StreamWarning = new PSDataCollection <WarningRecord>(); //http://msdn.microsoft.com/en-us/library/system.management.automation.warningrecord%28v=vs.85%29.aspx StreamVerbose = new PSDataCollection <VerboseRecord>(); //http://msdn.microsoft.com/en-us/library/system.management.automation.verboserecord%28v=vs.85%29.aspx StreamDebug = new PSDataCollection <DebugRecord>(); //http://msdn.microsoft.com/en-us/library/system.management.automation.debugrecord%28v=vs.85%29.aspx //Set the variables to the same collection which was passed in Variables = vars; } else { //PSInstance is not null, so we can check the streams StreamError = psInstance.Streams.Error ?? new PSDataCollection <ErrorRecord>(); StreamWarning = psInstance.Streams.Warning ?? new PSDataCollection <WarningRecord>(); StreamVerbose = psInstance.Streams.Verbose ?? new PSDataCollection <VerboseRecord>(); StreamDebug = psInstance.Streams.Debug ?? new PSDataCollection <DebugRecord>(); //Return the current value of the Variables that were passed in. Variables = new HashSet <VariablePlain>(); if (vars.Count > 0) { foreach (VariablePlain var in vars) { //If the value was marked as ReadOnly, we simply take it from the original hashset because PowerShell can't change it anyway if (var.ReadOnly) { Variables.Add(var); } else { //The variable could have been changed by the script, so retrieve it from PowerShell /* MTH: There are two functions to read variables from PowerShell: * PSVariable psv = PSInstance.Runspace.SessionStateProxy.PSVariable.Get("aTestVar"); //Docs: http://msdn.microsoft.com/en-us/library/system.management.automation.runspaces.sessionstateproxy.psvariable%28v=vs.85%29.aspx * Object obj = PSInstance.Runspace.SessionStateProxy.GetVariable("aTestVar"); //Docs: http://msdn.microsoft.com/en-us/library/system.management.automation.runspaces.sessionstateproxy.getvariable%28v=vs.85%29.aspx * I assume that the second one is the short-circuit version of the first one. Since we only want the value, we use it. */ Object value = psInstance.Runspace.SessionStateProxy.GetVariable(var.Name); VariablePlain new_var = new VariablePlain(var.Name, value); Variables.Add(new_var); } } } } }
private bool IsFinished(PSInvocationState state) { return (state == PSInvocationState.Completed || state == PSInvocationState.Failed || state == PSInvocationState.Stopped); }
internal PSInvocationStateInfo(PipelineStateInfo pipelineStateInfo) { this.executionState = (PSInvocationState) pipelineStateInfo.State; this.exceptionReason = pipelineStateInfo.Reason; }
internal PSInvocationStateInfo(PSInvocationState state, Exception reason) { throw new NotImplementedException(); }
/// <summary> /// Handle state changed information from PowerShell /// and send it to the client /// </summary> /// <param name="sender">sender of this event</param> /// <param name="eventArgs">arguments describing state changed /// information for this powershell</param> private void HandlePowerShellInvocationStateChanged(object sender, PSInvocationStateChangedEventArgs eventArgs) { PSInvocationState state = eventArgs.InvocationStateInfo.State; switch (state) { case PSInvocationState.Completed: case PSInvocationState.Failed: case PSInvocationState.Stopped: { if (LocalPowerShell.RunningExtraCommands) { // If completed successfully then allow extra commands to run. if (state == PSInvocationState.Completed) { return; } // For failed or stopped state, extra commands cannot run and // we allow this command invocation to finish. } // send the remaining data before sending in // state information. This is required because // the client side runspace pool will remove // the association with the client side powershell // once the powershell reaches a terminal state. // If the association is removed, then any data // sent to the powershell will be discarded by // the runspace pool data structure handler on the client side SendRemainingData(); if (state == PSInvocationState.Completed && (_extraPowerShell != null) && !_extraPowerShellAlreadyScheduled) { _extraPowerShellAlreadyScheduled = true; Start(false); } else { DataStructureHandler.RaiseRemoveAssociationEvent(); // send the state change notification to the client DataStructureHandler.SendStateChangedInformationToClient( eventArgs.InvocationStateInfo); UnregisterPowerShellEventHandlers(LocalPowerShell); if (_extraPowerShell != null) { UnregisterPowerShellEventHandlers(_extraPowerShell); } UnregisterDataStructureHandlerEventHandlers(DataStructureHandler); UnregisterPipelineOutputEventHandlers(_localPowerShellOutput); // BUGBUG: currently the local powershell cannot // be disposed as raising the events is // not done towards the end. Need to fix // powershell in order to get this enabled //localPowerShell.Dispose(); } } break; case PSInvocationState.Stopping: { // abort all pending host calls _remoteHost.ServerMethodExecutor.AbortAllCalls(); } break; } }
/// <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; } }
public PSTerminalStateException(PSInvocationState state) : base() { State = state; }
internal InvalidPowerShellStateException(PSInvocationState currentState) : base(ResourceManagerCache.FormatResourceString("PowerShellStrings", "InvalidPowerShellStateGeneral")) { using (InvalidPowerShellStateException.tracer.TraceConstructor((object)this)) this.currState = currentState; }