Team Ai
Datasetpublic

MegaBites-AI/Windows-powershell

sourceHugging Facemitupdated 6mo agoView on Hugging Face
0likes372downloads
RemoveJob.cs1086 linesDownload Raw Back to commands
1// Copyright (c) Microsoft Corporation.2// Licensed under the MIT License.3 4using System;5using System.Collections;6using System.Collections.Generic;7using System.ComponentModel;8using System.Diagnostics.CodeAnalysis;9using System.Management.Automation;10using System.Management.Automation.Remoting;11using System.Threading;12 13using Dbg = System.Management.Automation.Diagnostics;14 15namespace Microsoft.PowerShell.Commands16{17    /// <summary>18    /// This is the base class for job cmdlet and contains some helper functions.19    /// </summary>20    public class JobCmdletBase : PSRemotingCmdlet21    {22        #region Strings23 24        // Parametersets used by job cmdlets25        internal const string JobParameterSet = "JobParameterSet";26        internal const string InstanceIdParameterSet = "InstanceIdParameterSet";27        internal const string SessionIdParameterSet = "SessionIdParameterSet";28        internal const string NameParameterSet = "NameParameterSet";29        internal const string StateParameterSet = "StateParameterSet";30        internal const string CommandParameterSet = "CommandParameterSet";31        internal const string FilterParameterSet = "FilterParameterSet";32 33        // common parameter names34        internal const string JobParameter = "Job";35        internal const string InstanceIdParameter = "InstanceId";36        internal const string SessionIdParameter = "SessionId";37        internal const string NameParameter = "Name";38        internal const string StateParameter = "State";39        internal const string CommandParameter = "Command";40        internal const string FilterParameter = "Filter";41 42        #endregion Strings43 44        #region Job Matches45 46        /// <summary>47        /// Find the jobs in repository which match matching the specified names.48        /// </summary>49        /// <param name="writeobject">if true, method writes the object instead of returning it50        /// in list (an empty list is returned).</param>51        /// <param name="writeErrorOnNoMatch">Write error if no match is found.</param>52        /// <param name="checkIfJobCanBeRemoved">Check if this job can be removed.</param>53        /// <param name="recurse">Recurse and check in child jobs.</param>54        /// <returns>List of matching jobs.</returns>55        internal List<Job> FindJobsMatchingByName(56            bool recurse,57            bool writeobject,58            bool writeErrorOnNoMatch,59            bool checkIfJobCanBeRemoved)60        {61            List<Job> matches = new List<Job>();62            Hashtable duplicateDetector = new Hashtable();63 64            if (_names == null)65            {66                return matches;67            }68 69            foreach (string name in _names)70            {71                if (string.IsNullOrEmpty(name))72                {73                    continue;74                }75 76                // search all jobs in repository.77                bool jobFound = false;78                duplicateDetector.Clear();79                jobFound = FindJobsMatchingByNameHelper(matches, JobRepository.Jobs, name,80                                    duplicateDetector, recurse, writeobject, checkIfJobCanBeRemoved);81 82                // search all jobs in JobManager83                List<Job2> jobs2 = JobManager.GetJobsByName(name, this, false, writeobject, recurse, null);84 85                bool job2Found = (jobs2 != null) && (jobs2.Count > 0);86 87                if (job2Found)88                {89                    foreach (Job2 job2 in jobs2)90                    {91                        if (CheckIfJob2CanBeRemoved(checkIfJobCanBeRemoved, NameParameter, job2,92                            RemotingErrorIdStrings.JobWithSpecifiedNameNotCompleted, job2.Id, job2.Name))93                        {94                            matches.Add(job2);95                        }96                    }97                }98 99                jobFound = jobFound || job2Found;100 101                // if a match is not found, write an error)102                if (jobFound || !writeErrorOnNoMatch || WildcardPattern.ContainsWildcardCharacters(name))103                {104                    continue;105                }106 107                Exception ex = PSTraceSource.NewArgumentException(NameParameter, RemotingErrorIdStrings.JobWithSpecifiedNameNotFound, name);108                WriteError(new ErrorRecord(ex, "JobWithSpecifiedNameNotFound", ErrorCategory.ObjectNotFound, name));109            }110 111            return matches;112        }113 114        private bool CheckIfJob2CanBeRemoved(bool checkForRemove, string parameterName, Job2 job2, string resourceString, params object[] args)115        {116            if (checkForRemove)117            {118                if (job2.IsFinishedState(job2.JobStateInfo.State))119                    return true;120 121                string message = PSRemotingErrorInvariants.FormatResourceString(resourceString, args);122                Exception ex = new ArgumentException(message, parameterName);123                WriteError(new ErrorRecord(ex, "JobObjectNotFinishedCannotBeRemoved", ErrorCategory.InvalidOperation, job2));124                return false;125            }126 127            return true;128        }129 130        private bool FindJobsMatchingByNameHelper(List<Job> matches, IList<Job> jobsToSearch, string name,131                        Hashtable duplicateDetector, bool recurse, bool writeobject, bool checkIfJobCanBeRemoved)132        {133            Dbg.Assert(!string.IsNullOrEmpty(name), "Caller should ensure that name is not null or empty");134 135            bool jobFound = false;136 137            WildcardPattern pattern =138                WildcardPattern.Get(name, WildcardOptions.IgnoreCase | WildcardOptions.Compiled);139 140            foreach (Job job in jobsToSearch)141            {142                // check if this job has already been searched143                if (duplicateDetector.ContainsKey(job.Id))144                {145                    continue;146                }147 148                duplicateDetector.Add(job.Id, job.Id);149 150                // check if the job is available in any of the151                // top level jobs152 153                // if (string.Equals(job.Name, name, StringComparison.OrdinalIgnoreCase))154                if (pattern.IsMatch(job.Name))155                {156                    jobFound = true;157                    if (!checkIfJobCanBeRemoved || CheckJobCanBeRemoved(job, NameParameter, RemotingErrorIdStrings.JobWithSpecifiedNameNotCompleted, job.Id, job.Name))158                    {159                        if (writeobject)160                        {161                            WriteObject(job);162                        }163                        else164                        {165                            matches.Add(job);166                        }167                    }168                    // break;169                }170 171                // check if the job is available in any of the childjobs172                if (job.ChildJobs != null && job.ChildJobs.Count > 0 && recurse)173                {174                    bool jobFoundinChildJobs = FindJobsMatchingByNameHelper(matches, job.ChildJobs, name,175                                                    duplicateDetector, recurse, writeobject, checkIfJobCanBeRemoved);176 177                    if (jobFoundinChildJobs)178                    {179                        jobFound = true;180                    }181                }182            }183 184            return jobFound;185        }186 187        /// <summary>188        /// Find the jobs in repository which match the specified instanceid.189        /// </summary>190        /// <param name="writeobject">if true, method writes the object instead of returning it191        /// in list (an empty list is returned).</param>192        /// <param name="writeErrorOnNoMatch">Write error if no match is found.</param>193        /// <param name="checkIfJobCanBeRemoved">Check if this job can be removed.</param>194        /// <param name="recurse">Look in all child jobs.</param>195        /// <returns>List of matching jobs.</returns>196        internal List<Job> FindJobsMatchingByInstanceId(bool recurse, bool writeobject, bool writeErrorOnNoMatch, bool checkIfJobCanBeRemoved)197        {198            List<Job> matches = new List<Job>();199 200            Hashtable duplicateDetector = new Hashtable();201 202            if (_instanceIds == null)203            {204                return matches;205            }206 207            foreach (Guid id in _instanceIds)208            {209                // search all jobs in Job repository210                duplicateDetector.Clear();211                bool jobFound = FindJobsMatchingByInstanceIdHelper(matches, JobRepository.Jobs, id,212                                    duplicateDetector, recurse, writeobject, checkIfJobCanBeRemoved);213 214                // TODO: optimize this to not search JobManager since matching by InstanceId is unique215                // search all jobs in JobManager216                Job2 job2 = JobManager.GetJobByInstanceId(id, this, false, writeobject, recurse);217 218                bool job2Found = job2 != null;219 220                if (job2Found)221                {222                    if (CheckIfJob2CanBeRemoved(checkIfJobCanBeRemoved, InstanceIdParameter, job2,223                        RemotingErrorIdStrings.JobWithSpecifiedInstanceIdNotCompleted, job2.Id, job2.InstanceId))224                    {225                        matches.Add(job2);226                    }227                }228 229                jobFound = jobFound || job2Found;230 231                if (jobFound || !writeErrorOnNoMatch)232                {233                    continue;234                }235 236                Exception ex = PSTraceSource.NewArgumentException(InstanceIdParameter,237                                                                  RemotingErrorIdStrings.JobWithSpecifiedInstanceIdNotFound,238                                                                  id);239 240                WriteError(new ErrorRecord(ex, "JobWithSpecifiedInstanceIdNotFound", ErrorCategory.ObjectNotFound, id));241            }242 243            return matches;244        }245 246        private bool FindJobsMatchingByInstanceIdHelper(List<Job> matches, IList<Job> jobsToSearch, Guid instanceId,247                        Hashtable duplicateDetector, bool recurse, bool writeobject, bool checkIfJobCanBeRemoved)248        {249            bool jobFound = false;250 251            // Most likely users will ask for top level jobs.252            // So in order to be more efficient, first look253            // into the top level jobs and only if a match is254            // not found in the top level jobs, recurse. This255            // will ensure that we get a pretty quick hit when256            // the job tree is more than 2 levels deep257 258            // check if job is found in top level item259            foreach (Job job in jobsToSearch)260            {261                if (duplicateDetector.ContainsKey(job.Id))262                {263                    continue;264                }265 266                duplicateDetector.Add(job.Id, job.Id);267 268                if (job.InstanceId == instanceId)269                {270                    jobFound = true;271                    if (!checkIfJobCanBeRemoved || CheckJobCanBeRemoved(job, InstanceIdParameter, RemotingErrorIdStrings.JobWithSpecifiedInstanceIdNotCompleted, job.Id, job.InstanceId))272                    {273                        // instance id is unique, so once a match is found274                        // you can break275                        if (writeobject)276                        {277                            WriteObject(job);278                        }279                        else280                        {281                            matches.Add(job);282                        }283 284                        break;285                    }286                }287            }288 289            // check if a match is found in the child jobs290            if (!jobFound && recurse)291            {292                foreach (Job job in jobsToSearch)293                {294                    if (job.ChildJobs != null && job.ChildJobs.Count > 0)295                    {296                        jobFound = FindJobsMatchingByInstanceIdHelper(matches, job.ChildJobs, instanceId,297                                        duplicateDetector, recurse, writeobject, checkIfJobCanBeRemoved);298 299                        if (jobFound)300                        {301                            break;302                        }303                    }304                }305            }306 307            return jobFound;308        }309 310        /// <summary>311        /// Find the jobs in repository which match the specified session ids.312        /// </summary>313        /// <param name="writeobject">if true, method writes the object instead of returning it314        /// in list (an empty list is returned).</param>315        /// <param name="writeErrorOnNoMatch">Write error if no match is found.</param>316        /// <param name="checkIfJobCanBeRemoved">Check if this job can be removed.</param>317        /// <param name="recurse">Look in child jobs as well.</param>318        /// <returns>List of matching jobs.</returns>319        internal List<Job> FindJobsMatchingBySessionId(bool recurse, bool writeobject, bool writeErrorOnNoMatch, bool checkIfJobCanBeRemoved)320        {321            List<Job> matches = new List<Job>();322 323            if (_sessionIds == null)324            {325                return matches;326            }327 328            Hashtable duplicateDetector = new Hashtable();329 330            foreach (int id in _sessionIds)331            {332                // check jobs in job repository333                bool jobFound = FindJobsMatchingBySessionIdHelper(matches, JobRepository.Jobs, id,334                                    duplicateDetector, recurse, writeobject, checkIfJobCanBeRemoved);335 336                // check jobs in job manager337                Job2 job2 = JobManager.GetJobById(id, this, false, writeobject, recurse);338                bool job2Found = job2 != null;339 340                if (job2Found)341                {342                    if (CheckIfJob2CanBeRemoved(checkIfJobCanBeRemoved, SessionIdParameter, job2,343                        RemotingErrorIdStrings.JobWithSpecifiedSessionIdNotCompleted, job2.Id))344                    {345                        matches.Add(job2);346                    }347                }348 349                jobFound = jobFound || job2Found;350 351                if (jobFound || !writeErrorOnNoMatch)352                {353                    continue;354                }355 356                Exception ex = PSTraceSource.NewArgumentException(SessionIdParameter, RemotingErrorIdStrings.JobWithSpecifiedSessionIdNotFound, id);357                WriteError(new ErrorRecord(ex, "JobWithSpecifiedSessionNotFound", ErrorCategory.ObjectNotFound, id));358            }359 360            return matches;361        }362 363        private bool FindJobsMatchingBySessionIdHelper(List<Job> matches, IList<Job> jobsToSearch, int sessionId,364                        Hashtable duplicateDetector, bool recurse, bool writeobject, bool checkIfJobCanBeRemoved)365        {366            bool jobFound = false;367 368            // Most likely users will ask for top level jobs.369            // So in order to be more efficient, first look370            // into the top level jobs and only if a match is371            // not found in the top level jobs, recurse. This372            // will ensure that we get a pretty quick hit when373            // the job tree is more than 2 levels deep374 375            // check if there is a match in the top level jobs376            foreach (Job job in jobsToSearch)377            {378                if (job.Id == sessionId)379                {380                    jobFound = true;381                    if (!checkIfJobCanBeRemoved || CheckJobCanBeRemoved(job, SessionIdParameter, RemotingErrorIdStrings.JobWithSpecifiedSessionIdNotCompleted, job.Id))382                    {383                        if (writeobject)384                        {385                            WriteObject(job);386                        }387                        else388                        {389                            matches.Add(job);390                        }391 392                        // session id will be unique for every session, so393                        // can break after the first match394                        break;395                    }396                }397            }398 399            // check if there is a match found in the child jobs400            if (!jobFound && recurse)401            {402                foreach (Job job in jobsToSearch)403                {404                    if (job.ChildJobs != null && job.ChildJobs.Count > 0)405                    {406                        jobFound = FindJobsMatchingBySessionIdHelper(matches, job.ChildJobs, sessionId,407                                        duplicateDetector, recurse, writeobject, checkIfJobCanBeRemoved);408 409                        if (jobFound)410                        {411                            break;412                        }413                    }414                }415            }416 417            return jobFound;418        }419 420        /// <summary>421        /// Find the jobs in repository which match the specified command.422        /// </summary>423        /// <param name="writeobject">if true, method writes the object instead of returning it424        /// in list (an empty list is returned).</param>425        /// <returns>List of matching jobs.</returns>426        internal List<Job> FindJobsMatchingByCommand(427            bool writeobject)428        {429            List<Job> matches = new List<Job>();430 431            if (_commands == null)432            {433                return matches;434            }435 436            List<Job> jobs = new List<Job>();437 438            jobs.AddRange(JobRepository.Jobs);439 440            foreach (string command in _commands)441            {442                List<Job2> jobs2 = JobManager.GetJobsByCommand(command, this, false, false, false, null);443 444                if (jobs2 != null)445                {446                    foreach (Job2 job2 in jobs2)447                    {448                        jobs.Add(job2);449                    }450                }451 452                foreach (Job job in jobs)453                {454                    WildcardPattern commandPattern = WildcardPattern.Get(command, WildcardOptions.IgnoreCase);455                    string jobCommand = job.Command.Trim();456                    // Win8: 469830457                    // Win7 code does not have commandPattern.IsMatch. We added wildcard support for Command parameterset458                    // in Win8 which breaks scenarios where the actual command has wildcards.)459                    if (jobCommand.Equals(command.Trim(), StringComparison.OrdinalIgnoreCase) || commandPattern.IsMatch(jobCommand))460                    {461                        if (writeobject)462                        {463                            WriteObject(job);464                        }465                        else466                        {467                            matches.Add(job);468                        }469                    }470                }471            }472 473            return matches;474        }475 476        /// <summary>477        /// Find the jobs in repository which match the specified state.478        /// </summary>479        /// <param name="writeobject">if true, method writes the object instead of returning it480        /// in list (an empty list is returned).</param>481        /// <returns>List of matching jobs.</returns>482        internal List<Job> FindJobsMatchingByState(483            bool writeobject)484        {485            List<Job> matches = new List<Job>();486            List<Job> jobs = new List<Job>();487 488            jobs.AddRange(JobRepository.Jobs);489 490            List<Job2> jobs2 = JobManager.GetJobsByState(_jobstate, this, false, false, false, null);491 492            if (jobs2 != null)493            {494                foreach (Job2 job2 in jobs2)495                {496                    jobs.Add(job2);497                }498            }499 500            foreach (Job job in jobs)501            {502                if (job.JobStateInfo.State != _jobstate)503                {504                    continue;505                }506 507                if (writeobject)508                {509                    WriteObject(job);510                }511                else512                {513                    matches.Add(job);514                }515            }516 517            return matches;518        }519 520        /// <summary>521        /// Find the jobs which match the specified filter.522        /// </summary>523        /// <param name="writeobject"></param>524        /// <returns></returns>525        internal List<Job> FindJobsMatchingByFilter(bool writeobject)526        {527            List<Job> matches = new List<Job>();528            List<Job> jobs = new List<Job>();529 530            // add Jobs from JobRepository -- only job property based filters are supported.531            FindJobsMatchingByFilterHelper(jobs, JobRepository.Jobs);532 533            var filterDictionary = new Dictionary<string, object>();534            foreach (string item in _filter.Keys)535            {536                filterDictionary.Add(item, _filter[item]);537            }538 539            List<Job2> jobs2 = JobManager.GetJobsByFilter(filterDictionary, this, false, false, true);540            if (jobs2 != null)541            {542                foreach (Job2 job2 in jobs2)543                {544                    jobs.Add(job2);545                }546            }547 548            foreach (Job job in jobs)549            {550                if (writeobject)551                {552                    WriteObject(job);553                }554                else555                {556                    matches.Add(job);557                }558            }559 560            return matches;561        }562 563        /// <summary>564        /// Used to find the v2 jobs that match a given filter.565        /// </summary>566        /// <param name="matches"></param>567        /// <param name="jobsToSearch"></param>568        /// <returns></returns>569        private static bool FindJobsMatchingByFilterHelper(List<Job> matches, List<Job> jobsToSearch)570        {571            // check that filter only has job properties572            // if so, filter on one at a time using helpers.573            return false;574        }575 576        /// <summary>577        /// Copies the jobs to list.578        /// </summary>579        /// <param name="jobs"></param>580        /// <param name="writeobject">if true, method writes the object instead of returning it581        /// in list (an empty list is returned).</param>582        /// <param name="checkIfJobCanBeRemoved">If true, only jobs which can be removed will be checked.</param>583        /// <returns></returns>584        internal List<Job> CopyJobsToList(Job[] jobs, bool writeobject, bool checkIfJobCanBeRemoved)585        {586            List<Job> matches = new List<Job>();587            if (jobs == null)588            {589                return matches;590            }591 592            foreach (Job job in jobs)593            {594                if (!checkIfJobCanBeRemoved || CheckJobCanBeRemoved(job, "Job", RemotingErrorIdStrings.JobWithSpecifiedSessionIdNotCompleted, job.Id))595                {596                    if (writeobject)597                    {598                        WriteObject(job);599                    }600                    else601                    {602                        matches.Add(job);603                    }604                }605            }606 607            return matches;608        }609 610        /// <summary>611        /// Checks that this job object can be removed. If not, writes an error record.612        /// </summary>613        /// <param name="job">Job object to be removed.</param>614        /// <param name="parameterName">Name of the parameter which is associated with this job object.615        /// </param>616        /// <param name="resourceString">Resource String in case of error.</param>617        /// <param name="list">Parameters for resource message.</param>618        /// <returns>True if object should be removed, else false.</returns>619        private bool CheckJobCanBeRemoved(Job job, string parameterName, string resourceString, params object[] list)620        {621            if (job.IsFinishedState(job.JobStateInfo.State))622                return true;623            string message = PSRemotingErrorInvariants.FormatResourceString(resourceString, list);624            Exception ex = new ArgumentException(message, parameterName);625            WriteError(new ErrorRecord(ex, "JobObjectNotFinishedCannotBeRemoved", ErrorCategory.InvalidOperation, job));626            return false;627        }628 629        #endregion JobMatches630 631        #region Parameters632 633        /// <summary>634        /// Name of the jobs to retrieve.635        /// </summary>636        [Parameter(ValueFromPipelineByPropertyName = true, Position = 0,637                  Mandatory = true,638                  ParameterSetName = JobCmdletBase.NameParameterSet)]639        [ValidateNotNullOrEmpty]640        public string[] Name641        {642            get643            {644                return _names;645            }646 647            set648            {649                _names = value;650            }651        }652 653        /// <summary>654        /// </summary>655        private string[] _names;656 657        /// <summary>658        /// InstanceIds for which job659        /// need to be obtained.660        /// </summary>661        [Parameter(ValueFromPipelineByPropertyName = true, Position = 0,662                   Mandatory = true,663                   ParameterSetName = JobCmdletBase.InstanceIdParameterSet)]664        [ValidateNotNullOrEmpty]665        public Guid[] InstanceId666        {667            get668            {669                return _instanceIds;670            }671 672            set673            {674                _instanceIds = value;675            }676        }677 678        /// <summary>679        /// </summary>680        private Guid[] _instanceIds;681 682        /// <summary>683        /// SessionId for which job684        /// need to be obtained.685        /// </summary>686        [Parameter(ValueFromPipelineByPropertyName = true, Position = 0,687                  Mandatory = true,688                  ParameterSetName = JobCmdletBase.SessionIdParameterSet)]689        [ValidateNotNullOrEmpty]690        [SuppressMessage("Microsoft.Performance", "CA1819:PropertiesShouldNotReturnArrays")]691        public virtual int[] Id692        {693            get694            {695                return _sessionIds;696            }697 698            set699            {700                _sessionIds = value;701            }702        }703 704        /// <summary>705        /// </summary>706        private int[] _sessionIds;707 708        /// <summary>709        /// All the job objects having this state.710        /// </summary>711        [Parameter(Mandatory = true,712                   Position = 0, ValueFromPipelineByPropertyName = true,713            ParameterSetName = RemoveJobCommand.StateParameterSet)]714        public virtual JobState State715        {716            get717            {718                return _jobstate;719            }720 721            set722            {723                _jobstate = value;724            }725        }726 727        /// <summary>728        /// </summary>729        private JobState _jobstate;730 731        /// <summary>732        /// All the job objects having this command.733        /// </summary>734        [Parameter(ValueFromPipelineByPropertyName = true,735            ParameterSetName = RemoveJobCommand.CommandParameterSet)]736        [ValidateNotNullOrEmpty]737        public virtual string[] Command738        {739            get740            {741                return _commands;742            }743 744            set745            {746                _commands = value;747            }748        }749 750        /// <summary>751        /// </summary>752        private string[] _commands;753 754        /// <summary>755        /// All the job objects matching the values in filter.756        /// </summary>757        [Parameter(Mandatory = true,758                   Position = 0, ValueFromPipelineByPropertyName = true,759            ParameterSetName = RemoveJobCommand.FilterParameterSet)]760        [ValidateNotNullOrEmpty]761        [SuppressMessage("Microsoft.Usage", "CA2227:CollectionPropertiesShouldBeReadOnly")]762        public virtual Hashtable Filter763        {764            get { return _filter; }765 766            set { _filter = value; }767        }768 769        private Hashtable _filter;770 771        #endregion Parameters772 773        #region Overrides774 775        /// <summary>776        /// All remoting cmdlets other than Start-PSJob should777        /// continue to work even if PowerShell remoting is not778        /// enabled. This is because jobs are based out of APIs779        /// and there can be other job implementations like780        /// eventing or WMI which are not based on PowerShell781        /// remoting.782        /// </summary>783        protected override void BeginProcessing()784        {785            CommandDiscovery.AutoloadModulesWithJobSourceAdapters(this.Context, this.CommandOrigin);786            // intentionally left blank to avoid787            // check being performed in base.BeginProcessing()788        }789        #endregion Overrides790    }791 792    /// <summary>793    /// This cmdlet removes the Job object from the runspace794    /// wide Job repository.795    ///796    /// Once the Job object is removed, it will not be available797    /// through get-psjob command.798    /// </summary>799    [Cmdlet(VerbsCommon.Remove, "Job", SupportsShouldProcess = true, DefaultParameterSetName = JobCmdletBase.SessionIdParameterSet,800        HelpUri = "https://go.microsoft.com/fwlink/?LinkID=2096868")]801    [OutputType(typeof(Job), ParameterSetName = new string[] { JobCmdletBase.JobParameterSet })]802    public class RemoveJobCommand : JobCmdletBase, IDisposable803    {804        #region Parameters805 806        /// <summary>807        /// Specifies the Jobs objects which need to be808        /// removed.809        /// </summary>810        [Parameter(Mandatory = true,811                   Position = 0,812                   ValueFromPipeline = true,813                   ValueFromPipelineByPropertyName = true,814                   ParameterSetName = RemoveJobCommand.JobParameterSet)]815        [SuppressMessage("Microsoft.Performance", "CA1819:PropertiesShouldNotReturnArrays")]816        [ValidateNotNullOrEmpty]817        public Job[] Job818        {819            get820            {821                return _jobs;822            }823 824            set825            {826                _jobs = value;827            }828        }829 830        private Job[] _jobs;831 832        /// <summary>833        /// If state of the job is running or notstarted, this will forcefully stop it.834        /// </summary>835        [Parameter(ParameterSetName = RemoveJobCommand.InstanceIdParameterSet)]836        [Parameter(ParameterSetName = RemoveJobCommand.JobParameterSet)]837        [Parameter(ParameterSetName = RemoveJobCommand.NameParameterSet)]838        [Parameter(ParameterSetName = RemoveJobCommand.SessionIdParameterSet)]839        [Parameter(ParameterSetName = RemoveJobCommand.FilterParameterSet)]840        [Alias("F")]841        public SwitchParameter Force842        {843            get844            {845                return _force;846            }847 848            set849            {850                _force = value;851            }852        }853 854        private bool _force = false;855 856        #endregion Parameters857 858        #region Overrides859 860        /// <summary>861        /// Gets the job object as per the parameter and removes it.862        /// </summary>863        protected override void ProcessRecord()864        {865            List<Job> listOfJobsToRemove = null;866 867            switch (ParameterSetName)868            {869                case NameParameterSet:870                    {871                        listOfJobsToRemove = FindJobsMatchingByName(false, false, true, !_force);872                    }873 874                    break;875 876                case InstanceIdParameterSet:877                    {878                        listOfJobsToRemove = FindJobsMatchingByInstanceId(true, false, true, !_force);879                    }880 881                    break;882 883                case SessionIdParameterSet:884                    {885                        listOfJobsToRemove = FindJobsMatchingBySessionId(true, false, true, !_force);886                    }887 888                    break;889 890                case CommandParameterSet:891                    {892                        listOfJobsToRemove = FindJobsMatchingByCommand(false);893                    }894 895                    break;896 897                case StateParameterSet:898                    {899                        listOfJobsToRemove = FindJobsMatchingByState(false);900                    }901 902                    break;903 904                case FilterParameterSet:905                    {906                        listOfJobsToRemove = FindJobsMatchingByFilter(false);907                    }908 909                    break;910 911                default:912                    {913                        listOfJobsToRemove = CopyJobsToList(_jobs, false, !_force);914                    }915 916                    break;917            }918 919            // Now actually remove the jobs920            foreach (Job job in listOfJobsToRemove)921            {922                string message = GetMessage(RemotingErrorIdStrings.StopPSJobWhatIfTarget, job.Command, job.Id);923 924                if (!ShouldProcess(message, VerbsCommon.Remove))925                {926                    continue;927                }928 929                Job2 job2 = job as Job2;930                if (!job.IsFinishedState(job.JobStateInfo.State))931                {932                    // if it is a Job2, then async is supported933                    // stop the job asynchronously934                    if (job2 != null)935                    {936                        _cleanUpActions.Add(job2, HandleStopJobCompleted);937                        job2.StopJobCompleted += HandleStopJobCompleted;938 939                        lock (_syncObject)940                        {941                            if (!job2.IsFinishedState(job2.JobStateInfo.State) &&942                                !_pendingJobs.Contains(job2.InstanceId))943                            {944                                _pendingJobs.Add(job2.InstanceId);945                            }946                        }947 948                        job2.StopJobAsync();949                    }950                    else951                    {952                        job.StopJob();953                        RemoveJobAndDispose(job, false);954                    }955                }956                else957                {958                    RemoveJobAndDispose(job, job2 != null);959                }960            }961        }962 963        /// <summary>964        /// Wait for all the stop jobs to be completed.965        /// </summary>966        protected override void EndProcessing()967        {968            bool haveToWait = false;969            lock (_syncObject)970            {971                _needToCheckForWaitingJobs = true;972                if (_pendingJobs.Count > 0)973                    haveToWait = true;974            }975 976            if (haveToWait)977                _waitForJobs.WaitOne();978        }979 980        /// <summary>981        /// Release waiting for jobs.982        /// </summary>983        protected override void StopProcessing()984        {985            _waitForJobs.Set();986        }987 988        #endregion Overrides989 990        #region Private Methods991        private void RemoveJobAndDispose(Job job, bool jobIsJob2)992        {993            try994            {995                bool job2TypeFound = false;996 997                if (jobIsJob2)998                {999                    job2TypeFound = JobManager.RemoveJob(job as Job2, this, true, false);1000                }1001 1002                if (!job2TypeFound)1003                {1004                    JobRepository.Remove(job);1005                }1006 1007                job.Dispose();1008            }1009            catch (ArgumentException ex)1010            {1011                string message = PSRemotingErrorInvariants.FormatResourceString(1012                                        RemotingErrorIdStrings.CannotRemoveJob);1013 1014                ArgumentException ex2 = new ArgumentException(message, ex);1015                WriteError(new ErrorRecord(ex2, "CannotRemoveJob", ErrorCategory.InvalidOperation, job));1016            }1017        }1018 1019        private void HandleStopJobCompleted(object sender, AsyncCompletedEventArgs eventArgs)1020        {1021            Job job = sender as Job;1022            RemoveJobAndDispose(job, true);1023 1024            bool releaseWait = false;1025            lock (_syncObject)1026            {1027                if (_pendingJobs.Contains(job.InstanceId))1028                {1029                    _pendingJobs.Remove(job.InstanceId);1030                }1031 1032                if (_needToCheckForWaitingJobs && _pendingJobs.Count == 0)1033                    releaseWait = true;1034            }1035            // end processing has been called1036            // set waithandle if this is the last one1037            if (releaseWait)1038                _waitForJobs.Set();1039        }1040 1041        #endregion Private Methods1042 1043        #region Private Members1044 1045        private readonly HashSet<Guid> _pendingJobs = new HashSet<Guid>();1046        private readonly ManualResetEvent _waitForJobs = new ManualResetEvent(false);1047 1048        private readonly Dictionary<Job2, EventHandler<AsyncCompletedEventArgs>> _cleanUpActions =1049            new Dictionary<Job2, EventHandler<AsyncCompletedEventArgs>>();1050 1051        private readonly object _syncObject = new object();1052        private bool _needToCheckForWaitingJobs;1053 1054        #endregion Private Members1055 1056        #region Dispose1057 1058        /// <summary>1059        /// </summary>1060        public void Dispose()1061        {1062            Dispose(true);1063            GC.SuppressFinalize(this);1064        }1065 1066        /// <summary>1067        /// </summary>1068        /// <param name="disposing"></param>1069        protected void Dispose(bool disposing)1070        {1071            if (!disposing)1072            {1073                return;1074            }1075 1076            foreach (var pair in _cleanUpActions)1077            {1078                pair.Key.StopJobCompleted -= pair.Value;1079            }1080 1081            _waitForJobs.Dispose();1082        }1083        #endregion Dispose1084    }1085}1086