/// <summary> /// Executes a PSCommand against the session's runspace and returns /// a collection of results of the expected type. /// </summary> /// <typeparam name="TResult">The expected result type.</typeparam> /// <param name="psCommand">The PSCommand to be executed.</param> /// <param name="sendOutputToHost"> /// If true, causes any output written during command execution to be written to the host. /// </param> /// <param name="sendErrorToHost"> /// If true, causes any errors encountered during command execution to be written to the host. /// </param> /// <returns> /// An awaitable Task which will provide results once the command /// execution completes. /// </returns> public async Task <IEnumerable <TResult> > ExecuteCommand <TResult>( PSCommand psCommand, bool sendOutputToHost = false, bool sendErrorToHost = true) { RunspaceHandle runspaceHandle = null; IEnumerable <TResult> executionResult = null; // If the debugger is active and the caller isn't on the pipeline // thread, send the command over to that thread to be executed. if (Thread.CurrentThread.ManagedThreadId != this.pipelineThreadId && this.pipelineExecutionTask != null) { Logger.Write(LogLevel.Verbose, "Passing command execution to pipeline thread."); PipelineExecutionRequest <TResult> executionRequest = new PipelineExecutionRequest <TResult>( this, psCommand, sendOutputToHost); // Send the pipeline execution request to the pipeline thread this.pipelineResultTask = new TaskCompletionSource <IPipelineExecutionRequest>(); this.pipelineExecutionTask.SetResult(executionRequest); await this.pipelineResultTask.Task; return(executionRequest.Results); } else { try { // Instruct PowerShell to send output and errors to the host if (sendOutputToHost) { psCommand.Commands[0].MergeMyResults( PipelineResultTypes.Error, PipelineResultTypes.Output); psCommand.Commands.Add( this.GetOutputCommand( endOfStatement: false)); } if (this.currentRunspace.RunspaceAvailability == RunspaceAvailability.AvailableForNestedCommand || this.debuggerStoppedTask != null) { Logger.Write( LogLevel.Verbose, string.Format( "Attempting to execute nested pipeline command(s):\r\n\r\n{0}", GetStringForPSCommand(psCommand))); executionResult = this.ExecuteCommandInDebugger <TResult>( psCommand, sendOutputToHost); } else { Logger.Write( LogLevel.Verbose, string.Format( "Attempting to execute command(s):\r\n\r\n{0}", GetStringForPSCommand(psCommand))); // Set the runspace runspaceHandle = await this.GetRunspaceHandle(); if (runspaceHandle.Runspace.RunspaceAvailability != RunspaceAvailability.AvailableForNestedCommand) { this.powerShell.Runspace = runspaceHandle.Runspace; } // Invoke the pipeline on a background thread // TODO: Use built-in async invocation! executionResult = await Task.Factory.StartNew <IEnumerable <TResult> >( () => { this.powerShell.Commands = psCommand; Collection <TResult> result = this.powerShell.Invoke <TResult>(); return(result); }, CancellationToken.None, // Might need a cancellation token TaskCreationOptions.None, TaskScheduler.Default ); if (this.powerShell.HadErrors) { string errorMessage = "Execution completed with errors:\r\n\r\n"; foreach (var error in this.powerShell.Streams.Error) { errorMessage += error.ToString() + "\r\n"; } Logger.Write(LogLevel.Error, errorMessage); } else { Logger.Write( LogLevel.Verbose, "Execution completed successfully."); } return(executionResult); } } catch (RuntimeException e) { Logger.Write( LogLevel.Error, "Runtime exception occurred while executing command:\r\n\r\n" + e.ToString()); if (sendErrorToHost) { // Write the error to the host this.WriteExceptionToHost(e); } } finally { // Get the new prompt before releasing the runspace handle if (sendOutputToHost) { // Write the prompt if (runspaceHandle != null) { this.WritePromptWithRunspace(runspaceHandle.Runspace); } else { this.WritePromptWithNestedPipeline(); } } // Dispose of the execution context if (runspaceHandle != null) { runspaceHandle.Dispose(); } } } return(executionResult); }
private async Task <IEnumerable <T> > ExecuteCommand <T>(PSCommand command, bool redirectOutput = false) { var result = default(IEnumerable <T>); if (Thread.CurrentThread.ManagedThreadId != _pipelineThreadId && _pipelineExecutionTask != null) { // Queue the execution since one task is already running. var executionRequest = new PipelineExecutionRequest <T>(this, command, redirectOutput); _pipelineResultTask = new TaskCompletionSource <IPipelineExecutionRequest>(); if (_pipelineExecutionTask.TrySetResult(executionRequest)) { await _pipelineResultTask.Task; return(executionRequest.Results); } return(null); } var scriptOutput = new PSDataCollection <PSObject>(); if (redirectOutput) { scriptOutput.DataAdded += (sender, args) => { // Stream script output to console. Execute.OnUIThread(() => { var output = IoC.Get <IOutput>(); foreach (var item in scriptOutput.ReadAll()) { output.AppendLine(item.ToString()); } }); }; } if (_runspace.RunspaceAvailability == RunspaceAvailability.AvailableForNestedCommand || _debuggerExecutionTask != null) { result = ExecuteCommandInDebugger <T>(command, redirectOutput); } else { result = await Task.Factory.StartNew <IEnumerable <T> >(() => { _powerShell.Commands = command; var executionResult = _powerShell.Invoke <T>(scriptOutput); return(executionResult); }, CancellationToken.None, TaskCreationOptions.None, TaskScheduler.Default ); } _powerShell?.Commands.Clear(); if (_powerShell == null || _powerShell.HadErrors) { return(null); } return(result); }
/// <summary> /// Executes a PSCommand against the session's runspace and returns /// a collection of results of the expected type. /// </summary> /// <typeparam name="TResult">The expected result type.</typeparam> /// <param name="psCommand">The PSCommand to be executed.</param> /// <param name="sendOutputToHost"> /// If true, causes any output written during command execution to be written to the host. /// </param> /// <returns> /// An awaitable Task which will provide results once the command /// execution completes. /// </returns> public async Task <IEnumerable <TResult> > ExecuteCommand <TResult>( PSCommand psCommand, bool sendOutputToHost = false) { // If the debugger is active and the caller isn't on the pipeline // thread, send the command over to that thread to be executed. if (Thread.CurrentThread.ManagedThreadId != this.pipelineThreadId && this.pipelineExecutionTask != null) { Logger.Write(LogLevel.Verbose, "Passing command execution to pipeline thread."); PipelineExecutionRequest <TResult> executionRequest = new PipelineExecutionRequest <TResult>( this, psCommand, sendOutputToHost); // Send the pipeline execution request to the pipeline thread this.pipelineResultTask = new TaskCompletionSource <IPipelineExecutionRequest>(); this.pipelineExecutionTask.SetResult(executionRequest); await this.pipelineResultTask.Task; return(executionRequest.Results); } else { try { // Instruct PowerShell to send output and errors to the host if (sendOutputToHost) { psCommand.Commands[0].MergeMyResults( PipelineResultTypes.Error, PipelineResultTypes.Output); psCommand.Commands.Add( this.GetOutputCommand( endOfStatement: false)); } if (this.currentRunspace.RunspaceAvailability == RunspaceAvailability.AvailableForNestedCommand || this.debuggerStoppedTask != null) { Logger.Write( LogLevel.Verbose, string.Format( "Attempting to execute nested pipeline command(s):\r\n\r\n{0}", GetStringForPSCommand(psCommand))); using (Pipeline pipeline = this.currentRunspace.CreateNestedPipeline()) { foreach (var command in psCommand.Commands) { pipeline.Commands.Add(command); } IEnumerable <TResult> result = pipeline .Invoke() .Select(pso => pso.BaseObject) .Cast <TResult>(); return(result); } } else { Logger.Write( LogLevel.Verbose, string.Format( "Attempting to execute command(s):\r\n\r\n{0}", GetStringForPSCommand(psCommand))); // Set the runspace var runspaceHandle = await this.GetRunspaceHandle(); if (runspaceHandle.Runspace.RunspaceAvailability != RunspaceAvailability.AvailableForNestedCommand) { this.powerShell.Runspace = runspaceHandle.Runspace; } // Invoke the pipeline on a background thread // TODO: Use built-in async invocation! var taskResult = await Task.Factory.StartNew <IEnumerable <TResult> >( () => { this.powerShell.Commands = psCommand; Collection <TResult> result = this.powerShell.Invoke <TResult>(); return(result); }, CancellationToken.None, // Might need a cancellation token TaskCreationOptions.None, TaskScheduler.Default ); runspaceHandle.Dispose(); if (this.powerShell.HadErrors) { // TODO: Find a good way to extract errors! Logger.Write( LogLevel.Error, "Execution completed with errors."); } else { Logger.Write( LogLevel.Verbose, "Execution completed successfully."); } bool hadErrors = this.powerShell.HadErrors; return(taskResult); } } catch (RuntimeException e) { // TODO: Return an error Logger.Write( LogLevel.Error, "Exception occurred while attempting to execute command:\r\n\r\n" + e.ToString()); } } // TODO: Better result return(null); }