Team Ai
Datasetpublic

MegaBites-AI/Windows-powershell

sourceHugging Facemitupdated 6mo agoView on Hugging Face
0likes372downloads
1// Copyright (c) Microsoft Corporation.2// Licensed under the MIT License.3 4using System;5using System.Collections.Generic;6using System.Collections.Specialized;7using System.Diagnostics;8using System.Diagnostics.CodeAnalysis;9using System.Globalization;10using System.Management.Automation;11using System.Resources;12using System.Threading;13using Microsoft.Powershell.Commands.GetCounter.PdhNative;14using Microsoft.PowerShell.Commands.Diagnostics.Common;15using Microsoft.PowerShell.Commands.GetCounter;16 17namespace Microsoft.PowerShell.Commands18{19    /// <summary>20    /// Class that implements the Get-Counter cmdlet.21    /// </summary>22    [Cmdlet(VerbsCommon.Get, "Counter", DefaultParameterSetName = "GetCounterSet", HelpUri = "https://go.microsoft.com/fwlink/?LinkID=2109647")]23    public sealed class GetCounterCommand : PSCmdlet24    {25        //26        // ListSet parameter27        //28        [Parameter(29                Position = 0,30                Mandatory = true,31                ParameterSetName = "ListSetSet",32                ValueFromPipeline = true,33                ValueFromPipelineByPropertyName = false,34                HelpMessageBaseName = "GetEventResources")]35        [AllowEmptyCollection]36        [SuppressMessage("Microsoft.Performance", "CA1819:PropertiesShouldNotReturnArrays",37                            Scope = "member",38                            Target = "Microsoft.PowerShell.Commands.GetCounterCommand.ListSet",39                            Justification = "A string[] is required here because that is the type Powershell supports")]40        public string[] ListSet { get; set; } = { "*" };41 42        //43        // Counter parameter44        //45        [Parameter(46                Position = 0,47                ParameterSetName = "GetCounterSet",48                ValueFromPipeline = true,49                ValueFromPipelineByPropertyName = true,50                HelpMessageBaseName = "GetEventResources")]51        [AllowEmptyCollection]52        [SuppressMessage("Microsoft.Performance", "CA1819:PropertiesShouldNotReturnArrays",53                            Scope = "member",54                            Target = "Microsoft.PowerShell.Commands.GetCounterCommand.ListSet",55                            Justification = "A string[] is required here because that is the type Powershell supports")]56        public string[] Counter57        {58            get59            {60                return _counter;61            }62 63            set64            {65                _counter = value;66                _defaultCounters = false;67            }68        }69 70        private string[] _counter = {@"\network interface(*)\bytes total/sec",71                                 @"\processor(_total)\% processor time",72                                 @"\memory\% committed bytes in use",73                                 @"\memory\cache faults/sec",74                                 @"\physicaldisk(_total)\% disk time",75                                 @"\physicaldisk(_total)\current disk queue length"};76 77        private bool _defaultCounters = true;78 79        private readonly List<string> _accumulatedCounters = new();80 81        //82        // SampleInterval parameter.83        // Defaults to 1 second.84        //85        [Parameter(86                ParameterSetName = "GetCounterSet",87                ValueFromPipeline = false,88                ValueFromPipelineByPropertyName = false,89                HelpMessageBaseName = "GetEventResources")]90        [ValidateRange((int)1, int.MaxValue)]91        public int SampleInterval { get; set; } = 1;92 93        //94        // MaxSamples parameter95        //96        private const Int64 KEEP_ON_SAMPLING = -1;97 98        [Parameter(99                ParameterSetName = "GetCounterSet",100                ValueFromPipeline = false,101                ValueFromPipelineByPropertyName = false,102                HelpMessageBaseName = "GetEventResources")]103        [ValidateRange((Int64)1, Int64.MaxValue)]104        public Int64 MaxSamples105        {106            get107            {108                return _maxSamples;109            }110 111            set112            {113                _maxSamples = value;114                _maxSamplesSpecified = true;115            }116        }117 118        private Int64 _maxSamples = 1;119        private bool _maxSamplesSpecified = false;120 121        //122        // Continuous switch123        //124        [Parameter(ParameterSetName = "GetCounterSet")]125        public SwitchParameter Continuous126        {127            get { return _continuous; }128 129            set { _continuous = value; }130        }131 132        private bool _continuous = false;133 134        //135        // ComputerName parameter136        //137        [Parameter(138                ValueFromPipeline = false,139                ValueFromPipelineByPropertyName = false,140                HelpMessageBaseName = "GetEventResources",141                HelpMessageResourceId = "ComputerNameParamHelp")]142        [ValidateNotNull]143        [AllowEmptyCollection]144        [Alias("Cn")]145        [SuppressMessage("Microsoft.Performance", "CA1819:PropertiesShouldNotReturnArrays",146                            Scope = "member",147                            Target = "Microsoft.PowerShell.Commands.GetCounterCommand.ComputerName",148                            Justification = "A string[] is required here because that is the type Powershell supports")]149        public string[] ComputerName { get; set; } = Array.Empty<string>();150 151        private ResourceManager _resourceMgr = null;152 153        private PdhHelper _pdhHelper = null;154 155        private readonly EventWaitHandle _cancelEventArrived = new(false, EventResetMode.ManualReset);156 157        // Culture identifier(s)158        private const string FrenchCultureId = "fr-FR";159        // The localized Pdh resource strings might use Unicode characters that are different from160        // what the user can type with the keyboard to represent a special character.161        //162        // e.g. the apostrophe in French UI culture: it's [char]39 from keyboard, but it's [char]8217163        // in the resource strings.164        //165        // With this dictionary, we can add special mapping if we find other special cases in the future.166        private readonly Dictionary<string, List<Tuple<char, char>>> _cultureAndSpecialCharacterMap =167            new()168                {169                   {170                       FrenchCultureId, new List<Tuple<char, char>>()171                                            {172                                                // 'APOSTROPHE' to 'RIGHT SINGLE QUOTATION MARK'173                                                new Tuple<char, char>((char)0x0027, (char)0x2019),174                                                // 'MODIFIER LETTER APOSTROPHE' to 'RIGHT SINGLE QUOTATION MARK'175                                                new Tuple<char, char>((char)0x02BC, (char)0x2019),176                                                // 'HEAVY SINGLE COMMA QUOTATION MARK ORNAMENT' to 'RIGHT SINGLE QUOTATION MARK'177                                                new Tuple<char, char>((char)0x275C, (char)0x2019),178                                            }179                   }180                };181 182        //183        // BeginProcessing() is invoked once per pipeline184        //185        protected override void BeginProcessing()186        {187            if (Platform.IsIoT)188            {189                // IoT does not have the '$env:windir\System32\pdh.dll' assembly which is required by this cmdlet.190                throw new PlatformNotSupportedException();191            }192 193            _pdhHelper = new PdhHelper();194            _resourceMgr = Microsoft.PowerShell.Commands.Diagnostics.Common.CommonUtilities.GetResourceManager();195 196            uint res = _pdhHelper.ConnectToDataSource();197            if (res != PdhResults.PDH_CSTATUS_VALID_DATA)198            {199                ReportPdhError(res, true);200                return;201            }202 203            if (Continuous.IsPresent && _maxSamplesSpecified)204            {205                Exception exc = new(string.Format(CultureInfo.CurrentCulture, _resourceMgr.GetString("CounterContinuousOrMaxSamples")));206                ThrowTerminatingError(new ErrorRecord(exc, "CounterContinuousOrMaxSamples", ErrorCategory.InvalidArgument, null));207            }208        }209 210        //211        // EndProcessing() is invoked once per pipeline212        //213        protected override void EndProcessing()214        {215            if (ParameterSetName == "GetCounterSet")216            {217                ProcessGetCounter();218            }219 220            _pdhHelper.Dispose();221        }222 223        //224        // Handle Control-C225        //226        protected override void StopProcessing()227        {228            _cancelEventArrived.Set();229            _pdhHelper.Dispose();230        }231 232        //233        // ProcessRecord() override.234        // This is the main entry point for the cmdlet.235        //236        protected override void ProcessRecord()237        {238            try239            {240                switch (ParameterSetName)241                {242                    case "ListSetSet":243                        ProcessListSet();244                        break;245 246                    case "GetCounterSet":247                        AccumulatePipelineCounters();248                        break;249 250                    default:251                        Debug.Fail(string.Create(CultureInfo.InvariantCulture, $"Invalid parameter set name: {ParameterSetName}"));252                        break;253                }254            }255            catch (Exception exc)256            {257                ThrowTerminatingError(new ErrorRecord(exc, "CounterApiError", ErrorCategory.InvalidResult, null));258            }259        }260 261        //262        // AccumulatePipelineCounters() accumulates counter paths in the pipeline scenario:263        // we do not want to start sampling until all the counters are supplied.264        //265        private void AccumulatePipelineCounters()266        {267            _accumulatedCounters.AddRange(_counter);268        }269 270        //271        // ProcessListSet() does the work to process ListSet parameter set.272        //273        private void ProcessListSet()274        {275            if (ComputerName.Length == 0)276            {277                ProcessListSetPerMachine(null);278            }279            else280                foreach (string machine in ComputerName)281                {282                    ProcessListSetPerMachine(machine);283                }284        }285 286        //287        // ProcessListSetPerMachine() helper lists counter sets on a machine.288        // NOTE: machine argument should be NULL for the local machine289        //290        private void ProcessListSetPerMachine(string machine)291        {292            StringCollection counterSets = new();293            uint res = _pdhHelper.EnumObjects(machine, ref counterSets);294            if (res != PdhResults.PDH_CSTATUS_VALID_DATA)295            {296                // add an error message297                string msg = string.Format(CultureInfo.InvariantCulture, _resourceMgr.GetString("NoCounterSetsOnComputer"), machine, res);298                Exception exc = new(msg);299                WriteError(new ErrorRecord(exc, "NoCounterSetsOnComputer", ErrorCategory.InvalidResult, machine));300                return;301            }302 303            CultureInfo culture = GetCurrentCulture();304            List<Tuple<char, char>> characterReplacementList = null;305            StringCollection validPaths = new();306 307            _cultureAndSpecialCharacterMap.TryGetValue(culture.Name, out characterReplacementList);308 309            foreach (string pattern in ListSet)310            {311                bool bMatched = false;312                string normalizedPattern = pattern;313 314                if (characterReplacementList != null)315                {316                    foreach (Tuple<char, char> pair in characterReplacementList)317                    {318                        normalizedPattern = normalizedPattern.Replace(pair.Item1, pair.Item2);319                    }320                }321 322                WildcardPattern wildLogPattern = new(normalizedPattern, WildcardOptions.IgnoreCase);323 324                foreach (string counterSet in counterSets)325                {326                    if (!wildLogPattern.IsMatch(counterSet))327                    {328                        continue;329                    }330 331                    StringCollection counterSetCounters = new();332                    StringCollection counterSetInstances = new();333 334                    res = _pdhHelper.EnumObjectItems(machine, counterSet, ref counterSetCounters, ref counterSetInstances);335                    if (res == PdhResults.PDH_ACCESS_DENIED)336                    {337                        string msg = string.Format(CultureInfo.InvariantCulture, _resourceMgr.GetString("CounterSetEnumAccessDenied"), counterSet);338                        Exception exc = new(msg);339                        WriteError(new ErrorRecord(exc, "CounterSetEnumAccessDenied", ErrorCategory.InvalidResult, null));340                        continue;341                    }342                    else if (res != PdhResults.PDH_CSTATUS_VALID_DATA)343                    {344                        ReportPdhError(res, false);345                        continue;346                    }347 348                    string[] instanceArray = new string[counterSetInstances.Count];349                    int i = 0;350                    foreach (string instance in counterSetInstances)351                    {352                        instanceArray[i++] = instance;353                    }354 355                    //356                    // Special case: no instances present: change to * to create a valid paths357                    //358                    if (instanceArray.Length == 1 &&359                        instanceArray[0].Length == 0)360                    {361                        instanceArray[0] = "*";362                    }363 364                    Dictionary<string, string[]> counterInstanceMapping = new();365                    foreach (string counter in counterSetCounters)366                    {367                        counterInstanceMapping.TryAdd(counter, instanceArray);368                    }369 370                    PerformanceCounterCategoryType categoryType = PerformanceCounterCategoryType.Unknown;371                    if (counterSetInstances.Count > 1)372                    {373                        categoryType = PerformanceCounterCategoryType.MultiInstance;374                    }375                    else // if (counterSetInstances.Count == 1) //???376                    {377                        categoryType = PerformanceCounterCategoryType.SingleInstance;378                    }379 380                    string setHelp = _pdhHelper.GetCounterSetHelp(machine, counterSet);381 382                    CounterSet setObj = new(counterSet, machine, categoryType, setHelp, ref counterInstanceMapping);383                    WriteObject(setObj);384                    bMatched = true;385                }386 387                if (!bMatched)388                {389                    string msg = _resourceMgr.GetString("NoMatchingCounterSetsFound");390                    Exception exc = new(string.Format(CultureInfo.InvariantCulture, msg,391                      machine ?? "localhost", normalizedPattern));392                    WriteError(new ErrorRecord(exc, "NoMatchingCounterSetsFound", ErrorCategory.ObjectNotFound, null));393                }394            }395        }396 397        //398        // ProcessGetCounter()399        // Does the work to process GetCounterSet parameter set.400        //401        private void ProcessGetCounter()402        {403            // 1. Combine machine names with paths, if needed, to construct full paths404            // 2. Translate default paths into current locale405            // 3. Expand wildcards and validate the paths and write errors for any invalid paths406            // 4. OpenQuery/ AddCounters407            // 5. Skip the first reading408 409            CultureInfo culture = GetCurrentCulture();410            List<Tuple<char, char>> characterReplacementList = null;411            List<string> paths = CombineMachinesAndCounterPaths();412 413            if (!_defaultCounters)414            {415                _cultureAndSpecialCharacterMap.TryGetValue(culture.Name, out characterReplacementList);416            }417 418            StringCollection allExpandedPaths = new();419            uint res;420            foreach (string path in paths)421            {422                string localizedPath = path;423                if (_defaultCounters)424                {425                    res = _pdhHelper.TranslateLocalCounterPath(path, out localizedPath);426                    if (res != PdhResults.PDH_CSTATUS_VALID_DATA)427                    {428                        string msg = string.Format(CultureInfo.CurrentCulture, _resourceMgr.GetString("CounterPathTranslationFailed"), res);429                        Exception exc = new(msg);430                        WriteError(new ErrorRecord(exc, "CounterPathTranslationFailed", ErrorCategory.InvalidResult, null));431 432                        localizedPath = path;433                    }434                }435                else if (characterReplacementList != null)436                {437                    foreach (Tuple<char, char> pair in characterReplacementList)438                    {439                        localizedPath = localizedPath.Replace(pair.Item1, pair.Item2);440                    }441                }442 443                StringCollection expandedPaths;444                res = _pdhHelper.ExpandWildCardPath(localizedPath, out expandedPaths);445                if (res != PdhResults.PDH_CSTATUS_VALID_DATA)446                {447                    WriteDebug("Could not expand path " + localizedPath);448                    ReportPdhError(res, false);449                    continue;450                }451 452                foreach (string expandedPath in expandedPaths)453                {454                    if (!_pdhHelper.IsPathValid(expandedPath))455                    {456                        string msg = string.Format(CultureInfo.CurrentCulture, _resourceMgr.GetString("CounterPathIsInvalid"), localizedPath);457                        Exception exc = new(msg);458                        WriteError(new ErrorRecord(exc, "CounterPathIsInvalid", ErrorCategory.InvalidResult, null));459 460                        continue;461                    }462 463                    allExpandedPaths.Add(expandedPath);464                }465            }466 467            if (allExpandedPaths.Count == 0)468            {469                return;470            }471 472            res = _pdhHelper.OpenQuery();473            if (res != PdhResults.PDH_CSTATUS_VALID_DATA)474            {475                ReportPdhError(res, false);476            }477 478            res = _pdhHelper.AddCounters(ref allExpandedPaths, true);479            if (res != PdhResults.PDH_CSTATUS_VALID_DATA)480            {481                ReportPdhError(res, true);482 483                return;484            }485 486            PerformanceCounterSampleSet nextSet;487 488            bool bSkip = true;489            uint sampleReads = 0;490 491            if (Continuous.IsPresent)492            {493                _maxSamples = KEEP_ON_SAMPLING;494            }495 496            while (true)497            {498                // read the first set just to get the initial values499                res = _pdhHelper.ReadNextSet(out nextSet, bSkip);500 501                if (res == PdhResults.PDH_CSTATUS_VALID_DATA)502                {503                    // Display valid data504                    if (!bSkip)505                    {506                        WriteSampleSetObject(nextSet);507                        sampleReads++;508                    }509 510                    // Don't need to skip anymore511                    bSkip = false;512                }513                else if (res == PdhResults.PDH_NO_DATA || res == PdhResults.PDH_INVALID_DATA)514                {515                    // The provider may not be running.516                    // We should keep on trying - but skip the next valid reading.517 518                    ReportPdhError(res, false);519 520                    bSkip = true;521 522                    // Count this failed attempt as a sample:523                    sampleReads++;524                }525                else526                {527                    // Unexpected error, return528                    ReportPdhError(res, true);529                    return;530                }531 532                if (_maxSamples != KEEP_ON_SAMPLING && sampleReads >= _maxSamples)533                {534                    break;535                }536 537                bool cancelled = _cancelEventArrived.WaitOne((int)SampleInterval * 1000, true);538                if (cancelled)539                {540                    break;541                }542            }543        }544 545        private void ReportPdhError(uint res, bool bTerminate)546        {547            string msg;548            uint formatRes = CommonUtilities.FormatMessageFromModule(res, "pdh.dll", out msg);549            if (formatRes != 0)550            {551                msg = string.Format(CultureInfo.InvariantCulture, _resourceMgr.GetString("CounterApiError"), res);552            }553 554            Exception exc = new(msg);555            if (bTerminate)556            {557                ThrowTerminatingError(new ErrorRecord(exc, "CounterApiError", ErrorCategory.InvalidResult, null));558            }559            else560            {561                WriteError(new ErrorRecord(exc, "CounterApiError", ErrorCategory.InvalidResult, null));562            }563        }564 565        //566        // CombineMachinesAndCounterPaths() helper.567        // For paths that do not contain machine names, creates a path for each machine in machineNames.568        // Paths already containing a machine name will be preserved.569        //570        private List<string> CombineMachinesAndCounterPaths()571        {572            List<string> retColl = new();573 574            if (ComputerName.Length == 0)575            {576                retColl.AddRange(_accumulatedCounters);577                return retColl;578            }579 580            foreach (string path in _accumulatedCounters)581            {582                if (path.StartsWith("\\\\", StringComparison.OrdinalIgnoreCase)) // NOTE: can we do anything smarter here?583                {584                    retColl.Add(path);585                }586                else587                {588                    foreach (string machine in ComputerName)589                    {590                        string slashBeforePath = path.Length > 0 && path[0] == '\\' ? string.Empty : "\\";591                        if (machine.StartsWith("\\\\", StringComparison.OrdinalIgnoreCase))592                        {593                            retColl.Add(machine + slashBeforePath + path);594                        }595                        else596                        {597                            retColl.Add("\\\\" + machine + slashBeforePath + path);598                        }599                    }600                }601            }602 603            return retColl;604        }605 606        //607        // WriteSampleSetObject() helper.608        // In addition to writing the PerformanceCounterSampleSet object,609        // it writes a single error if one of the samples has an invalid (non-zero) status.610        //611        private void WriteSampleSetObject(PerformanceCounterSampleSet set)612        {613            foreach (PerformanceCounterSample sample in set.CounterSamples)614            {615                if (sample.Status != 0)616                {617                    string msg = string.Format(CultureInfo.InvariantCulture, _resourceMgr.GetString("CounterSampleDataInvalid"));618                    Exception exc = new(msg);619                    WriteError(new ErrorRecord(exc, "CounterApiError", ErrorCategory.InvalidResult, null));620                    break;621                }622            }623 624            WriteObject(set);625        }626 627        private static CultureInfo GetCurrentCulture()628        {629            return Thread.CurrentThread.CurrentUICulture;630        }631    }632}633