Team Ai
Datasetpublic

MegaBites-AI/Windows-powershell

sourceHugging Facemitupdated 6mo agoView on Hugging Face
0likes372downloads
SuspendJob.cs395 linesDownload Raw Back to commands
1// Copyright (c) Microsoft Corporation.2// Licensed under the MIT License.3 4using System;5using System.Collections.Generic;6using System.ComponentModel;7using System.Diagnostics.CodeAnalysis;8using System.Linq;9using System.Management.Automation;10using System.Management.Automation.Remoting;11using System.Threading;12 13namespace Microsoft.PowerShell.Commands14{15    /// <summary>16    /// This cmdlet suspends the jobs that are Job2. Errors are added for each Job that is not Job2.17    /// </summary>18#if !CORECLR19    [SuppressMessage("Microsoft.PowerShell", "PS1012:CallShouldProcessOnlyIfDeclaringSupport")]20    [Cmdlet(VerbsLifecycle.Suspend, "Job", SupportsShouldProcess = true, DefaultParameterSetName = JobCmdletBase.SessionIdParameterSet,21        HelpUri = "https://go.microsoft.com/fwlink/?LinkID=210613")]22    [OutputType(typeof(Job))]23#endif24    public class SuspendJobCommand : JobCmdletBase, IDisposable25    {26        #region Parameters27        /// <summary>28        /// Specifies the Jobs objects which need to be29        /// suspended.30        /// </summary>31        [Parameter(Mandatory = true,32                   Position = 0,33                   ValueFromPipeline = true,34                   ValueFromPipelineByPropertyName = true,35                   ParameterSetName = JobParameterSet)]36        [ValidateNotNullOrEmpty]37        [SuppressMessage("Microsoft.Performance", "CA1819:PropertiesShouldNotReturnArrays")]38        public Job[] Job39        {40            get41            {42                return _jobs;43            }44 45            set46            {47                _jobs = value;48            }49        }50 51        private Job[] _jobs;52 53        /// <summary>54        /// </summary>55        public override string[] Command56        {57            get58            {59                return null;60            }61        }62 63        /// <summary>64        /// If state of the job is running , this will forcefully suspend it.65        /// </summary>66        [Parameter(ParameterSetName = RemoveJobCommand.InstanceIdParameterSet)]67        [Parameter(ParameterSetName = RemoveJobCommand.JobParameterSet)]68        [Parameter(ParameterSetName = RemoveJobCommand.NameParameterSet)]69        [Parameter(ParameterSetName = RemoveJobCommand.SessionIdParameterSet)]70        [Parameter(ParameterSetName = RemoveJobCommand.FilterParameterSet)]71        [Parameter(ParameterSetName = RemoveJobCommand.StateParameterSet)]72        [Alias("F")]73        public SwitchParameter Force74        {75            get76            {77                return _force;78            }79 80            set81            {82                _force = value;83            }84        }85 86        private bool _force = false;87 88        /// <summary>89        /// </summary>90        [Parameter()]91        public SwitchParameter Wait92        {93            get94            {95                return _wait;96            }97 98            set99            {100                _wait = value;101            }102        }103 104        private bool _wait = false;105 106        #endregion Parameters107 108        #region Overrides109 110        /// <summary>111        /// Suspend the Job.112        /// </summary>113        protected override void ProcessRecord()114        {115            // List of jobs to suspend116            List<Job> jobsToSuspend = null;117 118            switch (ParameterSetName)119            {120                case NameParameterSet:121                    {122                        jobsToSuspend = FindJobsMatchingByName(true, false, true, false);123                    }124 125                    break;126 127                case InstanceIdParameterSet:128                    {129                        jobsToSuspend = FindJobsMatchingByInstanceId(true, false, true, false);130                    }131 132                    break;133 134                case SessionIdParameterSet:135                    {136                        jobsToSuspend = FindJobsMatchingBySessionId(true, false, true, false);137                    }138 139                    break;140 141                case StateParameterSet:142                    {143                        jobsToSuspend = FindJobsMatchingByState(false);144                    }145 146                    break;147 148                case FilterParameterSet:149                    {150                        jobsToSuspend = FindJobsMatchingByFilter(false);151                    }152 153                    break;154 155                default:156                    {157                        jobsToSuspend = CopyJobsToList(_jobs, false, false);158                    }159 160                    break;161            }162 163            _allJobsToSuspend.AddRange(jobsToSuspend);164 165            foreach (Job job in jobsToSuspend)166            {167                var job2 = job as Job2;168 169                // If the job is not Job2, the suspend operation is not supported.170                if (job2 == null)171                {172                    WriteError(173                        new ErrorRecord(174                            PSTraceSource.NewNotSupportedException(RemotingErrorIdStrings.JobSuspendNotSupported, job.Id),175                            "Job2OperationNotSupportedOnJob", ErrorCategory.InvalidType, (object)job));176                    continue;177                }178 179                string targetString =180                    PSRemotingErrorInvariants.FormatResourceString(RemotingErrorIdStrings.RemovePSJobWhatIfTarget,181                                                                   job.Command, job.Id);182                if (ShouldProcess(targetString, VerbsLifecycle.Suspend))183                {184                    if (_wait)185                    {186                        _cleanUpActions.Add(job2, HandleSuspendJobCompleted);187                    }188                    else189                    {190                        if (job2.IsFinishedState(job2.JobStateInfo.State) || job2.JobStateInfo.State == JobState.Stopping)191                        {192                            _warnInvalidState = true;193                            continue;194                        }195 196                        if (job2.JobStateInfo.State == JobState.Suspending || job2.JobStateInfo.State == JobState.Suspended)197                            continue;198 199                        job2.StateChanged += noWait_Job2_StateChanged;200                    }201 202                    job2.SuspendJobCompleted += HandleSuspendJobCompleted;203 204                    lock (_syncObject)205                    {206                        if (!_pendingJobs.Contains(job2.InstanceId))207                        {208                            _pendingJobs.Add(job2.InstanceId);209                        }210                    }211 212                    // there could be possibility that the job gets completed before or after the213                    // subscribing to nowait_job2_statechanged event so checking it again.214                    if (!_wait && (job2.IsFinishedState(job2.JobStateInfo.State) || job2.JobStateInfo.State == JobState.Suspending || job2.JobStateInfo.State == JobState.Suspended))215                    {216                        this.ProcessExecutionErrorsAndReleaseWaitHandle(job2);217                    }218 219                    job2.SuspendJobAsync(_force, RemotingErrorIdStrings.ForceSuspendJob);220                }221            }222        }223 224        private bool _warnInvalidState = false;225        private readonly HashSet<Guid> _pendingJobs = new HashSet<Guid>();226        private readonly ManualResetEvent _waitForJobs = new ManualResetEvent(false);227        private readonly Dictionary<Job2, EventHandler<AsyncCompletedEventArgs>> _cleanUpActions =228            new Dictionary<Job2, EventHandler<AsyncCompletedEventArgs>>();229        private readonly List<ErrorRecord> _errorsToWrite = new List<ErrorRecord>();230        private readonly List<Job> _allJobsToSuspend = new List<Job>();231        private readonly object _syncObject = new object();232        private bool _needToCheckForWaitingJobs;233 234        private void noWait_Job2_StateChanged(object sender, JobStateEventArgs e)235        {236            Job job = sender as Job;237 238            switch (e.JobStateInfo.State)239            {240                case JobState.Completed:241                case JobState.Stopped:242                case JobState.Failed:243                case JobState.Suspended:244                case JobState.Suspending:245                    this.ProcessExecutionErrorsAndReleaseWaitHandle(job);246                    break;247            }248        }249 250        private void HandleSuspendJobCompleted(object sender, AsyncCompletedEventArgs eventArgs)251        {252            Job job = sender as Job;253 254            if (eventArgs.Error != null && eventArgs.Error is InvalidJobStateException)255            {256                _warnInvalidState = true;257            }258 259            this.ProcessExecutionErrorsAndReleaseWaitHandle(job);260        }261 262        private void ProcessExecutionErrorsAndReleaseWaitHandle(Job job)263        {264            bool releaseWait = false;265            lock (_syncObject)266            {267                if (_pendingJobs.Contains(job.InstanceId))268                {269                    _pendingJobs.Remove(job.InstanceId);270                }271                else272                {273                    // there could be a possibility of race condition where this function is getting called twice274                    // so if job doesn't present in the _pendingJobs then just return275                    return;276                }277 278                if (_needToCheckForWaitingJobs && _pendingJobs.Count == 0)279                    releaseWait = true;280            }281 282            if (!_wait)283            {284                job.StateChanged -= noWait_Job2_StateChanged;285                Job2 job2 = job as Job2;286                if (job2 != null)287                    job2.SuspendJobCompleted -= HandleSuspendJobCompleted;288            }289 290            var parentJob = job as ContainerParentJob;291            if (parentJob != null && parentJob.ExecutionError.Count > 0)292            {293                foreach (294                    var e in295                        parentJob.ExecutionError.Where(static e => e.FullyQualifiedErrorId == "ContainerParentJobSuspendAsyncError")296                    )297                {298                    if (e.Exception is InvalidJobStateException)299                    {300                        // if any errors were invalid job state exceptions, warn the user.301                        // This is to support Get-Job | Resume-Job scenarios when many jobs302                        // are Completed, etc.303                        _warnInvalidState = true;304                    }305                    else306                    {307                        _errorsToWrite.Add(e);308                    }309                }310            }311 312            // end processing has been called313            // set waithandle if this is the last one314            if (releaseWait)315                _waitForJobs.Set();316        }317 318        /// <summary>319        /// End Processing.320        /// </summary>321        protected override void EndProcessing()322        {323            bool haveToWait = false;324            lock (_syncObject)325            {326                _needToCheckForWaitingJobs = true;327                if (_pendingJobs.Count > 0)328                {329                    haveToWait = true;330                }331            }332 333            if (haveToWait)334            {335                _waitForJobs.WaitOne();336            }337 338            if (_warnInvalidState) 339            {340                WriteWarning(RemotingErrorIdStrings.SuspendJobInvalidJobState);341            }342 343            foreach (var e in _errorsToWrite)344            {345                WriteError(e);346            }347 348            foreach (var j in _allJobsToSuspend)349            {350                WriteObject(j);351            }352 353            base.EndProcessing();354        }355 356        /// <summary>357        /// </summary>358        protected override void StopProcessing()359        {360            _waitForJobs.Set();361        }362 363        #endregion Overrides364 365        #region Dispose366 367        /// <summary>368        /// </summary>369        public void Dispose()370        {371            Dispose(true);372            GC.SuppressFinalize(this);373        }374 375        /// <summary>376        /// </summary>377        /// <param name="disposing"></param>378        protected void Dispose(bool disposing)379        {380            if (!disposing)381            {382                return;383            }384 385            foreach (var pair in _cleanUpActions)386            {387                pair.Key.SuspendJobCompleted -= pair.Value;388            }389 390            _waitForJobs.Dispose();391        }392        #endregion Dispose393    }394}395