MegaBites-AI/Windows-powershell
0308
1// Copyright (c) Microsoft Corporation.2// Licensed under the MIT License.3 4using System.Collections;5using System.Collections.Generic;6using System.Globalization;7using System.Management.Automation.Remoting;8using System.Management.Automation.Runspaces;9using System.Management.Automation.Tracing;10using System.Reflection;11using System.Security;12using System.Threading;13 14using Dbg = System.Management.Automation.Diagnostics;15 16// Stops compiler from warning about unknown warnings17#pragma warning disable 1634, 169118 19namespace System.Management.Automation20{21 /// <summary>22 /// Manager for JobSourceAdapters for invocation and management of specific Job types.23 /// </summary>24 public sealed class JobManager25 {26 private readonly PowerShellTraceSource _tracer = PowerShellTraceSourceFactory.GetTraceSource();27 28 /// <summary>29 /// Collection of registered JobSourceAdapters.30 /// </summary>31 private readonly Dictionary<string, JobSourceAdapter> _sourceAdapters =32 new Dictionary<string, JobSourceAdapter>();33 34 private readonly object _syncObject = new object();35 36 /// <summary>37 /// Collection of job IDs that are valid for reuse.38 /// </summary>39 private static readonly Dictionary<Guid, KeyValuePair<int, string>> s_jobIdsForReuse = new Dictionary<Guid, KeyValuePair<int, string>>();40 41 private static readonly object s_syncObject = new object();42 43 /// <summary>44 /// Creates a JobManager instance.45 /// </summary>46 internal JobManager()47 {48 }49 50 /// <summary>51 /// Returns true if the type is already registered.52 /// </summary>53 /// <param name="typeName">Type to check.</param>54 /// <returns>Whether the type is registered already.</returns>55 public bool IsRegistered(string typeName)56 {57 if (string.IsNullOrEmpty(typeName))58 {59 return false;60 }61 62 lock (_syncObject)63 {64 return _sourceAdapters.ContainsKey(typeName);65 }66 }67 68 /// <summary>69 /// Adds a new JobSourceAdapter to the JobManager instance.70 /// After addition, creating a NewJob with a JobDefinition71 /// indicating the JobSourceAdapter derivative type will function.72 /// </summary>73 /// <param name="jobSourceAdapterType">The derivative JobSourceAdapter type to74 /// register.</param>75 /// <exception cref="InvalidOperationException">Throws when there is no public76 /// default constructor on the type.</exception>77 internal void RegisterJobSourceAdapter(Type jobSourceAdapterType)78 {79 Dbg.Assert(typeof(JobSourceAdapter).IsAssignableFrom(jobSourceAdapterType), "BaseType of any type being registered with the JobManager should be JobSourceAdapter.");80 Dbg.Assert(jobSourceAdapterType != typeof(JobSourceAdapter), "JobSourceAdapter abstract type itself should never be registered.");81 Dbg.Assert(jobSourceAdapterType != null, "JobSourceAdapterType should never be called with null value.");82 object instance = null;83 84 ConstructorInfo constructor = jobSourceAdapterType.GetConstructor(Type.EmptyTypes);85 if (!constructor.IsPublic)86 {87 string message = string.Format(CultureInfo.CurrentCulture,88 RemotingErrorIdStrings.JobManagerRegistrationConstructorError,89 jobSourceAdapterType.FullName);90 throw new InvalidOperationException(message);91 }92 93 try94 {95 instance = constructor.Invoke(null);96 }97 catch (MemberAccessException exception)98 {99 _tracer.TraceException(exception);100 throw;101 }102 catch (TargetInvocationException exception)103 {104 _tracer.TraceException(exception);105 throw;106 }107 catch (TargetParameterCountException exception)108 {109 _tracer.TraceException(exception);110 throw;111 }112 catch (NotSupportedException exception)113 {114 _tracer.TraceException(exception);115 throw;116 }117 catch (SecurityException exception)118 {119 _tracer.TraceException(exception);120 throw;121 }122 123 if (instance != null)124 {125 lock (_syncObject)126 {127 _sourceAdapters.Add(jobSourceAdapterType.Name, (JobSourceAdapter)instance);128 }129 }130 }131 132 /// <summary>133 /// Returns a token that allows a job to be constructed with a specific id and instanceId.134 /// The original job must have been saved using "SaveJobIdForReconstruction" in the JobSourceAdapter.135 /// </summary>136 /// <param name="instanceId">The instance id desired.</param>137 /// <param name="typeName">The requesting type name for JobSourceAdapter implementation.</param>138 /// <returns>Token for job creation.</returns>139 internal static JobIdentifier GetJobIdentifier(Guid instanceId, string typeName)140 {141 lock (s_syncObject)142 {143 KeyValuePair<int, string> keyValuePair;144 if (s_jobIdsForReuse.TryGetValue(instanceId, out keyValuePair) && keyValuePair.Value.Equals(typeName))145 return new JobIdentifier(keyValuePair.Key, instanceId);146 return null;147 }148 }149 150 /// <summary>151 /// Saves the Id information for a job so that it can be constructed at a later time by a JobSourceAdapter152 /// with the same type.153 /// </summary>154 /// <param name="instanceId">The instance id to save.</param>155 /// <param name="id">The session specific id to save.</param>156 /// <param name="typeName">The type name for the JobSourceAdapter implementation doing the save.</param>157 internal static void SaveJobId(Guid instanceId, int id, string typeName)158 {159 lock (s_syncObject)160 {161 if (s_jobIdsForReuse.ContainsKey(instanceId))162 {163 return;164 }165 166 s_jobIdsForReuse.Add(instanceId, new KeyValuePair<int, string>(id, typeName));167 }168 }169 170 #region NewJob171 172 /// <summary>173 /// Creates a new job of the appropriate type given by JobDefinition passed in.174 /// </summary>175 /// <param name="definition">JobDefinition defining the command.</param>176 /// <returns>Job2 object of the appropriate type specified by the definition.</returns>177 /// <exception cref="InvalidOperationException">If JobSourceAdapter type specified178 /// in definition is not registered.</exception>179 /// <exception cref="Exception">JobSourceAdapter implementation exception thrown on error.180 /// </exception>181 public Job2 NewJob(JobDefinition definition)182 {183 ArgumentNullException.ThrowIfNull(definition);184 185 JobSourceAdapter sourceAdapter = GetJobSourceAdapter(definition);186 Job2 newJob;187 188#pragma warning disable 56500189 try190 {191 newJob = sourceAdapter.NewJob(definition);192 }193 catch (Exception exception)194 {195 // Since we are calling into 3rd party code196 // catching Exception is allowed. In all197 // other cases the appropriate exception198 // needs to be caught.199 200 // sourceAdapter.NewJob returned unknown error.201 _tracer.TraceException(exception);202 throw;203 }204#pragma warning restore 56500205 206 return newJob;207 }208 209 /// <summary>210 /// Creates a new job of the appropriate type given by JobDefinition passed in.211 /// </summary>212 /// <param name="specification">JobInvocationInfo defining the command.</param>213 /// <returns>Job2 object of the appropriate type specified by the definition.</returns>214 /// <exception cref="InvalidOperationException">If JobSourceAdapter type specified215 /// in definition is not registered.</exception>216 /// <exception cref="Exception">JobSourceAdapter implementation exception thrown on error.217 /// </exception>218 public Job2 NewJob(JobInvocationInfo specification)219 {220 ArgumentNullException.ThrowIfNull(specification);221 222 if (specification.Definition == null)223 {224 throw new ArgumentException(RemotingErrorIdStrings.NewJobSpecificationError, nameof(specification));225 }226 227 JobSourceAdapter sourceAdapter = GetJobSourceAdapter(specification.Definition);228 Job2 newJob = null;229 230#pragma warning disable 56500231 try232 {233 newJob = sourceAdapter.NewJob(specification);234 }235 catch (Exception exception)236 {237 // Since we are calling into 3rd party code238 // catching Exception is allowed. In all239 // other cases the appropriate exception240 // needs to be caught.241 242 // sourceAdapter.NewJob returned unknown error.243 _tracer.TraceException(exception);244 throw;245 }246#pragma warning restore 56500247 248 return newJob;249 }250 251 #endregion NewJob252 253 #region Persist Job254 255 /// <summary>256 /// Saves the job to a persisted store.257 /// </summary>258 /// <param name="job">Job2 type job to persist.</param>259 /// <param name="definition">Job definition containing source adapter information.</param>260 public void PersistJob(Job2 job, JobDefinition definition)261 {262 if (job == null)263 {264 throw new PSArgumentNullException(nameof(job));265 }266 267 if (definition == null)268 {269 throw new PSArgumentNullException(nameof(definition));270 }271 272 JobSourceAdapter sourceAdapter = GetJobSourceAdapter(definition);273 274 try275 {276 sourceAdapter.PersistJob(job);277 }278 catch (Exception exception)279 {280 // Since we are calling into 3rd party code281 // catching Exception is allowed. In all282 // other cases the appropriate exception283 // needs to be caught.284 285 // sourceAdapter.NewJob returned unknown error.286 _tracer.TraceException(exception);287 throw;288 }289 }290 291 #endregion292 293 /// <summary>294 /// Helper method, finds source adapter if registered, otherwise throws295 /// an InvalidOperationException.296 /// </summary>297 /// <param name="adapterTypeName">The name of the JobSourceAdapter derivative desired.</param>298 /// <returns>The JobSourceAdapter instance.</returns>299 /// <exception cref="InvalidOperationException">If JobSourceAdapter type specified300 /// is not found.</exception>301 private JobSourceAdapter AssertAndReturnJobSourceAdapter(string adapterTypeName)302 {303 JobSourceAdapter adapter;304 lock (_syncObject)305 {306 if (!_sourceAdapters.TryGetValue(adapterTypeName, out adapter))307 {308 throw new InvalidOperationException(RemotingErrorIdStrings.JobSourceAdapterNotFound);309 }310 }311 312 return adapter;313 }314 315 /// <summary>316 /// Helper method to find and return the job source adapter if currently loaded or317 /// otherwise load the associated module and the requested source adapter.318 /// </summary>319 /// <param name="definition">JobDefinition supplies the JobSourceAdapter information.</param>320 /// <returns>JobSourceAdapter.</returns>321 private JobSourceAdapter GetJobSourceAdapter(JobDefinition definition)322 {323 string adapterTypeName;324 if (!string.IsNullOrEmpty(definition.JobSourceAdapterTypeName))325 {326 adapterTypeName = definition.JobSourceAdapterTypeName;327 }328 else if (definition.JobSourceAdapterType != null)329 {330 adapterTypeName = definition.JobSourceAdapterType.Name;331 }332 else333 {334 throw new InvalidOperationException(RemotingErrorIdStrings.JobSourceAdapterNotFound);335 }336 337 JobSourceAdapter adapter;338 bool adapterFound = false;339 lock (_syncObject)340 {341 adapterFound = _sourceAdapters.TryGetValue(adapterTypeName, out adapter);342 }343 344 if (!adapterFound)345 {346 if (!string.IsNullOrEmpty(definition.ModuleName))347 {348 // Attempt to load the module.349 Exception ex = null;350 try351 {352 InitialSessionState iss = InitialSessionState.CreateDefault2();353 iss.Commands.Clear();354 iss.Formats.Clear();355 iss.Commands.Add(new SessionStateCmdletEntry("Import-Module", typeof(Microsoft.PowerShell.Commands.ImportModuleCommand), null));356 using (PowerShell powerShell = PowerShell.Create(iss))357 {358 powerShell.AddCommand("Import-Module");359 powerShell.AddParameter("Name", definition.ModuleName);360 powerShell.Invoke();361 362 if (powerShell.ErrorBuffer.Count > 0)363 {364 ex = powerShell.ErrorBuffer[0].Exception;365 }366 }367 }368 catch (RuntimeException e)369 {370 ex = e;371 }372 catch (InvalidOperationException e)373 {374 ex = e;375 }376 catch (ScriptCallDepthException e)377 {378 ex = e;379 }380 catch (SecurityException e)381 {382 ex = e;383 }384 385 if (ex != null)386 {387 throw new InvalidOperationException(RemotingErrorIdStrings.JobSourceAdapterNotFound, ex);388 }389 390 // Now try getting the job source adapter again.391 adapter = AssertAndReturnJobSourceAdapter(adapterTypeName);392 }393 else394 {395 throw new InvalidOperationException(RemotingErrorIdStrings.JobSourceAdapterNotFound);396 }397 }398 399 return adapter;400 }401 402 #region GetJobs403 404 /// <summary>405 /// Get list of all jobs.406 /// </summary>407 /// <param name="cmdlet">Cmdlet requesting this, for error processing.</param>408 /// <param name="writeErrorOnException"></param>409 /// <param name="writeObject"></param>410 /// <param name="jobSourceAdapterTypes">Job source adapter type names.</param>411 /// <returns>Collection of jobs.</returns>412 /// <exception cref="Exception">If cmdlet parameter is null, throws exception on error from413 /// JobSourceAdapter implementation.</exception>414 internal List<Job2> GetJobs(415 Cmdlet cmdlet,416 bool writeErrorOnException,417 bool writeObject,418 string[] jobSourceAdapterTypes)419 {420 return GetFilteredJobs(null, FilterType.None, cmdlet, writeErrorOnException, writeObject, false, jobSourceAdapterTypes);421 }422 423 /// <summary>424 /// Get list of jobs that matches the specified names.425 /// </summary>426 /// <param name="name">Names to match, can support427 /// wildcard if the store supports.</param>428 /// <param name="cmdlet">Cmdlet requesting this, for error processing.</param>429 /// <param name="writeErrorOnException"></param>430 /// <param name="writeObject"></param>431 /// <param name="recurse"></param>432 /// <param name="jobSourceAdapterTypes">Job source adapter type names.</param>433 /// <returns>Collection of jobs that match the specified434 /// criteria.</returns>435 /// <exception cref="Exception">If cmdlet parameter is null, throws exception on error from436 /// JobSourceAdapter implementation.</exception>437 internal List<Job2> GetJobsByName(438 string name,439 Cmdlet cmdlet,440 bool writeErrorOnException,441 bool writeObject,442 bool recurse,443 string[] jobSourceAdapterTypes)444 {445 return GetFilteredJobs(name, FilterType.Name, cmdlet, writeErrorOnException, writeObject, recurse, jobSourceAdapterTypes);446 }447 448 /// <summary>449 /// Get list of jobs that run the specified command.450 /// </summary>451 /// <param name="command">Command to match.</param>452 /// <param name="cmdlet">Cmdlet requesting this, for error processing.</param>453 /// <param name="writeErrorOnException"></param>454 /// <param name="writeObject"></param>455 /// <param name="recurse"></param>456 /// <param name="jobSourceAdapterTypes">Job source adapter type names.</param>457 /// <returns>Collection of jobs that match the specified458 /// criteria.</returns>459 /// <exception cref="Exception">If cmdlet parameter is null, throws exception on error from460 /// JobSourceAdapter implementation.</exception>461 internal List<Job2> GetJobsByCommand(462 string command,463 Cmdlet cmdlet,464 bool writeErrorOnException,465 bool writeObject,466 bool recurse,467 string[] jobSourceAdapterTypes)468 {469 return GetFilteredJobs(command, FilterType.Command, cmdlet, writeErrorOnException, writeObject, recurse, jobSourceAdapterTypes);470 }471 472 /// <summary>473 /// Get list of jobs that are in the specified state.474 /// </summary>475 /// <param name="state">State to match.</param>476 /// <param name="cmdlet">Cmdlet requesting this, for error processing.</param>477 /// <param name="writeErrorOnException"></param>478 /// <param name="writeObject"></param>479 /// <param name="recurse"></param>480 /// <param name="jobSourceAdapterTypes">Job source adapter type names.</param>481 /// <returns>Collection of jobs with the specified482 /// state.</returns>483 /// <exception cref="Exception">If cmdlet parameter is null, throws exception on error from484 /// JobSourceAdapter implementation.</exception>485 internal List<Job2> GetJobsByState(486 JobState state,487 Cmdlet cmdlet,488 bool writeErrorOnException,489 bool writeObject,490 bool recurse,491 string[] jobSourceAdapterTypes)492 {493 return GetFilteredJobs(state, FilterType.State, cmdlet, writeErrorOnException, writeObject, recurse, jobSourceAdapterTypes);494 }495 496 /// <summary>497 /// Get list of jobs based on the adapter specific498 /// filter parameters.499 /// </summary>500 /// <param name="filter">Dictionary containing name value501 /// pairs for adapter specific filters.</param>502 /// <param name="cmdlet">Cmdlet requesting this, for error processing.</param>503 /// <param name="writeErrorOnException"></param>504 /// <param name="writeObject"></param>505 /// <param name="recurse"></param>506 /// <returns>Collection of jobs that match the507 /// specified criteria.</returns>508 /// <exception cref="Exception">If cmdlet parameter is null, throws exception on error from509 /// JobSourceAdapter implementation.</exception>510 internal List<Job2> GetJobsByFilter(Dictionary<string, object> filter, Cmdlet cmdlet, bool writeErrorOnException, bool writeObject, bool recurse)511 {512 return GetFilteredJobs(filter, FilterType.Filter, cmdlet, writeErrorOnException, writeObject, recurse, null);513 }514 515 /// <summary>516 /// Get a filtered list of jobs based on adapter name.517 /// </summary>518 /// <param name="id">Job id.</param>519 /// <param name="name">Adapter name.</param>520 /// <returns></returns>521 internal bool IsJobFromAdapter(Guid id, string name)522 {523 lock (_syncObject)524 {525 foreach (JobSourceAdapter sourceAdapter in _sourceAdapters.Values)526 {527 if (sourceAdapter.Name.Equals(name, StringComparison.OrdinalIgnoreCase))528 {529 return (sourceAdapter.GetJobByInstanceId(id, false) != null);530 }531 }532 }533 534 return false;535 }536 537 /// <summary>538 /// Get a filtered list of jobs based on filter type.539 /// </summary>540 /// <param name="filter">Object to use for filtering.</param>541 /// <param name="filterType">Type of filter, specifies which "get" from542 /// JobSourceAdapter to call, and dictates the type for filter.</param>543 /// <param name="cmdlet">Cmdlet requesting this, for error processing.</param>544 /// <param name="writeErrorOnException"></param>545 /// <param name="writeObject"></param>546 /// <param name="recurse"></param>547 /// <param name="jobSourceAdapterTypes">Job source adapter type names.</param>548 /// <returns>Filtered list of jobs.</returns>549 /// <exception cref="Exception">If cmdlet parameter is null, throws exception on error from550 /// JobSourceAdapter implementation.</exception>551 private List<Job2> GetFilteredJobs(552 object filter,553 FilterType filterType,554 Cmdlet cmdlet,555 bool writeErrorOnException,556 bool writeObject,557 bool recurse,558 string[] jobSourceAdapterTypes)559 {560 Diagnostics.Assert(cmdlet != null, "Cmdlet should be passed to JobManager");561 562 List<Job2> allJobs = new List<Job2>();563 564 lock (_syncObject)565 {566 foreach (JobSourceAdapter sourceAdapter in _sourceAdapters.Values)567 {568 List<Job2> jobs = null;569 570 // Filter search based on job source adapter types if provided.571 if (!CheckTypeNames(sourceAdapter, jobSourceAdapterTypes))572 {573 continue;574 }575 576#pragma warning disable 56500577 try578 {579 jobs = CallJobFilter(sourceAdapter, filter, filterType, recurse);580 }581 catch (Exception exception)582 {583 // Since we are calling into 3rd party code584 // catching Exception is allowed. In all585 // other cases the appropriate exception586 // needs to be caught.587 588 // sourceAdapter.GetJobsByFilter() threw unknown exception.589 _tracer.TraceException(exception);590 WriteErrorOrWarning(writeErrorOnException, cmdlet, exception, "JobSourceAdapterGetJobsError", sourceAdapter);591 }592#pragma warning restore 56500593 594 if (jobs == null)595 {596 continue;597 }598 599 allJobs.AddRange(jobs);600 }601 }602 603 if (writeObject)604 {605 foreach (Job2 job in allJobs)606 {607 cmdlet.WriteObject(job);608 }609 }610 611 return allJobs;612 }613 614 /// <summary>615 /// Compare sourceAdapter name with the provided source adapter type616 /// name list.617 /// </summary>618 /// <param name="sourceAdapter"></param>619 /// <param name="jobSourceAdapterTypes"></param>620 /// <returns></returns>621 private static bool CheckTypeNames(JobSourceAdapter sourceAdapter, string[] jobSourceAdapterTypes)622 {623 // If no type names were specified then allow all adapter types.624 if (jobSourceAdapterTypes == null ||625 jobSourceAdapterTypes.Length == 0)626 {627 return true;628 }629 630 string sourceAdapterName = GetAdapterName(sourceAdapter);631 Diagnostics.Assert(sourceAdapterName != null, "Source adapter should have name or type.");632 633 // Look for name match allowing wildcards.634 foreach (string typeName in jobSourceAdapterTypes)635 {636 WildcardPattern typeNamePattern = WildcardPattern.Get(typeName, WildcardOptions.IgnoreCase);637 if (typeNamePattern.IsMatch(sourceAdapterName))638 {639 return true;640 }641 }642 643 return false;644 }645 646 private static string GetAdapterName(JobSourceAdapter sourceAdapter)647 {648 return (!string.IsNullOrEmpty(sourceAdapter.Name) ?649 sourceAdapter.Name :650 sourceAdapter.GetType().ToString());651 }652 653 /// <summary>654 /// Gets a filtered list of jobs from the given JobSourceAdapter.655 /// </summary>656 /// <param name="sourceAdapter">JobSourceAdapter to query.</param>657 /// <param name="filter">Filter object.</param>658 /// <param name="filterType">Filter type.</param>659 /// <param name="recurse"></param>660 /// <returns>List of jobs from sourceAdapter filtered on filterType.</returns>661 /// <exception cref="Exception">Throws exception on error from JobSourceAdapter662 /// implementation.</exception>663 private static List<Job2> CallJobFilter(JobSourceAdapter sourceAdapter, object filter, FilterType filterType, bool recurse)664 {665 List<Job2> jobs = new List<Job2>();666 IList<Job2> matches;667 668 switch (filterType)669 {670 case FilterType.Command:671 672 matches = sourceAdapter.GetJobsByCommand((string)filter, recurse);673 break;674 case FilterType.Filter:675 matches = sourceAdapter.GetJobsByFilter((Dictionary<string, object>)filter, recurse);676 break;677 case FilterType.Name:678 matches = sourceAdapter.GetJobsByName((string)filter, recurse);679 break;680 case FilterType.State:681 matches = sourceAdapter.GetJobsByState((JobState)filter, recurse);682 break;683 case FilterType.None:684 default:685 matches = sourceAdapter.GetJobs();686 break;687 }688 689 if (matches != null)690 {691 jobs.AddRange(matches);692 }693 694 return jobs;695 }696 697 /// <summary>698 /// Get job specified by the session specific id provided.699 /// </summary>700 /// <param name="id">Session specific job id.</param>701 /// <param name="cmdlet">Cmdlet requesting this, for error processing.</param>702 /// <param name="writeErrorOnException"></param>703 /// <param name="writeObject"></param>704 /// <param name="recurse"></param>705 /// <returns>Job that match the specified criteria.</returns>706 /// <exception cref="Exception">If cmdlet parameter is null, throws exception on error from707 /// JobSourceAdapter implementation.</exception>708 internal Job2 GetJobById(int id, Cmdlet cmdlet, bool writeErrorOnException, bool writeObject, bool recurse)709 {710 return GetJobThroughId<int>(Guid.Empty, id, cmdlet, writeErrorOnException, writeObject, recurse);711 }712 713 /// <summary>714 /// Get job that has the specified id.715 /// </summary>716 /// <param name="instanceId">Guid to match.</param>717 /// <param name="cmdlet">Cmdlet requesting this, for error processing.</param>718 /// <param name="writeErrorOnException"></param>719 /// <param name="writeObject"></param>720 /// <param name="recurse"></param>721 /// <returns>Job with the specified guid.</returns>722 /// <exception cref="Exception">If cmdlet parameter is null, throws exception on error from723 /// JobSourceAdapter implementation.</exception>724 internal Job2 GetJobByInstanceId(Guid instanceId, Cmdlet cmdlet, bool writeErrorOnException, bool writeObject, bool recurse)725 {726 return GetJobThroughId<Guid>(instanceId, 0, cmdlet, writeErrorOnException, writeObject, recurse);727 }728 729 private Job2 GetJobThroughId<T>(Guid guid, int id, Cmdlet cmdlet, bool writeErrorOnException, bool writeObject, bool recurse)730 {731 Diagnostics.Assert(cmdlet != null, "Cmdlet should always be passed to JobManager");732 Job2 job = null;733 lock (_syncObject)734 {735 foreach (JobSourceAdapter sourceAdapter in _sourceAdapters.Values)736 {737 try738 {739 if (typeof(T) == typeof(Guid))740 {741 Diagnostics.Assert(id == 0, "id must be zero when invoked with guid");742 job = sourceAdapter.GetJobByInstanceId(guid, recurse);743 }744 else if (typeof(T) == typeof(int))745 {746 Diagnostics.Assert(guid == Guid.Empty, "Guid must be empty when used with int");747 job = sourceAdapter.GetJobBySessionId(id, recurse);748 }749 }750 catch (Exception exception)751 {752 // Since we are calling into 3rd party code753 // catching Exception is allowed. In all754 // other cases the appropriate exception755 // needs to be caught.756 757 // sourceAdapter.GetJobByInstanceId threw unknown exception.758 _tracer.TraceException(exception);759 760 WriteErrorOrWarning(writeErrorOnException, cmdlet, exception, "JobSourceAdapterGetJobByInstanceIdError", sourceAdapter);761 }762 763 if (job == null)764 {765 continue;766 }767 768 if (writeObject)769 {770 cmdlet.WriteObject(job);771 }772 773 return job;774 }775 }776 777 return null;778 }779 780 /// <summary>781 /// Gets or creates a Job2 object with the given definition name, path782 /// and definition type if specified, that can be run via the StartJob()783 /// method.784 /// </summary>785 /// <param name="definitionName">Job definition name.</param>786 /// <param name="definitionPath">Job definition file path.</param>787 /// <param name="definitionType">JobSourceAdapter type that contains the job definition.</param>788 /// <param name="cmdlet">Cmdlet making call.</param>789 /// <param name="writeErrorOnException">Whether to write jobsourceadapter errors.</param>790 /// <returns>List of matching Job2 objects.</returns>791 internal List<Job2> GetJobToStart(792 string definitionName,793 string definitionPath,794 string definitionType,795 Cmdlet cmdlet,796 bool writeErrorOnException)797 {798 List<Job2> jobs = new List<Job2>();799 WildcardPattern typeNamePattern = (definitionType != null) ?800 WildcardPattern.Get(definitionType, WildcardOptions.IgnoreCase) : null;801 802 lock (_syncObject)803 {804 foreach (JobSourceAdapter sourceAdapter in _sourceAdapters.Values)805 {806 try807 {808 if (typeNamePattern != null)809 {810 string sourceAdapterName = GetAdapterName(sourceAdapter);811 if (!typeNamePattern.IsMatch(sourceAdapterName))812 {813 continue;814 }815 }816 817 Job2 job = sourceAdapter.NewJob(definitionName, definitionPath);818 if (job != null)819 {820 jobs.Add(job);821 }822 823 if (typeNamePattern != null)824 {825 // Adapter type found, can quit.826 break;827 }828 }829 catch (Exception exception)830 {831 // Since we are calling into 3rd party code832 // catching Exception is allowed. In all833 // other cases the appropriate exception834 // needs to be caught.835 836 _tracer.TraceException(exception);837 838 WriteErrorOrWarning(writeErrorOnException, cmdlet, exception, "JobSourceAdapterGetJobByInstanceIdError", sourceAdapter);839 }840 }841 }842 843 return jobs;844 }845 846 private static void WriteErrorOrWarning(bool writeErrorOnException, Cmdlet cmdlet, Exception exception, string identifier, JobSourceAdapter sourceAdapter)847 {848 try849 {850 if (writeErrorOnException)851 {852 cmdlet.WriteError(new ErrorRecord(exception, identifier, ErrorCategory.OpenError, sourceAdapter));853 }854 else855 {856 // Write a warning857 string message = string.Format(CultureInfo.CurrentCulture,858 RemotingErrorIdStrings.JobSourceAdapterError,859 exception.Message,860 sourceAdapter.Name);861 cmdlet.WriteWarning(message);862 }863 }864 catch (Exception)865 {866 // if this call is not made from a cmdlet thread or if867 // the cmdlet is closed this will thrown an exception868 // it is fine to eat that exception869 }870 }871 872 /// <summary>873 /// Returns a List of adapter names currently loaded.874 /// </summary>875 /// <param name="adapterTypeNames">Adapter names to filter on.</param>876 /// <returns>List of names.</returns>877 internal List<string> GetLoadedAdapterNames(string[] adapterTypeNames)878 {879 List<string> adapterNames = new List<string>();880 lock (_syncObject)881 {882 foreach (JobSourceAdapter sourceAdapter in _sourceAdapters.Values)883 {884 if (CheckTypeNames(sourceAdapter, adapterTypeNames))885 {886 adapterNames.Add(GetAdapterName(sourceAdapter));887 }888 }889 }890 891 return adapterNames;892 }893 894 #endregion GetJobs895 896 #region RemoveJob897 898 /// <summary>899 /// Remove a job from the appropriate store.900 /// </summary>901 /// <param name="sessionJobId">Session specific Job ID to remove.</param>902 /// <param name="cmdlet"></param>903 /// <param name="writeErrorOnException"></param>904 internal void RemoveJob(int sessionJobId, Cmdlet cmdlet, bool writeErrorOnException)905 {906 Job2 job = GetJobById(sessionJobId, cmdlet, writeErrorOnException, false, false);907 RemoveJob(job, cmdlet, false);908 }909 910 /// <summary>911 /// Remove a job from the appropriate store.912 /// </summary>913 /// <param name="job">Job object to remove.</param>914 /// <param name="cmdlet"></param>915 /// <param name="writeErrorOnException"></param>916 /// <param name="throwExceptions">If true, will throw all JobSourceAdapter exceptions to caller.917 /// This is needed if RemoveJob is being called from an event handler in Receive-Job.</param>918 /// <returns>True if job is found.</returns>919 internal bool RemoveJob(Job2 job, Cmdlet cmdlet, bool writeErrorOnException, bool throwExceptions = false)920 {921 bool jobFound = false;922 923 lock (_syncObject)924 {925 foreach (JobSourceAdapter sourceAdapter in _sourceAdapters.Values)926 {927 Job2 foundJob = null;928#pragma warning disable 56500929 try930 {931 foundJob = sourceAdapter.GetJobByInstanceId(job.InstanceId, true);932 }933 catch (Exception exception)934 {935 // Since we are calling into 3rd party code936 // catching Exception is allowed. In all937 // other cases the appropriate exception938 // needs to be caught.939 940 // sourceAdapter.GetJobByInstanceId() threw unknown exception.941 _tracer.TraceException(exception);942 if (throwExceptions)943 {944 throw;945 }946 947 WriteErrorOrWarning(writeErrorOnException, cmdlet, exception, "JobSourceAdapterGetJobError", sourceAdapter);948 }949#pragma warning restore 56500950 951 if (foundJob == null)952 {953 continue;954 }955 956 jobFound = true;957 RemoveJobIdForReuse(foundJob);958 959#pragma warning disable 56500960 try961 {962 sourceAdapter.RemoveJob(job);963 }964 catch (Exception exception)965 {966 // Since we are calling into 3rd party code967 // catching Exception is allowed. In all968 // other cases the appropriate exception969 // needs to be caught.970 // sourceAdapter.RemoveJob() threw unknown exception.971 972 _tracer.TraceException(exception);973 if (throwExceptions)974 {975 throw;976 }977 978 WriteErrorOrWarning(writeErrorOnException, cmdlet, exception, "JobSourceAdapterRemoveJobError", sourceAdapter);979 }980#pragma warning restore 56500981 }982 }983 984 if (!jobFound && throwExceptions)985 {986 var message = PSRemotingErrorInvariants.FormatResourceString(RemotingErrorIdStrings.ItemNotFoundInRepository,987 "Job repository", job.InstanceId.ToString());988 throw new ArgumentException(message);989 }990 991 return jobFound;992 }993 994 private void RemoveJobIdForReuse(Job job)995 {996 Hashtable duplicateDetector = new Hashtable();997 duplicateDetector.Add(job.Id, job.Id);998 999 RemoveJobIdForReuseHelper(duplicateDetector, job);1000 }1001 1002 private void RemoveJobIdForReuseHelper(Hashtable duplicateDetector, Job job)1003 {1004 lock (s_syncObject)1005 {1006 s_jobIdsForReuse.Remove(job.InstanceId);1007 }1008 1009 foreach (Job child in job.ChildJobs)1010 {1011 if (duplicateDetector.ContainsKey(child.Id))1012 {1013 continue;1014 }1015 1016 duplicateDetector.Add(child.Id, child.Id);1017 1018 RemoveJobIdForReuse(child);1019 }1020 }1021 1022 #endregion RemoveJob1023 1024 /// <summary>1025 /// Filters available for GetJob, used internally to centralize Exception handling.1026 /// </summary>1027 private enum FilterType1028 {1029 /// <summary>1030 /// Use no filter.1031 /// </summary>1032 None,1033 1034 /// <summary>1035 /// Filter on command (string).1036 /// </summary>1037 Command,1038 1039 /// <summary>1040 /// Filter on custom dictionary (dictionary(string, object)).1041 /// </summary>1042 Filter,1043 1044 /// <summary>1045 /// Filter on name (string).1046 /// </summary>1047 Name,1048 1049 /// <summary>1050 /// Filter on job state (JobState).1051 /// </summary>1052 State1053 }1054 }1055}1056 