public override Collection <PSObject> Invoke(IEnumerable input)
{
// TODO: run the pipeline on another thread and wait for the completion
// TODO: nested pipelines: make sure we are running in the same thread as another pipeline, because
// nested pipelines aren't allowed to run in their own thread. This ensures that there is a "parent" pipeline
Input.Write(input, true);
// in a pipeline, the first command enters *always* the ProcessRecord phase, the following commands only
// if the previous command generated output. To make sure the first command enters that phase, add null
// if nothing else is in the input stream
if (_inputStream.Count == 0)
{
Input.Write(null);
}
string errorId = "BuildingPipelineProcessorFailed";
ExecutionContext context = _runspace.ExecutionContext.Clone();
RerouteExecutionContext(context);
try
{
if (!_pipelineStateInfo.State.Equals(PipelineState.NotStarted))
{
throw new InvalidPipelineStateException("Pipeline cannot be started",
_pipelineStateInfo.State, PipelineState.NotStarted);
}
var pipelineProcessor = BuildPipelineProcessor(context);
_runspace.AddRunningPipeline(this);
SetPipelineState(PipelineState.Running);
errorId = "TerminatingError";
pipelineProcessor.Execute(context);
SetPipelineState(PipelineState.Completed);
}
catch (ExitException ex)
{
// Toplevel pipeline
if (!IsNested)
{
_runspace.PSHost.SetShouldExit(ex.ExitCode);
}
else
{
// nested pipelines propagate the exit command
throw;
}
}
catch (Exception ex)
{
// in case of throw statement, parse error, or "ThrowTerminatingError"
// just add to error variable and rethrow that thing
var errorRecord = (ex is IContainsErrorRecord) ?
((IContainsErrorRecord)ex).ErrorRecord : new ErrorRecord(ex, errorId, ErrorCategory.InvalidOperation, null);
context.AddToErrorVariable(errorRecord);
context.SetVariable("global:?", false); // last command was definitely not successfull
throw;
}
_runspace.RemoveRunningPipeline(this);
return(Output.NonBlockingRead());
}