Team Ai
Datasetpublic

MegaBites-AI/Windows-powershell

sourceHugging Facemitupdated 6mo agoView on Hugging Face
0likes372downloads
DebugJob.cs478 linesDownload Raw Back to commands
1// Copyright (c) Microsoft Corporation.2// Licensed under the MIT License.3 4using System;5using System.Collections.Generic;6using System.Diagnostics.CodeAnalysis;7using System.Management.Automation;8using System.Management.Automation.Internal;9using System.Management.Automation.Remoting.Internal;10using System.Management.Automation.Runspaces;11 12namespace Microsoft.PowerShell.Commands13{14    /// <summary>15    /// This cmdlet takes a Job object and checks to see if it is debuggable.  If it16    /// is debuggable then it breaks into the job debugger in step mode.  If it is not17    /// debuggable then it is treated as a parent job and each child job is checked if18    /// it is debuggable and if it is will break into its job debugger in step mode.19    /// For multiple debuggable child jobs, each job execution will be halted and the20    /// debugger will step to each job execution point sequentially.21    ///22    /// When a job is debugged its output data is written to host and the executing job23    /// script will break into the host debugger, in step mode, at the next stoppable24    /// execution point.25    /// </summary>26    [SuppressMessage("Microsoft.PowerShell", "PS1012:CallShouldProcessOnlyIfDeclaringSupport")]27    [Cmdlet(VerbsDiagnostic.Debug, "Job", SupportsShouldProcess = true, DefaultParameterSetName = DebugJobCommand.JobParameterSet,28        HelpUri = "https://go.microsoft.com/fwlink/?LinkId=330208")]29    public sealed class DebugJobCommand : PSCmdlet30    {31        #region Strings32 33        private const string JobParameterSet = "JobParameterSet";34        private const string JobNameParameterSet = "JobNameParameterSet";35        private const string JobIdParameterSet = "JobIdParameterSet";36        private const string JobInstanceIdParameterSet = "JobInstanceIdParameterSet";37 38        #endregion39 40        #region Private members41 42        private Job _job;43        private Debugger _debugger;44        private PSDataCollection<PSStreamObject> _debugCollection;45 46        #endregion47 48        #region Parameters49 50        /// <summary>51        /// The Job object to be debugged.52        /// </summary>53        [Parameter(Position = 0,54                   Mandatory = true,55                   ValueFromPipelineByPropertyName = true,56                   ValueFromPipeline = true,57                   ParameterSetName = DebugJobCommand.JobParameterSet)]58        public Job Job59        {60            get;61            set;62        }63 64        /// <summary>65        /// The Job object name to be debugged.66        /// </summary>67        [Parameter(Position = 0,68                   Mandatory = true,69                   ParameterSetName = DebugJobCommand.JobNameParameterSet)]70        public string Name71        {72            get;73            set;74        }75 76        /// <summary>77        /// The Job object Id to be debugged.78        /// </summary>79        [Parameter(Position = 0,80                   Mandatory = true,81                   ParameterSetName = DebugJobCommand.JobIdParameterSet)]82        public int Id83        {84            get;85            set;86        }87 88        /// <summary>89        /// The Job object InstanceId to be debugged.90        /// </summary>91        [Parameter(Position = 0,92                   Mandatory = true,93                   ParameterSetName = DebugJobCommand.JobInstanceIdParameterSet)]94        public Guid InstanceId95        {96            get;97            set;98        }99 100        /// <summary>101        /// Gets or sets a flag that tells PowerShell to automatically perform a BreakAll when the debugger is attached to the remote target.102        /// </summary>103        [Parameter]104        public SwitchParameter BreakAll { get; set; }105 106        #endregion107 108        #region Overrides109 110        /// <summary>111        /// End processing.  Do work.112        /// </summary>113        protected override void EndProcessing()114        {115            switch (ParameterSetName)116            {117                case DebugJobCommand.JobParameterSet:118                    _job = Job;119                    break;120 121                case DebugJobCommand.JobNameParameterSet:122                    _job = GetJobByName(Name);123                    break;124 125                case DebugJobCommand.JobIdParameterSet:126                    _job = GetJobById(Id);127                    break;128 129                case DebugJobCommand.JobInstanceIdParameterSet:130                    _job = GetJobByInstanceId(InstanceId);131                    break;132            }133 134            if (!ShouldProcess(_job.Name, VerbsDiagnostic.Debug))135            {136                return;137            }138 139            Runspace runspace = LocalRunspace.DefaultRunspace;140            if (runspace == null || runspace.Debugger == null)141            {142                ThrowTerminatingError(143                    new ErrorRecord(144                        new PSInvalidOperationException(RemotingErrorIdStrings.CannotDebugJobNoHostDebugger),145                        "DebugJobNoHostDebugger",146                        ErrorCategory.InvalidOperation,147                        this)148                    );149            }150 151            if ((runspace.Debugger.DebugMode == DebugModes.Default) || (runspace.Debugger.DebugMode == DebugModes.None))152            {153                ThrowTerminatingError(154                    new ErrorRecord(155                        new PSInvalidOperationException(RemotingErrorIdStrings.CannotDebugJobInvalidDebuggerMode),156                        "DebugJobWrongDebugMode",157                        ErrorCategory.InvalidOperation,158                        this)159                    );160            }161 162            if (this.Host == null || this.Host.UI == null)163            {164                ThrowTerminatingError(165                    new ErrorRecord(166                        new PSInvalidOperationException(RemotingErrorIdStrings.CannotDebugJobNoHostUI),167                        "DebugJobNoHostAvailable",168                        ErrorCategory.InvalidOperation,169                        this)170                    );171            }172 173            if (!CheckForDebuggableJob())174            {175                ThrowTerminatingError(176                    new ErrorRecord(177                        new PSInvalidOperationException(DebuggerStrings.NoDebuggableJobsFound),178                        "DebugJobNoDebuggableJobsFound",179                        ErrorCategory.InvalidOperation,180                        this)181                    );182            }183 184            // Set up host script debugger to debug the job.185            _debugger = runspace.Debugger;186            _debugger.DebugJob(_job, breakAll: BreakAll);187 188            // Blocking call.  Send job output to host UI while debugging and wait for Job completion.189            WaitAndReceiveJobOutput();190        }191 192        /// <summary>193        /// Stop processing.194        /// </summary>195        protected override void StopProcessing()196        {197            // Cancel job debugging.198            Debugger debugger = _debugger;199            if ((debugger != null) && (_job != null))200            {201                debugger.StopDebugJob(_job);202            }203 204            // Unblock the data collection.205            PSDataCollection<PSStreamObject> debugCollection = _debugCollection;206            debugCollection?.Complete();207        }208 209        #endregion210 211        #region Private methods212 213        /// <summary>214        /// Check for debuggable job.  Job must implement IJobDebugger and also215        /// must be running or in Debug stopped state.216        /// </summary>217        /// <returns></returns>218        private bool CheckForDebuggableJob()219        {220            // Check passed in job object.221            bool debuggableJobFound = GetJobDebuggable(_job);222 223            if (!debuggableJobFound)224            {225                // Assume passed in job is a container job and check child jobs.226                foreach (var cJob in _job.ChildJobs)227                {228                    debuggableJobFound = GetJobDebuggable(cJob);229                    if (debuggableJobFound)230                    {231                        break;232                    }233                }234            }235 236            return debuggableJobFound;237        }238 239        private static bool GetJobDebuggable(Job job)240        {241            if (job is IJobDebugger)242            {243                return ((job.JobStateInfo.State == JobState.Running) ||244                        (job.JobStateInfo.State == JobState.AtBreakpoint));245            }246 247            return false;248        }249 250        private void WaitAndReceiveJobOutput()251        {252            _debugCollection = new PSDataCollection<PSStreamObject>();253            _debugCollection.BlockingEnumerator = true;254 255            try256            {257                AddEventHandlers();258 259                // This call blocks (blocking enumerator) until the job completes260                // or this command is cancelled.261                foreach (var streamItem in _debugCollection)262                {263                    streamItem?.WriteStreamObject(this);264                }265            }266            catch (Exception)267            {268                // Terminate job on exception.269                if (!_job.IsFinishedState(_job.JobStateInfo.State))270                {271                    _job.StopJob();272                }273 274                throw;275            }276            finally277            {278                RemoveEventHandlers();279                _debugCollection = null;280            }281        }282 283        private void HandleJobStateChangedEvent(object sender, JobStateEventArgs stateChangedArgs)284        {285            Job job = sender as Job;286            if (job.IsFinishedState(stateChangedArgs.JobStateInfo.State))287            {288                _debugCollection.Complete();289            }290        }291 292        private void HandleResultsDataAdding(object sender, DataAddingEventArgs dataAddingArgs)293        {294            if (_debugCollection.IsOpen)295            {296                PSStreamObject streamObject = dataAddingArgs.ItemAdded as PSStreamObject;297                if (streamObject != null)298                {299                    try300                    {301                        _debugCollection.Add(streamObject);302                    }303                    catch (PSInvalidOperationException) { }304                }305            }306        }307 308        private void HandleDebuggerNestedDebuggingCancelledEvent(object sender, EventArgs e)309        {310            StopProcessing();311        }312 313        private void AddEventHandlers()314        {315            _job.StateChanged += HandleJobStateChangedEvent;316            _debugger.NestedDebuggingCancelledEvent += HandleDebuggerNestedDebuggingCancelledEvent;317 318            if (_job.ChildJobs.Count == 0)319            {320                // No child jobs, monitor this job's results collection.321                _job.Results.DataAdding += HandleResultsDataAdding;322            }323            else324            {325                // Monitor each child job's results collections.326                foreach (var childJob in _job.ChildJobs)327                {328                    childJob.Results.DataAdding += HandleResultsDataAdding;329                }330            }331        }332 333        private void RemoveEventHandlers()334        {335            _job.StateChanged -= HandleJobStateChangedEvent;336            _debugger.NestedDebuggingCancelledEvent -= HandleDebuggerNestedDebuggingCancelledEvent;337 338            if (_job.ChildJobs.Count == 0)339            {340                // Remove single job DataAdding event handler.341                _job.Results.DataAdding -= HandleResultsDataAdding;342            }343            else344            {345                // Remove each child job's DataAdding event handler.346                foreach (var childJob in _job.ChildJobs)347                {348                    childJob.Results.DataAdding -= HandleResultsDataAdding;349                }350            }351        }352 353        private Job GetJobByName(string name)354        {355            // Search jobs in job repository.356            List<Job> jobs1 = new List<Job>();357            WildcardPattern pattern =358                WildcardPattern.Get(name, WildcardOptions.IgnoreCase | WildcardOptions.Compiled);359 360            foreach (Job job in JobRepository.Jobs)361            {362                if (pattern.IsMatch(job.Name))363                {364                    jobs1.Add(job);365                }366            }367 368            // Search jobs in job manager.369            List<Job2> jobs2 = JobManager.GetJobsByName(name, this, false, false, false, null);370 371            int jobCount = jobs1.Count + jobs2.Count;372            if (jobCount == 1)373            {374                return (jobs1.Count > 0) ? jobs1[0] : jobs2[0];375            }376 377            if (jobCount > 1)378            {379                ThrowTerminatingError(380                    new ErrorRecord(381                        new PSInvalidOperationException(StringUtil.Format(RemotingErrorIdStrings.FoundMultipleJobsWithName, name)),382                        "DebugJobFoundMultipleJobsWithName",383                        ErrorCategory.InvalidOperation,384                        this)385                    );386 387                return null;388            }389 390            ThrowTerminatingError(391                new ErrorRecord(392                    new PSInvalidOperationException(StringUtil.Format(RemotingErrorIdStrings.CannotFindJobWithName, name)),393                    "DebugJobCannotFindJobWithName",394                    ErrorCategory.InvalidOperation,395                    this)396                );397 398            return null;399        }400 401        private Job GetJobById(int id)402        {403            // Search jobs in job repository.404            List<Job> jobs1 = new List<Job>();405            foreach (Job job in JobRepository.Jobs)406            {407                if (job.Id == id)408                {409                    jobs1.Add(job);410                }411            }412 413            // Search jobs in job manager.414            Job job2 = JobManager.GetJobById(id, this, false, false, false);415 416            if ((jobs1.Count == 0) && (job2 == null))417            {418                ThrowTerminatingError(419                    new ErrorRecord(420                        new PSInvalidOperationException(StringUtil.Format(RemotingErrorIdStrings.CannotFindJobWithId, id)),421                        "DebugJobCannotFindJobWithId",422                        ErrorCategory.InvalidOperation,423                        this)424                    );425 426                return null;427            }428 429            if ((jobs1.Count > 1) ||430                (jobs1.Count == 1) && (job2 != null))431            {432                ThrowTerminatingError(433                    new ErrorRecord(434                        new PSInvalidOperationException(StringUtil.Format(RemotingErrorIdStrings.FoundMultipleJobsWithId, id)),435                        "DebugJobFoundMultipleJobsWithId",436                        ErrorCategory.InvalidOperation,437                        this)438                    );439 440                return null;441            }442 443            return (jobs1.Count > 0) ? jobs1[0] : job2;444        }445 446        private Job GetJobByInstanceId(Guid instanceId)447        {448            // Search jobs in job repository.449            foreach (Job job in JobRepository.Jobs)450            {451                if (job.InstanceId == instanceId)452                {453                    return job;454                }455            }456 457            // Search jobs in job manager.458            Job2 job2 = JobManager.GetJobByInstanceId(instanceId, this, false, false, false);459            if (job2 != null)460            {461                return job2;462            }463 464            ThrowTerminatingError(465                new ErrorRecord(466                    new PSInvalidOperationException(StringUtil.Format(RemotingErrorIdStrings.CannotFindJobWithInstanceId, instanceId)),467                    "DebugJobCannotFindJobWithInstanceId",468                    ErrorCategory.InvalidOperation,469                    this)470                );471 472            return null;473        }474 475        #endregion476    }477}478