Team Ai
Datasetpublic

MegaBites-AI/Windows-powershell

sourceHugging Facemitupdated 6mo agoView on Hugging Face
0likes372downloads
Pipeline.cs741 linesDownload Raw Back to hostifaces
1// Copyright (c) Microsoft Corporation.2// Licensed under the MIT License.3 4using System.Collections;5using System.Collections.ObjectModel;6using System.Management.Automation.Internal;7using System.Runtime.Serialization;8using System.Threading;9 10using Dbg = System.Management.Automation.Diagnostics;11 12namespace System.Management.Automation.Runspaces13{14    #region Exceptions15    /// <summary>16    /// Defines exception which is thrown when state of the pipeline is different17    /// from expected state.18    /// </summary>19    public class InvalidPipelineStateException : SystemException20    {21        /// <summary>22        /// Initializes a new instance of the InvalidPipelineStateException class.23        /// </summary>24        public InvalidPipelineStateException()25            : base(StringUtil.Format(RunspaceStrings.InvalidPipelineStateStateGeneral))26        {27        }28 29        /// <summary>30        /// Initializes a new instance of the InvalidPipelineStateException class31        /// with a specified error message.32        /// </summary>33        /// <param name="message">34        /// The error message that explains the reason for the exception.35        /// </param>36        public InvalidPipelineStateException(string message)37        : base(message)38        {39        }40 41        /// <summary>42        /// Initializes a new instance of the InvalidPipelineStateException class43        /// with a specified error message and a reference to the inner exception that is the cause of this exception.44        /// </summary>45        /// <param name="message">46        /// The error message that explains the reason for the exception.47        /// </param>48        /// <param name="innerException">49        /// The exception that is the cause of the current exception.50        /// </param>51        public InvalidPipelineStateException(string message, Exception innerException)52        : base(message, innerException)53        {54        }55 56        /// <summary>57        /// Initializes a new instance of the InvalidPipelineStateException and defines value of58        /// CurrentState and ExpectedState.59        /// </summary>60        /// <param name="message">The error message that explains the reason for the exception.61        /// </param>62        /// <param name="currentState">Current state of pipeline.</param>63        /// <param name="expectedState">Expected state of pipeline.</param>64        internal InvalidPipelineStateException(string message, PipelineState currentState, PipelineState expectedState)65        : base(message)66        {67            _expectedState = expectedState;68            _currentState = currentState;69        }70 71        #region ISerializable Members72 73        // 2005/04/20-JonN No need to implement GetObjectData74        // if all fields are static or [NonSerialized]75 76        /// <summary>77        /// Initializes a new instance of the <see cref="InvalidPipelineStateException"/>78        ///  class with serialized data.79        /// </summary>80        /// <param name="info">81        /// The <see cref="SerializationInfo"/> that holds the serialized object82        /// data about the exception being thrown.83        /// </param>84        /// <param name="context">85        /// The <see cref="StreamingContext"/> that contains contextual information86        /// about the source or destination.87        /// </param>88        [Obsolete("Legacy serialization support is deprecated since .NET 8", DiagnosticId = "SYSLIB0051")]89        private InvalidPipelineStateException(SerializationInfo info, StreamingContext context)90        {91            throw new NotSupportedException();92        }93 94        #endregion95 96        /// <summary>97        /// Gets CurrentState of the pipeline.98        /// </summary>99        public PipelineState CurrentState100        {101            get { return _currentState; }102        }103 104        /// <summary>105        /// Gets ExpectedState of the pipeline.106        /// </summary>107        public PipelineState ExpectedState108        {109            get { return _expectedState; }110        }111 112        /// <summary>113        /// State of pipeline when exception was thrown.114        /// </summary>115        [NonSerialized]116        private readonly PipelineState _currentState = 0;117 118        /// <summary>119        /// States of the pipeline expected in method which throws this exception.120        /// </summary>121        [NonSerialized]122        private readonly PipelineState _expectedState = 0;123    }124 125    #endregion Exceptions126 127    #region PipelineState128 129    /// <summary>130    /// Enumerated type defining the state of the Pipeline.131    /// </summary>132    public enum PipelineState133    {134        /// <summary>135        /// The pipeline has not been started.136        /// </summary>137        NotStarted = 0,138        /// <summary>139        /// The pipeline is executing.140        /// </summary>141        Running = 1,142        /// <summary>143        /// The pipeline is stoping execution.144        /// </summary>145        Stopping = 2,146        /// <summary>147        /// The pipeline is completed due to a stop request.148        /// </summary>149        Stopped = 3,150        /// <summary>151        /// The pipeline has completed.152        /// </summary>153        Completed = 4,154        /// <summary>155        /// The pipeline completed abnormally due to an error.156        /// </summary>157        Failed = 5,158        /// <summary>159        /// The pipeline is disconnected from remote running command.160        /// </summary>161        Disconnected = 6162    }163 164    /// <summary>165    /// Type which has information about PipelineState and Exception166    /// associated with PipelineState.167    /// </summary>168    public sealed class PipelineStateInfo169    {170        #region constructors171 172        /// <summary>173        /// Constructor for state changes not resulting from an error.174        /// </summary>175        /// <param name="state">Execution state.</param>176        internal PipelineStateInfo(PipelineState state)177            : this(state, null)178        {179        }180 181        /// <summary>182        /// Constructor for state changes with an optional error.183        /// </summary>184        /// <param name="state">The new state.</param>185        /// <param name="reason">A non-null exception if the state change was186        /// caused by an error,otherwise; null.187        /// </param>188        internal PipelineStateInfo(PipelineState state, Exception reason)189        {190            State = state;191            Reason = reason;192        }193 194        /// <summary>195        /// Copy constructor to support cloning.196        /// </summary>197        /// <param name="pipelineStateInfo">Source information.</param>198        /// <throws>199        /// ArgumentNullException when <paramref name="pipelineStateInfo"/> is null.200        /// </throws>201        internal PipelineStateInfo(PipelineStateInfo pipelineStateInfo)202        {203            Dbg.Assert(pipelineStateInfo != null, "caller should validate the parameter");204 205            State = pipelineStateInfo.State;206            Reason = pipelineStateInfo.Reason;207        }208 209        #endregion constructors210 211        #region public_properties212 213        /// <summary>214        /// The state of the runspace.215        /// </summary>216        /// <remarks>217        /// This value indicates the state of the pipeline after the change.218        /// </remarks>219        public PipelineState State { get; }220 221        /// <summary>222        /// The reason for the state change, if caused by an error.223        /// </summary>224        /// <remarks>225        /// The value of this property is non-null if the state226        /// changed due to an error. Otherwise, the value of this227        /// property is null.228        /// </remarks>229        public Exception Reason { get; }230 231        #endregion public_properties232 233        /// <summary>234        /// Clones this object.235        /// </summary>236        /// <returns>Cloned object.</returns>237        internal PipelineStateInfo Clone()238        {239            return new PipelineStateInfo(this);240        }241    }242 243    /// <summary>244    /// Event arguments passed to PipelineStateEvent handlers245    /// <see cref="Pipeline.StateChanged"/> event.246    /// </summary>247    public sealed class PipelineStateEventArgs : EventArgs248    {249        #region constructors250 251        /// <summary>252        /// Constructor PipelineStateEventArgs from PipelineStateInfo.253        /// </summary>254        /// <param name="pipelineStateInfo">The current state of the255        /// pipeline.</param>256        /// <throws>257        /// ArgumentNullException when <paramref name="pipelineStateInfo"/> is null.258        /// </throws>259        internal PipelineStateEventArgs(PipelineStateInfo pipelineStateInfo)260        {261            Dbg.Assert(pipelineStateInfo != null, "caller should validate the parameter");262            PipelineStateInfo = pipelineStateInfo;263        }264 265        #endregion constructors266 267        #region public_properties268 269        /// <summary>270        /// Info about current state of pipeline.271        /// </summary>272        public PipelineStateInfo PipelineStateInfo { get; }273 274        #endregion public_properties275    }276    #endregion ExecutionState277 278    /// <summary>279    /// Defines a class which can be used to invoke a pipeline of commands.280    /// </summary>281    public abstract class Pipeline : IDisposable282    {283        #region constructor284 285        /// <summary>286        /// Explicit default constructor.287        /// </summary>288        internal Pipeline(Runspace runspace)289            : this(runspace, new CommandCollection())290        {291        }292 293        /// <summary>294        /// Constructor to initialize both Runspace and Command to invoke.295        /// Caller should make sure that "command" is not null.296        /// </summary>297        /// <param name="runspace">298        /// Runspace to use for the command invocation.299        /// </param>300        /// <param name="command">301        /// command to Invoke.302        /// Caller should make sure that "command" is not null.303        /// </param>304        internal Pipeline(Runspace runspace, CommandCollection command)305        {306            if (runspace == null)307            {308                PSTraceSource.NewArgumentNullException(nameof(runspace));309            }310            // This constructor is used only internally.311            // Caller should make sure the input is valid312            Dbg.Assert(command != null, "Command cannot be null");313            InstanceId = runspace.GeneratePipelineId();314            Commands = command;315 316            // Reset the AMSI session so that it is re-initialized317            // when the next script block is parsed.318            AmsiUtils.CloseSession();319        }320 321        #endregion constructor322 323        #region properties324 325        /// <summary>326        /// Gets the runspace this pipeline is created on.327        /// </summary>328        public abstract Runspace Runspace { get; }329 330        /// <summary>331        /// Gets the property which indicates if this pipeline is nested.332        /// </summary>333        public abstract bool IsNested { get; }334 335        /// <summary>336        /// Gets the property which indicates if this pipeline is a child pipeline.337        ///338        /// IsChild flag makes it possible for the pipeline to differentiate between339        /// a true v1 nested pipeline and the cmdlets calling cmdlets case. See bug340        /// 211462.341        /// </summary>342        internal virtual bool IsChild343        {344            get { return false; }345 346            set { }347        }348 349        /// <summary>350        /// Gets input writer for this pipeline.351        /// </summary>352        /// <remarks>353        /// When the caller calls Input.Write(), the caller writes to the354        /// input of the pipeline.  Thus, <paramref name="Input"/>355        /// is a PipelineWriter or "thing which can be written to".356        /// Note:Input must be closed after Pipeline.InvokeAsync for InvokeAsync to357        /// finish.358        /// </remarks>359        public abstract PipelineWriter Input { get; }360 361        /// <summary>362        /// Gets the output reader for this pipeline.363        /// </summary>364        /// <remarks>365        /// When the caller calls Output.Read(), the caller reads from the366        /// output of the pipeline.  Thus, <paramref name="Output"/>367        /// is a PipelineReader or "thing which can be read from".368        /// </remarks>369        public abstract PipelineReader<PSObject> Output { get; }370 371        /// <summary>372        /// Gets the error output reader for this pipeline.373        /// </summary>374        /// <remarks>375        /// When the caller calls Error.Read(), the caller reads from the376        /// output of the pipeline.  Thus, <paramref name="Error"/>377        /// is a PipelineReader or "thing which can be read from".378        ///379        /// This is the non-terminating error stream from the command.380        /// In this release, the objects read from this PipelineReader381        /// are PSObjects wrapping ErrorRecords.382        /// </remarks>383        public abstract PipelineReader<object> Error { get; }384 385        /// <summary>386        /// Gets Info about current state of the pipeline.387        /// </summary>388        /// <remarks>389        /// This value indicates the state of the pipeline after the change.390        /// </remarks>391        public abstract PipelineStateInfo PipelineStateInfo { get; }392 393        /// <summary>394        /// True if pipeline execution encountered and error.395        /// It will always be true if _reason is non-null396        /// since an exception occurred. For other error types,397        /// It has to be set manually.398        /// </summary>399        public virtual bool HadErrors400        {401            get { return _hadErrors; }402        }403 404        private bool _hadErrors;405 406        internal void SetHadErrors(bool status)407        {408            _hadErrors = _hadErrors || status;409        }410 411        /// <summary>412        /// Gets the unique identifier for this pipeline. This identifier is unique with in413        /// the scope of Runspace.414        /// </summary>415        public long InstanceId { get; }416 417        /// <summary>418        /// Gets the collection of commands for this pipeline.419        /// </summary>420        public CommandCollection Commands { get; private set; }421 422        /// <summary>423        /// If this property is true, SessionState is updated for this424        /// pipeline state.425        /// </summary>426        public bool SetPipelineSessionState { get; set; } = true;427 428        /// <summary>429        /// Settings for the pipeline invocation thread.430        /// </summary>431        internal PSInvocationSettings InvocationSettings { get; set; }432 433        /// <summary>434        /// If this flag is true, the commands in this Pipeline will redirect the global error output pipe435        /// (ExecutionContext.ShellFunctionErrorOutputPipe) to the command's error output pipe.436        ///437        /// When the global error output pipe is not set, $ErrorActionPreference is not checked and all438        /// errors are treated as terminating errors.439        ///440        /// On V1, the global error output pipe is redirected to the command's error output pipe only when441        /// it has already been redirected. The command-line host achieves this redirection by merging the442        /// error output into the output pipe so it checks $ErrorActionPreference all right. However, when443        /// the Pipeline class is used programmatically the global error output pipe is not set and the first444        /// error terminates the pipeline.445        ///446        /// This flag is used to force the redirection. By default it is false to maintain compatibility with447        /// V1, but the V2 hosting interface (PowerShell class) sets this flag to true to ensure the global448        /// error output pipe is always set and $ErrorActionPreference is checked when invoking the Pipeline.449        /// </summary>450        internal bool RedirectShellErrorOutputPipe { get; set; } = false;451 452        #endregion properties453 454        #region events455 456        /// <summary>457        /// Event raised when Pipeline's state changes.458        /// </summary>459        public abstract event EventHandler<PipelineStateEventArgs> StateChanged;460 461        #endregion events462 463        #region methods464 465        /// <summary>466        /// Invoke the pipeline, synchronously, returning the results as an array of467        /// objects.468        /// </summary>469        /// <remarks>If using synchronous invoke, do not close470        /// input objectWriter. Synchronous invoke will always close the input471        /// objectWriter.472        /// </remarks>473        /// <exception cref="InvalidOperationException">474        /// No command is added to pipeline475        /// </exception>476        /// <exception cref="InvalidPipelineStateException">477        /// PipelineState is not NotStarted.478        /// </exception>479        /// <exception cref="InvalidOperationException">480        /// 1) A pipeline is already executing. Pipeline cannot execute481        /// concurrently.482        /// 2) Attempt is made to invoke a nested pipeline directly. Nested483        /// pipeline must be invoked from a running pipeline.484        /// </exception>485        /// <exception cref="InvalidRunspaceStateException">486        /// RunspaceState is not Open487        /// </exception>488        /// <exception cref="ObjectDisposedException">489        /// Pipeline already disposed490        /// </exception>491        /// <exception cref="ScriptCallDepthException">492        /// The script recursed too deeply into script functions.493        /// There is a fixed limit on the depth of recursion.494        /// </exception>495        /// <exception cref="System.Security.SecurityException">496        /// A CLR security violation occurred.  Typically, this happens497        /// because the current CLR permissions do not allow adequate498        /// reflection access to a cmdlet assembly.499        /// </exception>500        /// <exception cref="RuntimeException">501        /// Pipeline.Invoke can throw a variety of exceptions derived502        /// from RuntimeException. The most likely of these exceptions503        /// are listed below.504        /// </exception>505        /// <exception cref="ParameterBindingException">506        /// One of more parameters or parameter values specified for507        /// a cmdlet are not valid, or mandatory parameters for a cmdlet508        /// were not specified.509        /// </exception>510        /// <exception cref="CmdletInvocationException">511        /// A cmdlet generated a terminating error.512        /// </exception>513        /// <exception cref="CmdletProviderInvocationException">514        /// A provider generated a terminating error.515        /// </exception>516        /// <exception cref="ActionPreferenceStopException">517        /// The ActionPreference.Stop or ActionPreference.Inquire policy518        /// triggered a terminating error.519        /// </exception>520        /// <exception cref="PipelineStoppedException">521        /// The pipeline was terminated asynchronously.522        /// </exception>523        /// <exception cref="MetadataException">524        /// If there is an error generating the metadata for dynamic parameters.525        /// </exception>526        public Collection<PSObject> Invoke()527        {528            return Invoke(null);529        }530 531        /// <summary>532        /// Invoke the pipeline, synchronously, returning the results as an array of objects.533        /// </summary>534        /// <param name="input">an array of input objects to pass to the pipeline.535        /// Array may be empty but may not be null</param>536        /// <returns>An array of zero or more result objects.</returns>537        /// <remarks>If using synchronous exectute, do not close538        /// input objectWriter. Synchronous invoke will always close the input539        /// objectWriter.540        /// </remarks>541        /// <exception cref="InvalidOperationException">542        /// No command is added to pipeline543        /// </exception>544        /// <exception cref="InvalidPipelineStateException">545        /// PipelineState is not NotStarted.546        /// </exception>547        /// <exception cref="InvalidOperationException">548        /// 1) A pipeline is already executing. Pipeline cannot execute549        /// concurrently.550        /// 2) Attempt is made to invoke a nested pipeline directly. Nested551        /// pipeline must be invoked from a running pipeline.552        /// </exception>553        /// <exception cref="InvalidRunspaceStateException">554        /// RunspaceState is not Open555        /// </exception>556        /// <exception cref="ObjectDisposedException">557        /// Pipeline already disposed558        /// </exception>559        /// <exception cref="ScriptCallDepthException">560        /// The script recursed too deeply into script functions.561        /// There is a fixed limit on the depth of recursion.562        /// </exception>563        /// <exception cref="System.Security.SecurityException">564        /// A CLR security violation occurred.  Typically, this happens565        /// because the current CLR permissions do not allow adequate566        /// reflection access to a cmdlet assembly.567        /// </exception>568        /// <exception cref="RuntimeException">569        /// Pipeline.Invoke can throw a variety of exceptions derived570        /// from RuntimeException. The most likely of these exceptions571        /// are listed below.572        /// </exception>573        /// <exception cref="ParameterBindingException">574        /// One of more parameters or parameter values specified for575        /// a cmdlet are not valid, or mandatory parameters for a cmdlet576        /// were not specified.577        /// </exception>578        /// <exception cref="CmdletInvocationException">579        /// A cmdlet generated a terminating error.580        /// </exception>581        /// <exception cref="CmdletProviderInvocationException">582        /// A provider generated a terminating error.583        /// </exception>584        /// <exception cref="ActionPreferenceStopException">585        /// The ActionPreference.Stop or ActionPreference.Inquire policy586        /// triggered a terminating error.587        /// </exception>588        /// <exception cref="PipelineStoppedException">589        /// The pipeline was terminated asynchronously.590        /// </exception>591        /// <exception cref="MetadataException">592        /// If there is an error generating the metadata for dynamic parameters.593        /// </exception>594        public abstract Collection<PSObject> Invoke(IEnumerable input);595 596        /// <summary>597        /// Invoke the pipeline asynchronously.598        /// </summary>599        /// <remarks>600        /// 1) Results are returned through the <see cref="Pipeline.Output"/> reader.601        /// 2) When pipeline is invoked using InvokeAsync, invocation doesn't602        /// finish until Input to pipeline is closed. Caller of InvokeAsync must close603        /// the input pipe after all input has been written to input pipe. Input pipe604        /// is closed by calling Pipeline.Input.Close();605        ///606        /// If you want this pipeline to execute as a standalone command607        /// (that is, using command-line parameters only),608        /// be sure to call Pipeline.Input.Close() before calling609        /// InvokeAsync().  Otherwise, the command will be executed610        /// as though it had external input.  If you observe that the611        /// command isn't doing anything, this may be the reason.612        /// </remarks>613        /// <exception cref="InvalidOperationException">614        /// No command is added to pipeline615        /// </exception>616        /// <exception cref="InvalidPipelineStateException">617        /// PipelineState is not NotStarted.618        /// </exception>619        /// <exception cref="InvalidOperationException">620        /// 1) A pipeline is already executing. Pipeline cannot execute621        /// concurrently.622        /// 2) InvokeAsync is called on nested pipeline. Nested pipeline623        /// cannot be executed Asynchronously.624        /// </exception>625        /// <exception cref="InvalidRunspaceStateException">626        /// RunspaceState is not Open627        /// </exception>628        /// <exception cref="ObjectDisposedException">629        /// Pipeline already disposed630        /// </exception>631        public abstract void InvokeAsync();632 633        /// <summary>634        /// Synchronous call to stop the running pipeline.635        /// </summary>636        public abstract void Stop();637 638        /// <summary>639        /// Asynchronous call to stop the running pipeline.640        /// </summary>641        public abstract void StopAsync();642 643        /// <summary>644        /// Creates a new <see cref="Pipeline"/> that is a copy of the current instance.645        /// </summary>646        /// <returns>A new <see cref="Pipeline"/> that is a copy of this instance.</returns>647        public abstract Pipeline Copy();648 649        /// <summary>650        /// Connects synchronously to a running command on a remote server.651        /// The pipeline object must be in the disconnected state.652        /// </summary>653        /// <returns>A collection of result objects.</returns>654        public abstract Collection<PSObject> Connect();655 656        /// <summary>657        /// Connects asynchronously to a running command on a remote server.658        /// </summary>659        public abstract void ConnectAsync();660 661        /// <summary>662        /// Sets the command collection.663        /// </summary>664        /// <param name="commands">Command collection to set.</param>665        /// <remarks>called by ClientRemotePipeline</remarks>666        internal void SetCommandCollection(CommandCollection commands)667        {668            Commands = commands;669        }670 671        /// <summary>672        /// Sets the history string to the one that is specified.673        /// </summary>674        /// <param name="historyString">History string to set.</param>675        internal abstract void SetHistoryString(string historyString);676 677        /// <summary>678        /// Invokes a remote command and immediately disconnects if679        /// transport layer supports it.680        /// </summary>681        internal abstract void InvokeAsyncAndDisconnect();682 683        #endregion methods684 685        #region Remote data drain/block methods686 687        /// <summary>688        /// Blocks data arriving from remote session.689        /// </summary>690        internal virtual void SuspendIncomingData()691        {692            throw new PSNotImplementedException();693        }694 695        /// <summary>696        /// Resumes data arrive from remote session.697        /// </summary>698        internal virtual void ResumeIncomingData()699        {700            throw new PSNotImplementedException();701        }702 703        /// <summary>704        /// Blocking call that waits until the current remote data705        /// queue is empty.706        /// </summary>707        internal virtual void DrainIncomingData()708        {709            throw new PSNotImplementedException();710        }711 712        #endregion713 714        #region IDisposable Members715 716        /// <summary>717        /// Disposes the pipeline. If pipeline is running, dispose first718        /// stops the pipeline.719        /// </summary>720        public721        void722        Dispose()723        {724            Dispose(!IsChild);725            GC.SuppressFinalize(this);726        }727 728        /// <summary>729        /// Protected dispose which can be overridden by derived classes.730        /// </summary>731        /// <param name="disposing"></param>732        protected virtual733        void734        Dispose(bool disposing)735        {736        }737 738        #endregion IDisposable Members739    }740}741