Team Ai
Datasetpublic

MegaBites-AI/Windows-powershell

sourceHugging Facemitupdated 6mo agoView on Hugging Face
0likes372downloads
PSTask.cs1594 linesDownload Raw Back to hostifaces
1// Copyright (c) Microsoft Corporation.2// Licensed under the MIT License.3 4using System.Collections.Concurrent;5using System.Collections.Generic;6using System.Globalization;7using System.Management.Automation.Host;8using System.Management.Automation.Language;9using System.Management.Automation.Remoting.Internal;10using System.Management.Automation.Runspaces;11using System.Management.Automation.Security;12using System.Threading;13 14using Dbg = System.Management.Automation.Diagnostics;15 16namespace System.Management.Automation.PSTasks17{18    #region PSTask19 20    /// <summary>21    /// Class to encapsulate synchronous running scripts in parallel.22    /// </summary>23    internal sealed class PSTask : PSTaskBase24    {25        #region Members26 27        private readonly PSTaskDataStreamWriter _dataStreamWriter;28 29        #endregion30 31        #region Constructor32 33        /// <summary>34        /// Initializes a new instance of the <see cref="PSTask"/> class.35        /// </summary>36        /// <param name="scriptBlock">Script block to run in task.</param>37        /// <param name="usingValuesMap">Using values passed into script block.</param>38        /// <param name="dollarUnderbar">Dollar underbar variable value.</param>39        /// <param name="currentLocationPath">Current working directory.</param>40        /// <param name="dataStreamWriter">Cmdlet data stream writer.</param>41        public PSTask(42            ScriptBlock scriptBlock,43            Dictionary<string, object> usingValuesMap,44            object dollarUnderbar,45            string currentLocationPath,46            PSTaskDataStreamWriter dataStreamWriter)47            : base(48                scriptBlock,49                usingValuesMap,50                dollarUnderbar,51                currentLocationPath)52        {53            _dataStreamWriter = dataStreamWriter;54        }55 56        #endregion57 58        #region Overrides59 60        /// <summary>61        /// Initialize PowerShell object.62        /// </summary>63        protected override void InitializePowershell()64        {65            // Writer data stream handlers66            _output.DataAdded += (sender, args) => HandleOutputData();67            _powershell.Streams.Error.DataAdded += (sender, args) => HandleErrorData();68            _powershell.Streams.Warning.DataAdded += (sender, args) => HandleWarningData();69            _powershell.Streams.Verbose.DataAdded += (sender, args) => HandleVerboseData();70            _powershell.Streams.Debug.DataAdded += (sender, args) => HandleDebugData();71            _powershell.Streams.Progress.DataAdded += (sender, args) => HandleProgressData();72            _powershell.Streams.Information.DataAdded += (sender, args) => HandleInformationData();73 74            // State change handler75            _powershell.InvocationStateChanged += (sender, args) => HandleStateChanged(args);76        }77 78        #endregion79 80        #region Writer data stream handlers81 82        private void HandleOutputData()83        {84            foreach (var item in _output.ReadAll())85            {86                _dataStreamWriter.Add(87                    new PSStreamObject(PSStreamObjectType.Output, item));88            }89        }90 91        private void HandleErrorData()92        {93            foreach (var item in _powershell.Streams.Error.ReadAll())94            {95                _dataStreamWriter.Add(96                    new PSStreamObject(PSStreamObjectType.Error, item));97            }98        }99 100        private void HandleWarningData()101        {102            foreach (var item in _powershell.Streams.Warning.ReadAll())103            {104                _dataStreamWriter.Add(105                    new PSStreamObject(PSStreamObjectType.Warning, item.Message));106            }107        }108 109        private void HandleVerboseData()110        {111            foreach (var item in _powershell.Streams.Verbose.ReadAll())112            {113                _dataStreamWriter.Add(114                    new PSStreamObject(PSStreamObjectType.Verbose, item.Message));115            }116        }117 118        private void HandleDebugData()119        {120            foreach (var item in _powershell.Streams.Debug.ReadAll())121            {122                _dataStreamWriter.Add(123                    new PSStreamObject(PSStreamObjectType.Debug, item.Message));124            }125        }126 127        private void HandleInformationData()128        {129            foreach (var item in _powershell.Streams.Information.ReadAll())130            {131                _dataStreamWriter.Add(132                    new PSStreamObject(PSStreamObjectType.Information, item));133            }134        }135 136        private void HandleProgressData()137        {138            foreach (var item in _powershell.Streams.Progress.ReadAll())139            {140                _dataStreamWriter.Add(141                    new PSStreamObject(PSStreamObjectType.Progress, item));142            }143        }144 145        #endregion146 147        #region Event handlers148 149        private void HandleStateChanged(PSInvocationStateChangedEventArgs stateChangeInfo)150        {151            if (_dataStreamWriter != null)152            {153                // Treat any terminating exception as a non-terminating error record154                var newStateInfo = stateChangeInfo.InvocationStateInfo;155                if (newStateInfo.Reason != null)156                {157                    var errorRecord = new ErrorRecord(158                        newStateInfo.Reason,159                        "PSTaskException",160                        ErrorCategory.InvalidOperation,161                        this);162 163                    _dataStreamWriter.Add(164                        new PSStreamObject(PSStreamObjectType.Error, errorRecord));165                }166            }167 168            RaiseStateChangedEvent(stateChangeInfo);169        }170 171        #endregion172    }173 174    /// <summary>175    /// Class to encapsulate asynchronous running scripts in parallel as jobs.176    /// </summary>177    internal sealed class PSJobTask : PSTaskBase178    {179        #region Members180 181        private readonly Job _job;182 183        #endregion184 185        #region Constructor186 187        /// <summary>188        /// Initializes a new instance of the <see cref="PSJobTask"/> class.189        /// </summary>190        /// <param name="scriptBlock">Script block to run.</param>191        /// <param name="usingValuesMap">Using variable values passed to script block.</param>192        /// <param name="dollarUnderbar">Dollar underbar variable value for script block.</param>193        /// <param name="currentLocationPath">Current working directory.</param>194        /// <param name="job">Job object associated with task.</param>195        public PSJobTask(196            ScriptBlock scriptBlock,197            Dictionary<string, object> usingValuesMap,198            object dollarUnderbar,199            string currentLocationPath,200            Job job) : base(201                scriptBlock,202                usingValuesMap,203                dollarUnderbar,204                currentLocationPath)205        {206            _job = job;207        }208 209        #endregion210 211        #region Overrides212 213        /// <summary>214        /// Initialize PowerShell object.215        /// </summary>216        protected override void InitializePowershell()217        {218            // Job data stream handlers219            _output.DataAdded += (sender, args) => HandleJobOutputData();220            _powershell.Streams.Error.DataAdded += (sender, args) => HandleJobErrorData();221            _powershell.Streams.Warning.DataAdded += (sender, args) => HandleJobWarningData();222            _powershell.Streams.Verbose.DataAdded += (sender, args) => HandleJobVerboseData();223            _powershell.Streams.Debug.DataAdded += (sender, args) => HandleJobDebugData();224            _powershell.Streams.Information.DataAdded += (sender, args) => HandleJobInformationData();225 226            // State change handler227            _powershell.InvocationStateChanged += (sender, args) => HandleStateChanged(args);228        }229 230        #endregion231 232        #region Job data stream handlers233 234        private void HandleJobOutputData()235        {236            foreach (var item in _output.ReadAll())237            {238                _job.Output.Add(item);239                _job.Results.Add(240                    new PSStreamObject(PSStreamObjectType.Output, item));241            }242        }243 244        private void HandleJobErrorData()245        {246            foreach (var item in _powershell.Streams.Error.ReadAll())247            {248                _job.Error.Add(item);249                _job.Results.Add(250                    new PSStreamObject(PSStreamObjectType.Error, item));251            }252        }253 254        private void HandleJobWarningData()255        {256            foreach (var item in _powershell.Streams.Warning.ReadAll())257            {258                _job.Warning.Add(item);259                _job.Results.Add(260                    new PSStreamObject(PSStreamObjectType.Warning, item.Message));261            }262        }263 264        private void HandleJobVerboseData()265        {266            foreach (var item in _powershell.Streams.Verbose.ReadAll())267            {268                _job.Verbose.Add(item);269                _job.Results.Add(270                    new PSStreamObject(PSStreamObjectType.Verbose, item.Message));271            }272        }273 274        private void HandleJobDebugData()275        {276            foreach (var item in _powershell.Streams.Debug.ReadAll())277            {278                _job.Debug.Add(item);279                _job.Results.Add(280                    new PSStreamObject(PSStreamObjectType.Debug, item.Message));281            }282        }283 284        private void HandleJobInformationData()285        {286            foreach (var item in _powershell.Streams.Information.ReadAll())287            {288                _job.Information.Add(item);289                _job.Results.Add(290                    new PSStreamObject(PSStreamObjectType.Information, item));291            }292        }293 294        #endregion295 296        #region Event handlers297 298        private void HandleStateChanged(PSInvocationStateChangedEventArgs stateChangeInfo)299        {300            RaiseStateChangedEvent(stateChangeInfo);301        }302 303        #endregion304 305        #region Properties306 307        /// <summary>308        /// Gets Debugger.309        /// </summary>310        public Debugger Debugger311        {312            get => _powershell.Runspace.Debugger;313        }314 315        #endregion316    }317 318    /// <summary>319    /// Base class to encapsulate running a PowerShell script concurrently in a cmdlet or job context.320    /// </summary>321    internal abstract class PSTaskBase : IDisposable322    {323        #region Members324 325        private readonly ScriptBlock _scriptBlockToRun;326        private readonly Dictionary<string, object> _usingValuesMap;327        private readonly object _dollarUnderbar;328        private readonly int _id;329        private readonly string _currentLocationPath;330        private Runspace _runspace;331        protected PowerShell _powershell;332        protected PSDataCollection<PSObject> _output;333 334        public const string RunspaceName = "PSTask";335 336        private static int s_taskId;337 338        #endregion339 340        #region Events341 342        /// <summary>343        /// Event that fires when the task running state changes.344        /// </summary>345        public event EventHandler<PSInvocationStateChangedEventArgs> StateChanged;346 347        internal void RaiseStateChangedEvent(PSInvocationStateChangedEventArgs args)348        {349            StateChanged.SafeInvoke(this, args);350        }351 352        #endregion353 354        #region Properties355 356        /// <summary>357        /// Gets current running state of the task.358        /// </summary>359        public PSInvocationState State360        {361            get362            {363                PowerShell ps = _powershell;364                if (ps != null)365                {366                    return ps.InvocationStateInfo.State;367                }368 369                return PSInvocationState.NotStarted;370            }371        }372 373        /// <summary>374        /// Gets Task Id.375        /// </summary>376        public int Id { get => _id; }377 378        /// <summary>379        /// Gets Task Runspace.380        /// </summary>381        public Runspace Runspace { get => _runspace; }382 383        #endregion384 385        #region Constructor386 387        private PSTaskBase()388        {389            _id = Interlocked.Increment(ref s_taskId);390        }391 392        /// <summary>393        /// Initializes a new instance of the <see cref="PSTaskBase"/> class.394        /// </summary>395        /// <param name="scriptBlock">Script block to run.</param>396        /// <param name="usingValuesMap">Using variable values passed to script block.</param>397        /// <param name="dollarUnderbar">Dollar underbar variable value.</param>398        /// <param name="currentLocationPath">Current working directory.</param>399        protected PSTaskBase(400            ScriptBlock scriptBlock,401            Dictionary<string, object> usingValuesMap,402            object dollarUnderbar,403            string currentLocationPath) : this()404        {405            _scriptBlockToRun = scriptBlock;406            _usingValuesMap = usingValuesMap;407            _dollarUnderbar = dollarUnderbar;408            _currentLocationPath = currentLocationPath;409        }410 411        #endregion412 413        #region Abstract Methods414 415        /// <summary>416        /// Initialize PowerShell object.417        /// </summary>418        protected abstract void InitializePowershell();419 420        #endregion421 422        #region IDisposable423 424        /// <summary>425        /// Dispose PSTaskBase instance.426        /// </summary>427        public void Dispose()428        {429            _powershell.Dispose();430            _output.Dispose();431        }432 433        #endregion434 435        #region Public Methods436 437        /// <summary>438        /// Start task.439        /// </summary>440        /// <param name="runspace">Runspace used to run task.</param>441        public void Start(Runspace runspace)442        {443            if (_powershell != null)444            {445                Dbg.Assert(false, "A PSTask can be started only once.");446                return;447            }448 449            Dbg.Assert(runspace != null, "Task runspace cannot be null.");450            _runspace = runspace;451 452            // If available, set current working directory on the runspace.453            // Temporarily set the newly created runspace as the thread default runspace for any needed module loading.454            if (_currentLocationPath != null)455            {456                var oldDefaultRunspace = Runspace.DefaultRunspace;457                try458                {459                    Runspace.DefaultRunspace = runspace;460                    var context = new CmdletProviderContext(runspace.ExecutionContext)461                    {462                        // _currentLocationPath denotes the current path as-is, and should not be attempted expanded.463                        SuppressWildcardExpansion = true464                    };465                    runspace.ExecutionContext.SessionState.Internal.SetLocation(_currentLocationPath, context);466                }467                catch (DriveNotFoundException)468                {469                    // Allow task to run if current drive is not available.470                }471                finally472                {473                    Runspace.DefaultRunspace = oldDefaultRunspace;474                }475            }476 477            // Create the PowerShell command pipeline for the provided script block478            // The script will run on the provided Runspace in a new thread by default479            _powershell = PowerShell.Create(runspace);480 481            // Initialize PowerShell object data streams and event handlers482            _output = new PSDataCollection<PSObject>();483            InitializePowershell();484 485            // Start the script running in a new thread486            _powershell.AddScript(_scriptBlockToRun.ToString());487            _powershell.Commands.Commands[0].DollarUnderbar = _dollarUnderbar;488            if (_usingValuesMap != null && _usingValuesMap.Count > 0)489            {490                _powershell.AddParameter(Parser.VERBATIM_ARGUMENT, _usingValuesMap);491            }492 493            _powershell.BeginInvoke<object, PSObject>(input: null, output: _output);494        }495 496        /// <summary>497        /// Signals the running task to stop.498        /// </summary>499        public void SignalStop() => _powershell?.BeginStop(null, null);500 501        #endregion502    }503 504    #endregion505 506    #region PSTaskDataStreamWriter507 508    /// <summary>509    /// Class that handles writing task data stream objects to a cmdlet.510    /// </summary>511    internal sealed class PSTaskDataStreamWriter : IDisposable512    {513        #region Members514 515        private readonly PSCmdlet _cmdlet;516        private readonly PSDataCollection<PSStreamObject> _dataStream;517        private readonly int _cmdletThreadId;518 519        #endregion520 521        #region Properties522 523        /// <summary>524        /// Gets wait-able handle that signals when new data has been added to525        /// the data stream collection.526        /// </summary>527        /// <returns>Data added wait handle.</returns>528        internal WaitHandle DataAddedWaitHandle529        {530            get => _dataStream.WaitHandle;531        }532 533        #endregion534 535        #region Constructor536 537        private PSTaskDataStreamWriter() { }538 539        /// <summary>540        /// Initializes a new instance of the <see cref="PSTaskDataStreamWriter"/> class.541        /// </summary>542        /// <param name="psCmdlet">Parent cmdlet.</param>543        public PSTaskDataStreamWriter(PSCmdlet psCmdlet)544        {545            _cmdlet = psCmdlet;546            _cmdletThreadId = Environment.CurrentManagedThreadId;547            _dataStream = new PSDataCollection<PSStreamObject>();548        }549 550        #endregion551 552        #region Public Methods553 554        /// <summary>555        /// Add data stream object to the writer.556        /// </summary>557        /// <param name="streamObject">Data stream object to write.</param>558        public void Add(PSStreamObject streamObject)559        {560            _dataStream.Add(streamObject);561        }562 563        /// <summary>564        /// Write all objects in data stream collection to the cmdlet data stream.565        /// </summary>566        public void WriteImmediate()567        {568            CheckCmdletThread();569 570            foreach (var item in _dataStream.ReadAll())571            {572                item.WriteStreamObject(cmdlet: _cmdlet, overrideInquire: true);573            }574        }575 576        /// <summary>577        /// Waits for data stream objects to be added to the collection, and writes them578        /// to the cmdlet data stream.579        /// This method returns only after the writer has been closed.580        /// </summary>581        public void WaitAndWrite()582        {583            CheckCmdletThread();584 585            while (true)586            {587                _dataStream.WaitHandle.WaitOne();588                WriteImmediate();589 590                if (!_dataStream.IsOpen)591                {592                    WriteImmediate();593                    break;594                }595            }596        }597 598        /// <summary>599        /// Closes the stream writer.600        /// </summary>601        public void Close()602        {603            _dataStream.Complete();604        }605 606        #endregion607 608        #region Private Methods609 610        private void CheckCmdletThread()611        {612            if (Environment.CurrentManagedThreadId != _cmdletThreadId)613            {614                throw new PSInvalidOperationException(InternalCommandStrings.PSTaskStreamWriterWrongThread);615            }616        }617 618        #endregion619 620        #region IDisposable621 622        /// <summary>623        /// Dispose the stream writer.624        /// </summary>625        public void Dispose()626        {627            _dataStream.Dispose();628        }629 630        #endregion631    }632 633    #endregion634 635    #region PSTaskPool636 637    /// <summary>638    /// Pool for running PSTasks, with limit of total number of running tasks at a time.639    /// </summary>640    internal sealed class PSTaskPool : IDisposable641    {642        #region Members643 644        private readonly ManualResetEvent _addAvailable;645        private readonly int _sizeLimit;646        private readonly ManualResetEvent _stopAll;647        private readonly object _syncObject;648        private readonly Dictionary<int, PSTaskBase> _taskPool;649        private readonly ConcurrentQueue<Runspace> _runspacePool;650        private readonly ConcurrentDictionary<int, Runspace> _activeRunspaces;651        private readonly WaitHandle[] _waitHandles;652        private readonly bool _useRunspacePool;653        private bool _isOpen;654        private bool _stopping;655        private int _createdRunspaceCount;656 657        private const int AddAvailable = 0;658        private const int Stop = 1;659 660        #endregion661 662        #region Constructor663 664        private PSTaskPool() { }665 666        /// <summary>667        /// Initializes a new instance of the <see cref="PSTaskPool"/> class.668        /// </summary>669        /// <param name="size">Total number of allowed running objects in pool at one time.</param>670        /// <param name="useNewRunspace">When true, a new runspace object is created for the task instead of reusing one from the pool.</param>671        public PSTaskPool(672            int size,673            bool useNewRunspace)674        {675            _sizeLimit = size;676            _useRunspacePool = !useNewRunspace;677            _isOpen = true;678            _syncObject = new object();679            _addAvailable = new ManualResetEvent(true);680            _stopAll = new ManualResetEvent(false);681            _waitHandles = new WaitHandle[]682            {683                _addAvailable,      // index 0684                _stopAll,           // index 1685            };686            _taskPool = new Dictionary<int, PSTaskBase>(size);687            _activeRunspaces = new ConcurrentDictionary<int, Runspace>();688            if (_useRunspacePool)689            {690                _runspacePool = new ConcurrentQueue<Runspace>();691            }692        }693 694        #endregion695 696        #region Events697 698        /// <summary>699        /// Event that fires when pool is closed and drained of all tasks.700        /// </summary>701        public event EventHandler<EventArgs> PoolComplete;702 703        #endregion704 705        #region Properties706 707        /// <summary>708        /// Gets a value indicating whether a pool is currently open for accepting tasks.709        /// </summary>710        public bool IsOpen711        {712            get => _isOpen;713        }714 715        /// <summary>716        /// Gets a value of the count of total runspaces allocated.717        /// </summary>718        public int AllocatedRunspaceCount719        {720            get => _createdRunspaceCount;721        }722 723        #endregion724 725        #region IDisposable726 727        /// <summary>728        /// Dispose task pool.729        /// </summary>730        public void Dispose()731        {732            _addAvailable.Dispose();733            _stopAll.Dispose();734 735            DisposeRunspaces();736        }737 738        /// <summary>739        /// Dispose runspaces.740        /// </summary>741        internal void DisposeRunspaces()742        {743            foreach (var item in _activeRunspaces)744            {745                item.Value.Dispose();746            }747 748            _activeRunspaces.Clear();749        }750 751        #endregion752 753        #region Public Methods754 755        /// <summary>756        /// Method to add a task to the pool.757        /// If the pool is full, then this method blocks until space is available.758        /// This method is not multi-thread safe and assumes only one thread waits and adds tasks.759        /// </summary>760        /// <param name="task">Task to be added to pool.</param>761        /// <returns>True when task is successfully added.</returns>762        public bool Add(PSTaskBase task)763        {764            if (!_isOpen)765            {766                return false;767            }768 769            // Block until either space is available, or a stop is commanded770            var index = WaitHandle.WaitAny(_waitHandles);771 772            switch (index)773            {774                case AddAvailable:775                    var runspace = GetRunspace(task.Id);776                    task.StateChanged += HandleTaskStateChangedDelegate;777                    lock (_syncObject)778                    {779                        if (!_isOpen)780                        {781                            return false;782                        }783 784                        _taskPool.Add(task.Id, task);785                        if (_taskPool.Count == _sizeLimit)786                        {787                            _addAvailable.Reset();788                        }789 790                        task.Start(runspace);791                    }792 793                    return true;794 795                case Stop:796                    return false;797 798                default:799                    return false;800            }801        }802 803        /// <summary>804        /// Add child job task to task pool.805        /// </summary>806        /// <param name="childJob">Child job to be added to pool.</param>807        /// <returns>True when child job is successfully added.</returns>808        public bool Add(PSTaskChildJob childJob)809        {810            return Add(childJob.Task);811        }812 813        /// <summary>814        /// Signals all running tasks to stop and closes pool for any new tasks.815        /// </summary>816        public void StopAll()817        {818            _stopping = true;819 820            // Accept no more input821            Close();822            _stopAll.Set();823 824            // Stop all running tasks825            PSTaskBase[] tasksToStop;826            lock (_syncObject)827            {828                tasksToStop = new PSTaskBase[_taskPool.Values.Count];829                _taskPool.Values.CopyTo(tasksToStop, 0);830            }831 832            foreach (var task in tasksToStop)833            {834                task.Dispose();835            }836 837            // Dispose all active runspaces838            DisposeRunspaces();839            _stopping = false;840        }841 842        /// <summary>843        /// Closes the pool and prevents any new tasks from being added.844        /// </summary>845        public void Close()846        {847            _isOpen = false;848            CheckForComplete();849        }850 851        #endregion852 853        #region Private Methods854 855        private void HandleTaskStateChangedDelegate(object sender, PSInvocationStateChangedEventArgs args) => HandleTaskStateChanged(sender, args);856 857        private void HandleTaskStateChanged(object sender, PSInvocationStateChangedEventArgs args)858        {859            var task = sender as PSTaskBase;860            Dbg.Assert(task != null, "State changed sender must always be PSTaskBase");861            var stateInfo = args.InvocationStateInfo;862            switch (stateInfo.State)863            {864                // Look for completed state and remove865                case PSInvocationState.Completed:866                case PSInvocationState.Stopped:867                case PSInvocationState.Failed:868                    ReturnRunspace(task);869                    lock (_syncObject)870                    {871                        _taskPool.Remove(task.Id);872                        if (_taskPool.Count == (_sizeLimit - 1))873                        {874                            _addAvailable.Set();875                        }876                    }877 878                    task.StateChanged -= HandleTaskStateChangedDelegate;879                    if (!_stopping || stateInfo.State != PSInvocationState.Stopped)880                    {881                        // StopAll disposes tasks.882                        task.Dispose();883                    }884 885                    CheckForComplete();886                    break;887            }888        }889 890        private void CheckForComplete()891        {892            bool isTaskPoolComplete;893            lock (_syncObject)894            {895                isTaskPoolComplete = !_isOpen && _taskPool.Count == 0;896            }897 898            if (isTaskPoolComplete)899            {900                try901                {902                    PoolComplete.SafeInvoke(903                        this,904                        new EventArgs());905                }906                catch907                {908                    Dbg.Assert(false, "Exceptions should not be thrown on event thread");909                }910            }911        }912 913        private Runspace GetRunspace(int taskId)914        {915            var runspaceName = string.Create(CultureInfo.InvariantCulture, $"{PSTask.RunspaceName}:{taskId}");916 917            if (_useRunspacePool && _runspacePool.TryDequeue(out Runspace runspace))918            {919                if (runspace.RunspaceStateInfo.State == RunspaceState.Opened &&920                    runspace.RunspaceAvailability == RunspaceAvailability.Available)921                {922                    try923                    {924                        runspace.ResetRunspaceState();925                        runspace.Name = runspaceName;926                        return runspace;927                    }928                    catch929                    {930                        // If the runspace cannot be reset for any reason, remove it.931                    }932                }933 934                RemoveActiveRunspace(runspace);935            }936 937            // Create and initialize a new Runspace938            var iss = InitialSessionState.CreateDefault2();939            switch (SystemPolicy.GetSystemLockdownPolicy())940            {941                case SystemEnforcementMode.Enforce:942                    iss.LanguageMode = PSLanguageMode.ConstrainedLanguage;943                    break;944 945                case SystemEnforcementMode.Audit:946                    // In audit mode, CL restrictions are not enforced and instead audit947                    // log entries are created.948                    iss.LanguageMode = PSLanguageMode.ConstrainedLanguage;949                    break;950 951                case SystemEnforcementMode.None:952                    iss.LanguageMode = PSLanguageMode.FullLanguage;953                    break;954            }955 956            runspace = RunspaceFactory.CreateRunspace(iss);957            runspace.Name = runspaceName;958            _activeRunspaces.TryAdd(runspace.Id, runspace);959            runspace.Open();960            _createdRunspaceCount++;961 962            return runspace;963        }964 965        private void ReturnRunspace(PSTaskBase task)966        {967            var runspace = task.Runspace;968            Dbg.Assert(runspace != null, "Task runspace cannot be null.");969            if (_useRunspacePool &&970                runspace.RunspaceStateInfo.State == RunspaceState.Opened &&971                runspace.RunspaceAvailability == RunspaceAvailability.Available)972            {973                _runspacePool.Enqueue(runspace);974                return;975            }976 977            RemoveActiveRunspace(runspace);978        }979 980        private void RemoveActiveRunspace(Runspace runspace)981        {982            runspace.Dispose();983            _activeRunspaces.TryRemove(runspace.Id, out Runspace _);984        }985 986        #endregion987    }988 989    #endregion990 991    #region PSTaskJobs992 993    /// <summary>994    /// Job for running ForEach-Object parallel task child jobs asynchronously.995    /// </summary>996    public sealed class PSTaskJob : Job997    {998        #region Members999 1000        private readonly PSTaskPool _taskPool;1001        private bool _isOpen;1002        private bool _stopSignaled;1003 1004        #endregion1005 1006        #region Properties1007 1008        /// <summary>1009        /// Gets a value of the count of total runspaces allocated.1010        /// </summary>1011        public int AllocatedRunspaceCount1012        {1013            get => _taskPool.AllocatedRunspaceCount;1014        }1015 1016        #endregion1017 1018        #region Constructor1019 1020        private PSTaskJob() { }1021 1022        /// <summary>1023        /// Initializes a new instance of the <see cref="PSTaskJob"/> class.1024        /// </summary>1025        /// <param name="command">Job command text.</param>1026        /// <param name="throttleLimit">Pool size limit for task job.</param>1027        /// <param name="useNewRunspace">When true, a new runspace object is created for the task instead of reusing one from the pool.</param>1028        internal PSTaskJob(1029            string command,1030            int throttleLimit,1031            bool useNewRunspace) : base(command, string.Empty)1032        {1033            _taskPool = new PSTaskPool(throttleLimit, useNewRunspace);1034            _isOpen = true;1035            PSJobTypeName = nameof(PSTaskJob);1036 1037            _taskPool.PoolComplete += (sender, args) => HandleTaskPoolComplete(sender, args);1038        }1039 1040        #endregion1041 1042        #region Overrides1043 1044        /// <summary>1045        /// Gets Location.1046        /// </summary>1047        public override string Location1048        {1049            get => "PowerShell";1050        }1051 1052        /// <summary>1053        /// Gets HasMoreData.1054        /// </summary>1055        public override bool HasMoreData1056        {1057            get1058            {1059                foreach (var childJob in ChildJobs)1060                {1061                    if (childJob.HasMoreData)1062                    {1063                        return true;1064                    }1065                }1066 1067                return false;1068            }1069        }1070 1071        /// <summary>1072        /// Gets StatusMessage.1073        /// </summary>1074        public override string StatusMessage1075        {1076            get => string.Empty;1077        }1078 1079        /// <summary>1080        /// Stops running job.1081        /// </summary>1082        public override void StopJob()1083        {1084            _stopSignaled = true;1085            SetJobState(JobState.Stopping);1086 1087            _taskPool.StopAll();1088            SetJobState(JobState.Stopped);1089        }1090 1091        /// <summary>1092        /// Disposes task job.1093        /// </summary>1094        /// <param name="disposing">Indicates disposing action.</param>1095        protected override void Dispose(bool disposing)1096        {1097            if (disposing)1098            {1099                _taskPool.Dispose();1100            }1101 1102            base.Dispose(disposing);1103        }1104 1105        #endregion1106 1107        #region Internal Methods1108 1109        /// <summary>1110        /// Add a child job to the collection.1111        /// </summary>1112        /// <param name="childJob">Child job to add.</param>1113        /// <returns>True when child job is successfully added.</returns>1114        internal bool AddJob(PSTaskChildJob childJob)1115        {1116            if (!_isOpen)1117            {1118                return false;1119            }1120 1121            ChildJobs.Add(childJob);1122            return true;1123        }1124 1125        /// <summary>1126        /// Closes this parent job to adding more child jobs and starts1127        /// the child jobs running with the provided throttle limit.1128        /// </summary>1129        internal void Start()1130        {1131            _isOpen = false;1132            SetJobState(JobState.Running);1133 1134            // Submit jobs to the task pool, blocking when throttle limit is reached.1135            // This thread will end once all jobs reach a finished state by either running1136            // to completion, terminating with error, or stopped.1137            System.Threading.ThreadPool.QueueUserWorkItem(1138                (_) =>1139                {1140                    foreach (var childJob in ChildJobs)1141                    {1142                        _taskPool.Add((PSTaskChildJob)childJob);1143                    }1144 1145                    _taskPool.Close();1146                });1147        }1148 1149        #endregion1150 1151        #region Private Methods1152 1153        private void HandleTaskPoolComplete(object sender, EventArgs args)1154        {1155            try1156            {1157                if (_stopSignaled)1158                {1159                    SetJobState(JobState.Stopped, new PipelineStoppedException());1160                    return;1161                }1162 1163                // Final state will be 'Complete', only if all child jobs completed successfully.1164                JobState finalState = JobState.Completed;1165                foreach (var childJob in ChildJobs)1166                {1167                    if (childJob.JobStateInfo.State != JobState.Completed)1168                    {1169                        finalState = JobState.Failed;1170                        break;1171                    }1172                }1173 1174                SetJobState(finalState);1175 1176                // Release job task pool runspace resources.1177                (sender as PSTaskPool).DisposeRunspaces();1178            }1179            catch (ObjectDisposedException)1180            { }1181        }1182 1183        #endregion1184    }1185 1186    /// <summary>1187    /// PSTaskChildJob debugger wrapper.1188    /// </summary>1189    internal sealed class PSTaskChildDebugger : Debugger1190    {1191        #region Members1192 1193        private readonly Debugger _wrappedDebugger;1194        private readonly string _jobName;1195 1196        #endregion1197 1198        #region Constructor1199 1200        private PSTaskChildDebugger() { }

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