Team Ai
Datasetpublic

MegaBites-AI/Windows-powershell

sourceHugging Facemitupdated 6mo agoView on Hugging Face
0likes372downloads
Job2.cs2187 linesDownload Raw Back to client
1// Copyright (c) Microsoft Corporation.2// Licensed under the MIT License.3 4using System.Collections.Generic;5using System.ComponentModel;6using System.Diagnostics.CodeAnalysis;7using System.Linq;8using System.Management.Automation.Language;9using System.Management.Automation.Runspaces;10using System.Management.Automation.Tracing;11using System.Runtime.Serialization;12using System.Text;13using System.Threading;14 15using Dbg = System.Management.Automation.Diagnostics;16 17// Stops compiler from warning about unknown warnings18#pragma warning disable 1634, 169119 20namespace System.Management.Automation21{22    #region PowerShell v3 Job Extensions23 24    /// <summary>25    /// New base class for a job that provides extended state26    /// management functionality on the job. Since the existing27    /// Job class is an abstract class and there are existing28    /// implementations of the same, it is required to have a29    /// new class that will have the extended functionality. This30    /// is to ensure that backwards compatibility is maintained31    ///32    /// However, this class will derive from the existing Job33    /// class. The option of deprecating the existing class was34    /// considered as well. In order to maintain backwards35    /// compatibility of PowerShell job cmdlets they will have36    /// to work with the old interface and hence deprecating37    /// the Job class did not add any benefit rather than38    /// deriving from the same.39    /// </summary>40    /// <remarks>The following are some of the notes about41    /// why the asynchronous operations are provided this way42    /// in this class. There are two possible options in which43    /// asynchronous support can be provided:44    ///     1. Classical pattern (Begin and End)45    ///     2. Event based pattern46    ///47    /// Although the PowerShell API uses the classical pattern48    /// and we would like the Job API and PowerShell API to be49    /// as close as possible, the classical pattern is inherently50    /// complex to use.</remarks>51    public abstract class Job2 : Job52    {53        #region Private Members54 55        /// <summary>56        /// These are the parameters that can be used by a job57        /// implementation when they want to specify parameters58        /// to start a job.59        /// </summary>60        private List<CommandParameterCollection> _parameters;61 62        /// <summary>63        /// Object that will be used for thread synchronization.64        /// </summary>65        private readonly object _syncobject = new object();66 67        private const int StartJobOperation = 1;68        private const int StopJobOperation = 2;69        private const int SuspendJobOperation = 3;70        private const int ResumeJobOperation = 4;71        private const int UnblockJobOperation = 5;72 73        private readonly PowerShellTraceSource _tracer = PowerShellTraceSourceFactory.GetTraceSource();74 75        #endregion Private Members76 77        #region Properties78 79        /// <summary>80        /// Parameters to be used to start a job.81        /// This is a property because CommandParameterCollection82        /// does not have a public constructor. Hence the83        /// infrastructure creates an instance and provides84        /// it for the implementations to use.85        /// </summary>86        [SuppressMessage("Microsoft.Usage", "CA2227:CollectionPropertiesShouldBeReadOnly")]87        [SuppressMessage("Microsoft.Design", "CA1002:DoNotExposeGenericLists")]88        public List<CommandParameterCollection> StartParameters89        {90            get91            {92                if (_parameters == null)93                {94                    lock (_syncobject)95                    {96                        _parameters ??= new List<CommandParameterCollection>();97                    }98                }99 100                return _parameters;101            }102 103            set104            {105                if (value == null)106                {107                    throw PSTraceSource.NewArgumentNullException("value");108                }109 110                lock (_syncobject)111                {112                    _parameters = value;113                }114            }115        }116 117        /// <summary>118        /// </summary>119        protected object SyncRoot120        {121            get { return syncObject; }122        }123 124        #endregion Properties125 126        #region Protected Methods127 128        /// <summary>129        /// Default no argument constructor.130        /// </summary>131        protected Job2() : base() { }132 133        /// <summary>134        /// Constructor which will initialize the job135        /// with the associated command string.136        /// </summary>137        /// <param name="command">string representation138        /// of the command the job is running</param>139        protected Job2(string command) : base(command) { }140 141        /// <summary>142        /// Creates an instance of this class.143        /// </summary>144        /// <param name="command">Command invoked by this job object.</param>145        /// <param name="name">Friendly name for the job object.</param>146        protected Job2(string command, string name)147            : base(command, name)148        {149        }150 151        /// <summary>152        /// Creates an instance of this class.153        /// </summary>154        /// <param name="command">Command invoked by this job object.</param>155        /// <param name="name">Friendly name for the job object.</param>156        /// <param name="childJobs">Child jobs of this job object.</param>157        protected Job2(string command, string name, IList<Job> childJobs)158            : base(command, name, childJobs)159        {160        }161 162        /// <summary>163        /// Creates an instance of this class.164        /// </summary>165        /// <param name="command">Command invoked by this job object.</param>166        /// <param name="name">Friendly name for the job object.</param>167        /// <param name="token">JobIdentifier token used to assign Id and InstanceId.</param>168        protected Job2(string command, string name, JobIdentifier token)169            : base(command, name, token)170        {171        }172 173        /// <summary>174        /// Creates an instance of this class.175        /// </summary>176        /// <param name="command">Command string.</param>177        /// <param name="name">Friendly name for the job.</param>178        /// <param name="instanceId">Instance ID to allow job identification across sessions.</param>179        protected Job2(string command, string name, Guid instanceId)180            : base(command, name, instanceId)181        {182        }183 184        /// <summary>185        /// There is an internal method in Job which is not made186        /// public. In order to make this available to someone187        /// implementing a job it has to be added here. If the188        /// original method is made public it has changes of189        /// colliding with some implementation which may have190        /// added that method.191        /// </summary>192        /// <param name="state">State of the job.</param>193        /// <param name="reason">exception associated with the194        /// job entering this state</param>195        protected new void SetJobState(JobState state, Exception reason)196        {197            base.SetJobState(state, reason);198        }199 200        #endregion Protected Methods201 202        #region State Management203 204        /// <summary>205        /// Start a job. The job will be started with the parameters206        /// specified in StartParameters.207        /// </summary>208        /// <remarks>It is redundant to have a method named StartJob209        /// on a job class. However, this is done so as to avoid210        /// an FxCop violation "CA1716:IdentifiersShouldNotMatchKeywords"211        /// Stop and Resume are reserved keyworks in C# and hence cannot212        /// be used as method names. Therefore to be consistent it has213        /// been decided to use *Job in the name of the methods</remarks>214        public abstract void StartJob();215 216        /// <summary>217        /// Start a job asynchronously.218        /// </summary>219        public abstract void StartJobAsync();220 221        /// <summary>222        /// Event to be raise when the start job activity is completed.223        /// This event should not be raised for224        /// synchronous operation.225        /// </summary>226        public event EventHandler<AsyncCompletedEventArgs> StartJobCompleted;227 228        /// <summary>229        /// Method which can be extended or called by derived230        /// classes to raise the event when start of231        /// the job is completed.232        /// </summary>233        /// <param name="eventArgs">arguments describing234        /// an exception that is associated with the event</param>235        protected virtual void OnStartJobCompleted(AsyncCompletedEventArgs eventArgs)236        {237            RaiseCompletedHandler(StartJobOperation, eventArgs);238        }239 240        /// <summary>241        /// Method which can be extended or called by derived242        /// classes to raise the event when stopping a243        /// job is completed.244        /// </summary>245        /// <param name="eventArgs">argument describing246        /// an exception that is associated with the event</param>247        protected virtual void OnStopJobCompleted(AsyncCompletedEventArgs eventArgs)248        {249            RaiseCompletedHandler(StopJobOperation, eventArgs);250        }251 252        /// <summary>253        /// Method which can be extended or called by derived254        /// classes to raise the event when suspending a255        /// job is completed.256        /// </summary>257        /// <param name="eventArgs">argument describing258        /// an exception that is associated with the event</param>259        protected virtual void OnSuspendJobCompleted(AsyncCompletedEventArgs eventArgs)260        {261            RaiseCompletedHandler(SuspendJobOperation, eventArgs);262        }263 264        /// <summary>265        /// Method which can be extended or called by derived266        /// classes to raise the event when resuming a267        /// suspended job is completed.268        /// </summary>269        /// <param name="eventArgs">argument describing270        /// an exception that is associated with the event</param>271        protected virtual void OnResumeJobCompleted(AsyncCompletedEventArgs eventArgs)272        {273            RaiseCompletedHandler(ResumeJobOperation, eventArgs);274        }275 276        /// <summary>277        /// Method which can be extended or called by derived278        /// classes to raise the event when unblocking a279        /// blocked job is completed.280        /// </summary>281        /// <param name="eventArgs">argument describing282        /// an exception that is associated with the event</param>283        protected virtual void OnUnblockJobCompleted(AsyncCompletedEventArgs eventArgs)284        {285            RaiseCompletedHandler(UnblockJobOperation, eventArgs);286        }287 288        /// <summary>289        /// Raises the appropriate event based on the operation290        /// and the associated event arguments.291        /// </summary>292        /// <param name="operation">operation for which the event293        /// needs to be raised</param>294        /// <param name="eventArgs"></param>295        private void RaiseCompletedHandler(int operation, AsyncCompletedEventArgs eventArgs)296        {297            // Make a temporary copy of the event to avoid possibility of298            // a race condition if the last subscriber unsubscribes299            // immediately after the null check and before the event is raised.300            EventHandler<AsyncCompletedEventArgs> handler = null;301 302            switch (operation)303            {304                case StartJobOperation:305                    {306                        handler = StartJobCompleted;307                    }308 309                    break;310                case StopJobOperation:311                    {312                        handler = StopJobCompleted;313                    }314 315                    break;316                case SuspendJobOperation:317                    {318                        handler = SuspendJobCompleted;319                    }320 321                    break;322                case ResumeJobOperation:323                    {324                        handler = ResumeJobCompleted;325                    }326 327                    break;328                case UnblockJobOperation:329                    {330                        handler = UnblockJobCompleted;331                    }332 333                    break;334                default:335                    {336                        Dbg.Assert(false, "this condition should not be hit, check the value of operation that you passed");337                    }338 339                    break;340            }341#pragma warning disable 56500342            try343            {344                handler?.Invoke(this, eventArgs);345            }346            catch (Exception exception)347            {348                // errors in the handlers are not errors in the operation349                // silently ignore them350                _tracer.TraceException(exception);351            }352#pragma warning restore 56500353        }354 355        /// <summary>356        /// Stop a job asynchronously.357        /// </summary>358        public abstract void StopJobAsync();359 360        /// <summary>361        /// Event to be raised when the asynchronous stopping of a job362        /// is completed.This event should not be raised for363        /// synchronous operation.364        /// </summary>365        public event EventHandler<AsyncCompletedEventArgs> StopJobCompleted;366 367        /// <summary>368        /// Suspend a job.369        /// </summary>370        public abstract void SuspendJob();371 372        /// <summary>373        /// Asynchronously suspend a job.374        /// </summary>375        public abstract void SuspendJobAsync();376 377        /// <summary>378        /// This event should be raised whenever the asynchronous suspend of379        /// a job is completed. This event should not be raised for380        /// synchronous operation.381        /// </summary>382        public event EventHandler<AsyncCompletedEventArgs> SuspendJobCompleted;383 384        /// <summary>385        /// Resume a suspended job.386        /// </summary>387        public abstract void ResumeJob();388 389        /// <summary>390        /// Resume a suspended job asynchronously.391        /// </summary>392        public abstract void ResumeJobAsync();393 394        /// <summary>395        /// This event should be raised whenever the asynchronous resume of396        /// a suspended job is completed. This event should not be raised for397        /// synchronous operation.398        /// </summary>399        public event EventHandler<AsyncCompletedEventArgs> ResumeJobCompleted;400 401        /// <summary>402        /// Unblock a blocked job.403        /// </summary>404        public abstract void UnblockJob();405 406        /// <summary>407        /// Unblock a blocked job asynchronously.408        /// </summary>409        public abstract void UnblockJobAsync();410 411        /// <summary>412        /// StopJob.413        /// </summary>414        /// <param name="force"></param>415        /// <param name="reason"></param>416        public abstract void StopJob(bool force, string reason);417 418        /// <summary>419        /// StopJobAsync.420        /// </summary>421        /// <param name="force"></param>422        /// <param name="reason"></param>423        public abstract void StopJobAsync(bool force, string reason);424 425        /// <summary>426        /// SuspendJob.427        /// </summary>428        /// <param name="force"></param>429        /// <param name="reason"></param>430        public abstract void SuspendJob(bool force, string reason);431 432        /// <summary>433        /// SuspendJobAsync.434        /// </summary>435        /// <param name="force"></param>436        /// <param name="reason"></param>437        public abstract void SuspendJobAsync(bool force, string reason);438 439        /// <summary>440        /// This event should be raised whenever the asynchronous unblock441        /// of a blocked job is completed. This event should not be raised for442        /// synchronous operation.443        /// </summary>444        public event EventHandler<AsyncCompletedEventArgs> UnblockJobCompleted;445 446        #endregion State Management447    }448 449    /// <summary>450    /// Specifies the various thread options that can be used451    /// for the ThreadBasedJob.452    /// </summary>453    public enum JobThreadOptions454    {455        /// <summary>456        /// Use the default behavior, which is to use a457        /// ThreadPoolThread.458        /// </summary>459        Default = 0,460 461        /// <summary>462        /// Use a thread pool thread.463        /// </summary>464        UseThreadPoolThread = 1,465 466        /// <summary>467        /// Create a new thread everything and reuse.468        /// </summary>469        UseNewThread = 2,470    }471 472    /*/// <summary>473    /// This job will provide asynchronous behavior by running474    /// the user specified script block in a separate process.475    /// There will be options for running the scriptblock476    /// in a new process or an existing process.477    /// </summary>478    /// <remarks>Jobs for the out-of-process activity manager479    /// can be implemented using this interface</remarks>480    public abstract class ProcessBasedJob : Job2481    {482        public override void Start()483        {484            throw new NotImplementedException();485        }486 487        public override void StartAsync()488        {489            throw new NotImplementedException();490        }491    }*/492 493    /// <summary>494    /// Top level container job.495    /// </summary>496    public sealed class ContainerParentJob : Job2497    {498        #region Private Members499 500        private const string TraceClassName = "ContainerParentJob";501 502        private bool _moreData = true;503        private readonly object _syncObject = new object();504        private int _isDisposed = 0;505 506        private const int DisposedTrue = 1;507        private const int DisposedFalse = 0;508        // This variable is set to true if at least one child job failed.509 510        // count of number of child jobs which have finished511        private int _finishedChildJobsCount = 0;512 513        // count of number of child jobs which are blocked514        private int _blockedChildJobsCount = 0;515 516        // count of number of child jobs which are suspended517        private int _suspendedChildJobsCount = 0;518 519        // count of number of child jobs which are suspending520        private int _suspendingChildJobsCount = 0;521 522        // count of number of child jobs which failed523        private int _failedChildJobsCount = 0;524 525        // count of number of child jobs which stopped526        private int _stoppedChildJobsCount = 0;527 528        private readonly PowerShellTraceSource _tracer = PowerShellTraceSourceFactory.GetTraceSource();529        private readonly PSDataCollection<ErrorRecord> _executionError = new PSDataCollection<ErrorRecord>();530 531        private PSEventManager _eventManager;532 533        internal PSEventManager EventManager534        {535            get536            {537                return _eventManager;538            }539 540            set541            {542                _tracer.WriteMessage("Setting event manager for Job ", InstanceId);543                _eventManager = value;544            }545        }546 547        private ManualResetEvent _jobRunning;548 549        private ManualResetEvent JobRunning550        {551            get552            {553                if (_jobRunning == null)554                {555                    lock (_syncObject)556                    {557                        if (_jobRunning == null)558                        {559                            // this assert is required so that a wait handle560                            // is not created after the object is disposed561                            // which will result in a leak562                            AssertNotDisposed();563                            _jobRunning = new ManualResetEvent(false);564                        }565                    }566                }567 568                return _jobRunning;569            }570        }571 572        private ManualResetEvent _jobSuspendedOrAborted;573 574        private ManualResetEvent JobSuspendedOrAborted575        {576            get577            {578                if (_jobSuspendedOrAborted == null)579                {580                    lock (_syncObject)581                    {582                        if (_jobSuspendedOrAborted == null)583                        {584                            // this assert is required so that a wait handle585                            // is not created after the object is disposed586                            // which will result in a leak587                            AssertNotDisposed();588                            _jobSuspendedOrAborted = new ManualResetEvent(false);589                        }590                    }591                }592 593                return _jobSuspendedOrAborted;594            }595        }596 597        #endregion Private Members598 599        #region Constructors600 601        /// <summary>602        /// Create a container parent job with the603        /// specified command string and name.604        /// </summary>605        /// <param name="command">Command string.</param>606        /// <param name="name">Friendly name for display.</param>607        public ContainerParentJob(string command, string name)608            : base(command, name)609        {610            StateChanged += HandleMyStateChanged;611        }612 613        /// <summary>614        /// Create a container parent job with the615        /// specified command string.616        /// </summary>617        /// <param name="command">Command string.</param>618        public ContainerParentJob(string command)619            : base(command)620        {621            StateChanged += HandleMyStateChanged;622        }623 624        /// <summary>625        /// Create a container parent job with the626        /// specified command string.627        /// </summary>628        /// <param name="command">Command string.</param>629        /// <param name="name">Friendly name for the job.</param>630        /// <param name="jobId">JobIdentifier token that allows reuse of an Id and Instance Id.</param>631        public ContainerParentJob(string command, string name, JobIdentifier jobId)632            : base(command, name, jobId)633        {634            StateChanged += HandleMyStateChanged;635        }636 637        /// <summary>638        /// Create a container parent job with the639        /// specified command string.640        /// </summary>641        /// <param name="command">Command string.</param>642        /// <param name="name">Friendly name for the job.</param>643        /// <param name="instanceId">Instance ID to allow job identification across sessions.</param>644        public ContainerParentJob(string command, string name, Guid instanceId)645            : base(command, name, instanceId)646        {647            StateChanged += HandleMyStateChanged;648        }649 650        /// <summary>651        /// Create a container parent job with the652        /// specified command string.653        /// </summary>654        /// <param name="command">Command string.</param>655        /// <param name="name">Friendly name for the job.</param>656        /// <param name="jobId">JobIdentifier token that allows reuse of an Id and Instance Id.</param>657        /// <param name="jobType">Job type name.</param>658        public ContainerParentJob(string command, string name, JobIdentifier jobId, string jobType)659            : base(command, name, jobId)660        {661            PSJobTypeName = jobType;662            StateChanged += HandleMyStateChanged;663        }664 665        /// <summary>666        /// Create a container parent job with the667        /// specified command string.668        /// </summary>669        /// <param name="command">Command string.</param>670        /// <param name="name">Friendly name for the job.</param>671        /// <param name="instanceId">Instance ID to allow job identification across sessions.</param>672        /// <param name="jobType">Job type name.</param>673        public ContainerParentJob(string command, string name, Guid instanceId, string jobType)674            : base(command, name, instanceId)675        {676            PSJobTypeName = jobType;677            StateChanged += HandleMyStateChanged;678        }679 680        /// <summary>681        /// Create a container parent job with the specified command, name,682        /// job type strings.683        /// </summary>684        /// <param name="command">Command string.</param>685        /// <param name="name">Friendly name for the job.</param>686        /// <param name="jobType">Job type name.</param>687        public ContainerParentJob(string command, string name, string jobType)688            : base(command, name)689        {690            PSJobTypeName = jobType;691            StateChanged += HandleMyStateChanged;692        }693 694        #endregion Constructors695 696        internal PSDataCollection<ErrorRecord> ExecutionError { get { return _executionError; } }697 698        #region Public Methods699 700        /// <summary>701        /// Add a child job to the parent job.702        /// </summary>703        /// <param name="childJob">Child job to add.</param>704        /// <exception cref="ObjectDisposedException">Thrown if the job is disposed.</exception>705        /// <exception cref="ArgumentNullException">Thrown if child being added is null.</exception>706        public void AddChildJob(Job2 childJob)707        {708            AssertNotDisposed();709 710            ArgumentNullException.ThrowIfNull(childJob);711 712            _tracer.WriteMessage(TraceClassName, "AddChildJob", Guid.Empty, childJob, "Adding Child to Parent with InstanceId : ", InstanceId.ToString());713 714            JobStateInfo childJobStateInfo;715            lock (childJob.syncObject)716            {717                // Store job's state and subscribe to State Changed event. Locking here will718                // ensure that the jobstateinfo we get is the state before any state changed events are handled by ContainerParentJob.719                childJobStateInfo = childJob.JobStateInfo;720                childJob.StateChanged += HandleChildJobStateChanged;721            }722 723            ChildJobs.Add(childJob);724            ParentJobStateCalculation(new JobStateEventArgs(childJobStateInfo, new JobStateInfo(JobState.NotStarted)));725        }726 727        /// <summary>728        /// Indicates if more data is available.729        /// </summary>730        /// <remarks>731        /// This has more data if any of the child jobs have more data.732        /// </remarks>733        public override bool HasMoreData734        {735            get736            {737                // moreData is initially set to true, and it738                // will remain so until the async result739                // object has completed execution.740                if (_moreData && IsFinishedState(JobStateInfo.State))741                {742                    bool atleastOneChildHasMoreData = false;743 744                    for (int i = 0; i < ChildJobs.Count; i++)745                    {746                        if (ChildJobs[i].HasMoreData)747                        {748                            atleastOneChildHasMoreData = true;749                            break;750                        }751                    }752 753                    _moreData = atleastOneChildHasMoreData;754                }755 756                return _moreData;757            }758        }759 760        /// <summary>761        /// Message indicating status of the job.762        /// </summary>763        public override string StatusMessage764        {765            get766            {767                return ConstructStatusMessage();768            }769        }770 771        /// <summary>772        /// Starts all jobs.773        /// </summary>774        /// <exception cref="ObjectDisposedException">Thrown if job is disposed.</exception>775        public override void StartJob()776        {777            AssertNotDisposed();778            _tracer.WriteMessage(TraceClassName, "StartJob", Guid.Empty, this, "Entering method", null);779            s_structuredTracer.BeginContainerParentJobExecution(InstanceId);780 781            // If parent contains no child jobs then this method will not respond.  Throw error in this case.782            if (ChildJobs.Count == 0)783            {784                throw PSTraceSource.NewInvalidOperationException(RemotingErrorIdStrings.JobActionInvalidWithNoChildJobs);785            }786 787            foreach (Job2 job in this.ChildJobs)788            {789                if (job == null) throw PSTraceSource.NewInvalidOperationException(RemotingErrorIdStrings.JobActionInvalidWithNullChild);790            }791 792            // If there is only one child job, call the synchronous method on the child to avoid use of another thread.793            // If there are multiple, we can run them in parallel using the asynchronous versions.794            if (ChildJobs.Count == 1)795            {796                Job2 child = ChildJobs[0] as Job2;797                Dbg.Assert(child != null, "Job is null after initial null check");798#pragma warning disable 56500799                try800                {801                    _tracer.WriteMessage(TraceClassName, "StartJob", Guid.Empty, this,802                        "Single child job synchronously, child InstanceId: {0}", child.InstanceId.ToString());803                    child.StartJob();804                    JobRunning.WaitOne();805                }806                catch (Exception e)807                {808                    // These exceptions are thrown by third party code. Adding them here to the collection809                    // of execution errors to present consistent behavior of the object.810 811                    ExecutionError.Add(new ErrorRecord(e, "ContainerParentJobStartError",812                                                       ErrorCategory.InvalidResult, child));813                    _tracer.WriteMessage(TraceClassName, "StartJob", Guid.Empty, this,814                        "Single child job threw exception, child InstanceId: {0}", child.InstanceId.ToString());815                    _tracer.TraceException(e);816                }817#pragma warning restore 56500818                return;819            }820 821            var completed = new AutoResetEvent(false);822            // Count of StartJobCompleted events from children.823            var startedChildJobsCount = 0;824            EventHandler<AsyncCompletedEventArgs> eventHandler = (object sender, AsyncCompletedEventArgs e) =>825            {826                var childJob = sender as Job2;827                Dbg.Assert(childJob != null,828                           "StartJobCompleted only available on Job2");829                _tracer.WriteMessage(TraceClassName, "StartJob-Handler", Guid.Empty, this,830                    "Finished starting child job asynchronously, child InstanceId: {0}", childJob.InstanceId.ToString());831                if (e.Error != null)832                {833                    ExecutionError.Add(834                        new ErrorRecord(e.Error,835                                        "ContainerParentJobStartError",836                                        ErrorCategory.InvalidResult,837                                        childJob));838                    _tracer.WriteMessage(TraceClassName, "StartJob-Handler", Guid.Empty, this,839                        "Child job asynchronously had error, child InstanceId: {0}", childJob.InstanceId.ToString());840                    _tracer.TraceException(e.Error);841                }842 843                Interlocked.Increment(ref startedChildJobsCount);844                if (startedChildJobsCount == ChildJobs.Count)845                {846                    _tracer.WriteMessage(TraceClassName, "StartJob-Handler", Guid.Empty, this,847                        "Finished starting all child jobs asynchronously", null);848                    JobRunning.WaitOne();849                    completed.Set();850                }851            };852 853            foreach (Job2 job in ChildJobs)854            {855                Dbg.Assert(job != null, "Job is null after initial null check");856 857                job.StartJobCompleted += eventHandler;858                _tracer.WriteMessage(TraceClassName, "StartJob", Guid.Empty, this,859                    "Child job asynchronously, child InstanceId: {0}", job.InstanceId.ToString());860 861                // This child job is created to run synchronously and so can be debugged.  Set862                // the IJobDebugger.IsAsync accordingly.863                ScriptDebugger.SetDebugJobAsync(job as IJobDebugger, false);864                job.StartJobAsync();865            }866 867            completed.WaitOne();868            foreach (Job2 job in ChildJobs)869            {870                Dbg.Assert(job != null, "Job is null after initial null check");871 872                job.StartJobCompleted -= eventHandler;873            }874 875            /*876            if (ExecutionError.Count > 0)877            {878                // Check to see expected behavior if one child job fails to start.879            }880 881            if (ExecutionError.Count == 1)882            {883                throw ExecutionError[0];884            } */885            _tracer.WriteMessage(TraceClassName, "StartJob", Guid.Empty, this, "Exiting method", null);886        }887 888        private static readonly Tracer s_structuredTracer = new Tracer();889 890        /// <summary>891        /// Starts all child jobs asynchronously.892        /// When all child jobs are started, StartJobCompleted event is raised.893        /// </summary>894        public override void StartJobAsync()895        {896            if (_isDisposed == DisposedTrue)897            {898                OnStartJobCompleted(new AsyncCompletedEventArgs(new ObjectDisposedException(TraceClassName), false, null));899                return;900            }901 902            _tracer.WriteMessage(TraceClassName, "StartJobAsync", Guid.Empty, this, "Entering method", null);903            s_structuredTracer.BeginContainerParentJobExecution(InstanceId);904            foreach (Job2 job in this.ChildJobs)905            {906                if (job == null) throw PSTraceSource.NewInvalidOperationException(RemotingErrorIdStrings.JobActionInvalidWithNullChild);907            }908 909            // Count of StartJobCompleted events from children.910            var startedChildJobsCount = 0;911            EventHandler<AsyncCompletedEventArgs> eventHandler = null;912            eventHandler = (sender, e) =>913             {914                 var childJob = sender as Job2;915                 Dbg.Assert(childJob != null, "StartJobCompleted only available on Job2");916                 _tracer.WriteMessage(TraceClassName, "StartJobAsync-Handler", Guid.Empty, this,917                     "Finished starting child job asynchronously, child InstanceId: {0}", childJob.InstanceId.ToString());918                 if (e.Error != null)919                 {920                     ExecutionError.Add(new ErrorRecord(e.Error, "ContainerParentJobStartAsyncError",921                         ErrorCategory.InvalidResult, childJob));922                     _tracer.WriteMessage(TraceClassName, "StartJobAsync-Handler", Guid.Empty, this,923                        "Child job asynchronously had error, child InstanceId: {0}", childJob.InstanceId.ToString());924                     _tracer.TraceException(e.Error);925                 }926 927                 Interlocked.Increment(ref startedChildJobsCount);928                 Dbg.Assert(eventHandler != null, "Event handler magically disappeared");929                 childJob.StartJobCompleted -= eventHandler;930 931                 if (startedChildJobsCount == ChildJobs.Count)932                 {933                     _tracer.WriteMessage(TraceClassName, "StartJobAsync-Handler", Guid.Empty, this,934                        "Finished starting all child jobs asynchronously", null);935 936                     JobRunning.WaitOne();937                     // There may be multiple exceptions raised. They938                     // are stored in the Error stream of this job object, which is otherwise939                     // unused.940                     OnStartJobCompleted(new AsyncCompletedEventArgs(null, false, null));941                 }942             };943 944            foreach (Job2 job in ChildJobs)945            {946                Dbg.Assert(job != null, "Job is null after initial null check");947                job.StartJobCompleted += eventHandler;948 949                _tracer.WriteMessage(TraceClassName, "StartJobAsync", Guid.Empty, this,950                    "Child job asynchronously, child InstanceId: {0}", job.InstanceId.ToString());951                job.StartJobAsync();952            }953 954            _tracer.WriteMessage(TraceClassName, "StartJobAsync", Guid.Empty, this, "Exiting method", null);955        }956 957        /// <summary>958        /// Resume all jobs.959        /// </summary>960        /// <exception cref="ObjectDisposedException">Thrown if job is disposed.</exception>961        public override void ResumeJob()962        {963            AssertNotDisposed();964            _tracer.WriteMessage(TraceClassName, "ResumeJob", Guid.Empty, this, "Entering method", null);965 966            // If parent contains no child jobs then this method will not respond.  Throw error in this case.967            if (ChildJobs.Count == 0)968            {969                throw PSTraceSource.NewInvalidOperationException(RemotingErrorIdStrings.JobActionInvalidWithNoChildJobs);970            }971 972            foreach (Job2 job in this.ChildJobs)973            {974                if (job == null) throw PSTraceSource.NewInvalidOperationException(RemotingErrorIdStrings.JobActionInvalidWithNullChild);975            }976 977            // If there is only one child job, call the synchronous method on the child to avoid use of another thread.978            // If there are multiple, we can run them in parallel using the asynchronous versions.979            if (ChildJobs.Count == 1)980            {981                Job2 child = ChildJobs[0] as Job2;982                Dbg.Assert(child != null, "Job is null after initial null check");983#pragma warning disable 56500984                try985                {986                    _tracer.WriteMessage(TraceClassName, "ResumeJob", Guid.Empty, this,987                        "Single child job synchronously, child InstanceId: {0}", child.InstanceId.ToString());988                    child.ResumeJob();989                    JobRunning.WaitOne();990                }991                catch (Exception e)992                {993                    // These exceptions are thrown by third party code. Adding them here to the collection994                    // of execution errors to present consistent behavior of the object.995 996                    ExecutionError.Add(new ErrorRecord(e, "ContainerParentJobResumeError",997                                                       ErrorCategory.InvalidResult, child));998                    _tracer.WriteMessage(TraceClassName, "ResumeJob", Guid.Empty, this,999                        "Single child job threw exception, child InstanceId: {0}", child.InstanceId.ToString());1000                    _tracer.TraceException(e);1001                }1002#pragma warning restore 565001003                return;1004            }1005 1006            var completed = new AutoResetEvent(false);1007            // Count of ResumeJobCompleted events from children.1008            var resumedChildJobsCount = 0;1009            EventHandler<AsyncCompletedEventArgs> eventHandler = null;1010            foreach (Job2 job in ChildJobs)1011            {1012                Dbg.Assert(job != null, "Job is null after initial null check");1013 1014                eventHandler = (object sender, AsyncCompletedEventArgs e) =>1015                                            {1016                                                var childJob = sender as Job2;1017                                                Dbg.Assert(childJob != null, "ResumeJobCompleted only available on Job2");1018                                                _tracer.WriteMessage(TraceClassName, "ResumeJob-Handler", Guid.Empty, this,1019                                                    "Finished resuming child job asynchronously, child InstanceId: {0}", job.InstanceId.ToString());1020                                                if (e.Error != null)1021                                                {1022                                                    ExecutionError.Add(new ErrorRecord(e.Error, "ContainerParentJobResumeError",1023                                                        ErrorCategory.InvalidResult, job));1024                                                    _tracer.WriteMessage(TraceClassName, "ResumeJob-Handler", Guid.Empty, this,1025                                                        "Child job asynchronously had error, child InstanceId: {0}", job.InstanceId.ToString());1026                                                    _tracer.TraceException(e.Error);1027                                                }1028 1029                                                Interlocked.Increment(ref resumedChildJobsCount);1030                                                if (resumedChildJobsCount == ChildJobs.Count)1031                                                {1032                                                    _tracer.WriteMessage(TraceClassName, "ResumeJob-Handler", Guid.Empty, this,1033                                                        "Finished resuming all child jobs asynchronously", null);1034                                                    JobRunning.WaitOne();1035                                                    completed.Set();1036                                                }1037                                            };1038                job.ResumeJobCompleted += eventHandler;1039                _tracer.WriteMessage(TraceClassName, "ResumeJob", Guid.Empty, this,1040                    "Child job asynchronously, child InstanceId: {0}", job.InstanceId.ToString());1041                job.ResumeJobAsync();1042            }1043 1044            completed.WaitOne();1045            Dbg.Assert(eventHandler != null, "Event handler magically disappeared");1046            foreach (Job2 job in ChildJobs)1047            {1048                Dbg.Assert(job != null, "Job is null after initial null check");1049 1050                job.ResumeJobCompleted -= eventHandler;1051            }1052 1053            _tracer.WriteMessage(TraceClassName, "ResumeJob", Guid.Empty, this, "Exiting method", null);1054 1055            // Errors are taken from the Error collection by the cmdlet for ContainerParentJob.1056        }1057 1058        /// <summary>1059        /// Resume all jobs asynchronously.1060        /// </summary>1061        public override void ResumeJobAsync()1062        {1063            if (_isDisposed == DisposedTrue)1064            {1065                OnResumeJobCompleted(new AsyncCompletedEventArgs(new ObjectDisposedException(TraceClassName), false, null));1066                return;1067            }1068 1069            _tracer.WriteMessage(TraceClassName, "ResumeJobAsync", Guid.Empty, this, "Entering method", null);1070            foreach (Job2 job in this.ChildJobs)1071            {1072                if (job == null) throw PSTraceSource.NewInvalidOperationException(RemotingErrorIdStrings.JobActionInvalidWithNullChild);1073            }1074 1075            // Count of ResumeJobCompleted events from children.1076            var resumedChildJobsCount = 0;1077            foreach (Job2 job in ChildJobs)1078            {1079                Dbg.Assert(job != null, "Job is null after initial null check");1080 1081                EventHandler<AsyncCompletedEventArgs> eventHandler = null;1082                eventHandler = (sender, e) =>1083                                        {1084                                            var childJob = sender as Job2;1085                                            Dbg.Assert(childJob != null, "ResumeJobCompleted only available on Job2");1086                                            _tracer.WriteMessage(TraceClassName, "ResumeJobAsync-Handler", Guid.Empty, this,1087                                                "Finished resuming child job asynchronously, child InstanceId: {0}", job.InstanceId.ToString());1088                                            if (e.Error != null)1089                                            {1090                                                ExecutionError.Add(new ErrorRecord(e.Error, "ContainerParentJobResumeAsyncError",1091                                                    ErrorCategory.InvalidResult, job));1092                                                _tracer.WriteMessage(TraceClassName, "ResumeJobAsync-Handler", Guid.Empty, this,1093                                                    "Child job asynchronously had error, child InstanceId: {0}", job.InstanceId.ToString());1094                                                _tracer.TraceException(e.Error);1095                                            }1096 1097                                            Interlocked.Increment(ref resumedChildJobsCount);1098                                            Dbg.Assert(eventHandler != null, "Event handler magically disappeared");1099                                            childJob.ResumeJobCompleted -= eventHandler;1100                                            if (resumedChildJobsCount == ChildJobs.Count)1101                                            {1102                                                _tracer.WriteMessage(TraceClassName, "ResumeJobAsync-Handler", Guid.Empty, this,1103                                                    "Finished resuming all child jobs asynchronously", null);1104 1105                                                JobRunning.WaitOne();1106                                                // There may be multiple exceptions raised. They1107                                                // are stored in the Error stream of this job object, which is otherwise1108                                                // unused.1109                                                OnResumeJobCompleted(new AsyncCompletedEventArgs(null, false, null));1110                                            }1111                                        };1112                job.ResumeJobCompleted += eventHandler;1113                _tracer.WriteMessage(TraceClassName, "ResumeJobAsync", Guid.Empty, this,1114                    "Child job asynchronously, child InstanceId: {0}", job.InstanceId.ToString());1115                job.ResumeJobAsync();1116            }1117 1118            _tracer.WriteMessage(TraceClassName, "ResumeJobAsync", Guid.Empty, this, "Exiting method", null);1119        }1120 1121        /// <summary>1122        /// Suspends all jobs.1123        /// </summary>1124        /// <exception cref="ObjectDisposedException">Thrown if job is disposed.</exception>1125        public override void SuspendJob()1126        {1127            SuspendJobInternal(null, null);1128        }1129 1130        /// <summary>1131        /// Suspends all jobs forcefully.1132        /// </summary>1133        /// <param name="force">Force flag for suspending forcefully.</param>1134        /// <param name="reason">Reason for doing forceful suspend.</param>1135        public override void SuspendJob(bool force, string reason)1136        {1137            SuspendJobInternal(force, reason);1138        }1139 1140        /// <summary>1141        /// Suspends all jobs asynchronously.1142        /// When all jobs have been suspended, SuspendJobCompleted is raised.1143        /// </summary>1144        public override void SuspendJobAsync()1145        {1146            SuspendJobAsyncInternal(null, null);1147        }1148 1149        /// <summary>1150        /// Suspends all jobs asynchronously with force flag.1151        /// When all jobs have been suspended, SuspendJobCompleted is raised.1152        /// </summary>1153        /// <param name="force">Force flag for suspending forcefully.</param>1154        /// <param name="reason">Reason for doing forceful suspend.</param>1155        public override void SuspendJobAsync(bool force, string reason)1156        {1157            SuspendJobAsyncInternal(force, reason);1158        }1159 1160        /// <summary>1161        /// Stop all child jobs.1162        /// </summary>1163        public override void StopJob()1164        {1165            StopJobInternal(null, null);1166        }1167 1168        /// <summary>1169        /// Stops all child jobs asynchronously.1170        /// Once all child jobs are stopped, StopJobCompleted event is raised.1171        /// </summary>1172        public override void StopJobAsync()1173        {1174            StopJobAsyncInternal(null, null);1175        }1176 1177        /// <summary>1178        /// StopJob.1179        /// </summary>1180        /// <param name="force"></param>1181        /// <param name="reason"></param>1182        public override void StopJob(bool force, string reason)1183        {1184            StopJobInternal(force, reason);1185        }1186 1187        /// <summary>1188        /// StopJobAsync.1189        /// </summary>1190        /// <param name="force"></param>1191        /// <param name="reason"></param>1192        public override void StopJobAsync(bool force, string reason)1193        {1194            StopJobAsyncInternal(force, reason);1195        }1196 1197        /// <summary>1198        /// Unblock all child jobs.1199        /// </summary>1200        /// <exception cref="ObjectDisposedException">Thrown if job is disposed.</exception>

Showing the first 1,200 of 2187 lines. Download the file for the rest.