MegaBites-AI/Windows-powershell
0372
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 