MegaBites-AI/Windows-powershell
0372
1// Copyright (c) Microsoft Corporation.2// Licensed under the MIT License.3 4using System;5using System.Collections;6using System.Collections.Generic;7using System.Collections.ObjectModel;8using System.Collections.Specialized;9using System.ComponentModel;10using System.Diagnostics;11using System.Diagnostics.CodeAnalysis;12using System.Globalization;13using System.IO;14using System.Management.Automation;15using System.Management.Automation.Runspaces;16using System.Net;17using System.Reflection;18using System.Resources;19using System.Security;20using System.Security.Principal;21using System.Text;22using System.Threading;23using System.Xml;24 25using Microsoft.PowerShell.Commands.Diagnostics.Common;26using Microsoft.PowerShell.Commands.GetCounter;27using Microsoft.Powershell.Commands.GetCounter.PdhNative;28 29namespace Microsoft.PowerShell.Commands30{31 ///32 /// Class that implements the Get-Counter cmdlet.33 ///34 [Cmdlet(VerbsData.Import, "Counter", DefaultParameterSetName = "GetCounterSet", HelpUri = "https://go.microsoft.com/fwlink/?LinkID=138338")]35 public sealed class ImportCounterCommand : PSCmdlet36 {37 //38 // Path parameter39 //40 [Parameter(41 Position = 0,42 Mandatory = true,43 ValueFromPipeline = true,44 ValueFromPipelineByPropertyName = true,45 HelpMessageBaseName = "GetEventResources")]46 [Alias("PSPath")]47 48 [SuppressMessage("Microsoft.Performance", "CA1819:PropertiesShouldNotReturnArrays",49 Scope = "member",50 Target = "Microsoft.PowerShell.Commands.GetCounterCommand.ListSet",51 Justification = "A string[] is required here because that is the type Powershell supports")]52 public string[] Path53 {54 get { return _path; }55 56 set { _path = value; }57 }58 59 private string[] _path;60 61 private StringCollection _resolvedPaths = new StringCollection();62 63 private List<string> _accumulatedFileNames = new List<string>();64 65 //66 // ListSet parameter67 //68 [Parameter(69 Mandatory = true,70 ParameterSetName = "ListSetSet",71 ValueFromPipeline = false,72 ValueFromPipelineByPropertyName = false,73 HelpMessageBaseName = "GetEventResources")]74 [AllowEmptyCollection]75 [SuppressMessage("Microsoft.Performance", "CA1819:PropertiesShouldNotReturnArrays",76 Scope = "member",77 Target = "Microsoft.PowerShell.Commands.GetCounterCommand.ListSet",78 Justification = "A string[] is required here because that is the type Powershell supports")]79 public string[] ListSet80 {81 get { return _listSet; }82 83 set { _listSet = value; }84 }85 86 private string[] _listSet = Array.Empty<string>();87 88 //89 // StartTime parameter90 //91 [Parameter(92 ValueFromPipeline = false,93 ValueFromPipelineByPropertyName = false,94 ParameterSetName = "GetCounterSet",95 HelpMessageBaseName = "GetEventResources")]96 public DateTime StartTime97 {98 get { return _startTime; }99 100 set { _startTime = value; }101 }102 103 private DateTime _startTime = DateTime.MinValue;104 105 //106 // EndTime parameter107 //108 [Parameter(109 ValueFromPipeline = false,110 ValueFromPipelineByPropertyName = false,111 ParameterSetName = "GetCounterSet",112 HelpMessageBaseName = "GetEventResources")]113 public DateTime EndTime114 {115 get { return _endTime; }116 117 set { _endTime = value; }118 }119 120 private DateTime _endTime = DateTime.MaxValue;121 122 //123 // Counter parameter124 //125 [Parameter(126 Mandatory = false,127 ParameterSetName = "GetCounterSet",128 ValueFromPipeline = false,129 HelpMessageBaseName = "GetEventResources")]130 [AllowEmptyCollection]131 [SuppressMessage("Microsoft.Performance", "CA1819:PropertiesShouldNotReturnArrays",132 Scope = "member",133 Target = "Microsoft.PowerShell.Commands.GetCounterCommand.ListSet",134 Justification = "A string[] is required here because that is the type Powershell supports")]135 public string[] Counter136 {137 get { return _counter; }138 139 set { _counter = value; }140 }141 142 private string[] _counter = Array.Empty<string>();143 144 //145 // Summary switch146 //147 [Parameter(ParameterSetName = "SummarySet")]148 public SwitchParameter Summary149 {150 get { return _summary; }151 152 set { _summary = value; }153 }154 155 private SwitchParameter _summary;156 157 //158 // MaxSamples parameter159 //160 private const Int64 KEEP_ON_SAMPLING = -1;161 [Parameter(162 ParameterSetName = "GetCounterSet",163 ValueFromPipeline = false,164 ValueFromPipelineByPropertyName = false,165 HelpMessageBaseName = "GetEventResources")]166 [ValidateRange((Int64)1, Int64.MaxValue)]167 public Int64 MaxSamples168 {169 get { return _maxSamples; }170 171 set { _maxSamples = value; }172 }173 174 private Int64 _maxSamples = KEEP_ON_SAMPLING;175 176 private ResourceManager _resourceMgr = null;177 178 private PdhHelper _pdhHelper = null;179 180 private bool _stopping = false;181 182 //183 // AccumulatePipelineFileNames() accumulates counter file paths in the pipeline scenario:184 // we do not want to construct a Pdh query until all the file names are supplied.185 //186 private void AccumulatePipelineFileNames()187 {188 _accumulatedFileNames.AddRange(_path);189 }190 191 //192 // BeginProcessing() is invoked once per pipeline193 //194 protected override void BeginProcessing()195 {196 197#if CORECLR198 if (Platform.IsIoT)199 {200 // IoT does not have the '$env:windir\System32\pdh.dll' assembly which is required by this cmdlet.201 throw new PlatformNotSupportedException();202 }203 204 // PowerShell 7 requires at least Windows 7,205 // so no version test is needed206 _pdhHelper = new PdhHelper(false);207#else208 _pdhHelper = new PdhHelper(System.Environment.OSVersion.Version.Major < 6);209#endif210 _resourceMgr = Microsoft.PowerShell.Commands.Diagnostics.Common.CommonUtilities.GetResourceManager();211 }212 213 //214 // EndProcessing() is invoked once per pipeline215 //216 protected override void EndProcessing()217 {218 //219 // Resolve and validate the Path argument: present for all parametersets.220 //221 if (!ResolveFilePaths())222 {223 return;224 }225 226 ValidateFilePaths();227 228 switch (ParameterSetName)229 {230 case "ListSetSet":231 ProcessListSet();232 break;233 234 case "GetCounterSet":235 ProcessGetCounter();236 break;237 238 case "SummarySet":239 ProcessSummary();240 break;241 242 default:243 Debug.Assert(false, $"Invalid parameter set name: {ParameterSetName}");244 break;245 }246 247 _pdhHelper.Dispose();248 }249 250 //251 // Handle Control-C252 //253 protected override void StopProcessing()254 {255 _stopping = true;256 _pdhHelper.Dispose();257 }258 259 //260 // ProcessRecord() override.261 // This is the main entry point for the cmdlet.262 //263 protected override void ProcessRecord()264 {265 AccumulatePipelineFileNames();266 }267 268 //269 // ProcessSummary().270 // Does the work to process Summary parameter set.271 //272 private void ProcessSummary()273 {274 uint res = _pdhHelper.ConnectToDataSource(_resolvedPaths);275 if (res != 0)276 {277 ReportPdhError(res, true);278 return;279 }280 281 CounterFileInfo summaryObj;282 res = _pdhHelper.GetFilesSummary(out summaryObj);283 284 if (res != 0)285 {286 ReportPdhError(res, true);287 return;288 }289 290 WriteObject(summaryObj);291 }292 293 //294 // ProcessListSet().295 // Does the work to process ListSet parameter set.296 //297 private void ProcessListSet()298 {299 uint res = _pdhHelper.ConnectToDataSource(_resolvedPaths);300 if (res != 0)301 {302 ReportPdhError(res, true);303 return;304 }305 306 StringCollection machineNames = new StringCollection();307 res = _pdhHelper.EnumBlgFilesMachines(ref machineNames);308 if (res != 0)309 {310 ReportPdhError(res, true);311 return;312 }313 314 foreach (string machine in machineNames)315 {316 StringCollection counterSets = new StringCollection();317 res = _pdhHelper.EnumObjects(machine, ref counterSets);318 if (res != 0)319 {320 return;321 }322 323 StringCollection validPaths = new StringCollection();324 325 foreach (string pattern in _listSet)326 {327 bool bMatched = false;328 329 WildcardPattern wildLogPattern = new WildcardPattern(pattern, WildcardOptions.IgnoreCase);330 331 foreach (string counterSet in counterSets)332 {333 if (!wildLogPattern.IsMatch(counterSet))334 {335 continue;336 }337 338 StringCollection counterSetCounters = new StringCollection();339 StringCollection counterSetInstances = new StringCollection();340 341 res = _pdhHelper.EnumObjectItems(machine, counterSet, ref counterSetCounters, ref counterSetInstances);342 if (res != 0)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 Dictionary<string, string[]> counterInstanceMapping = new Dictionary<string, string[]>();356 foreach (string counter in counterSetCounters)357 {358 counterInstanceMapping.Add(counter, instanceArray);359 }360 361 PerformanceCounterCategoryType categoryType = PerformanceCounterCategoryType.Unknown;362 if (counterSetInstances.Count > 1)363 {364 categoryType = PerformanceCounterCategoryType.MultiInstance;365 }366 else // if (counterSetInstances.Count == 1) //???367 {368 categoryType = PerformanceCounterCategoryType.SingleInstance;369 }370 371 string setHelp = _pdhHelper.GetCounterSetHelp(machine, counterSet);372 373 CounterSet setObj = new CounterSet(counterSet, machine, categoryType, setHelp, ref counterInstanceMapping);374 WriteObject(setObj);375 bMatched = true;376 }377 378 if (!bMatched)379 {380 string msg = _resourceMgr.GetString("NoMatchingCounterSetsInFile");381 Exception exc = new Exception(string.Format(CultureInfo.InvariantCulture, msg,382 CommonUtilities.StringArrayToString(_resolvedPaths),383 pattern));384 WriteError(new ErrorRecord(exc, "NoMatchingCounterSetsInFile", ErrorCategory.ObjectNotFound, null));385 }386 }387 }388 }389 390 //391 // ProcessGetCounter()392 // Does the work to process GetCounterSet parameter set.393 //394 private void ProcessGetCounter()395 {396 // Validate StartTime-EndTime, if present397 if (_startTime != DateTime.MinValue || _endTime != DateTime.MaxValue)398 {399 if (_startTime >= _endTime)400 {401 string msg = string.Format(CultureInfo.InvariantCulture, _resourceMgr.GetString("CounterInvalidDateRange"));402 Exception exc = new Exception(msg);403 ThrowTerminatingError(new ErrorRecord(exc, "CounterInvalidDateRange", ErrorCategory.InvalidArgument, null));404 return;405 }406 }407 408 uint res = _pdhHelper.ConnectToDataSource(_resolvedPaths);409 if (res != 0)410 {411 ReportPdhError(res, true);412 return;413 }414 415 StringCollection validPaths = new StringCollection();416 if (_counter.Length > 0)417 {418 foreach (string path in _counter)419 {420 StringCollection expandedPaths;421 res = _pdhHelper.ExpandWildCardPath(path, out expandedPaths);422 if (res != 0)423 {424 WriteDebug(path);425 ReportPdhError(res, false);426 continue;427 }428 429 foreach (string expandedPath in expandedPaths)430 {431 if (!_pdhHelper.IsPathValid(expandedPath))432 {433 string msg = string.Format(CultureInfo.InvariantCulture, _resourceMgr.GetString("CounterPathIsInvalid"), path);434 Exception exc = new Exception(msg);435 WriteError(new ErrorRecord(exc, "CounterPathIsInvalid", ErrorCategory.InvalidResult, null));436 437 continue;438 }439 440 validPaths.Add(expandedPath);441 }442 }443 444 if (validPaths.Count == 0)445 {446 return;447 }448 }449 else450 {451 res = _pdhHelper.GetValidPathsFromFiles(ref validPaths);452 if (res != 0)453 {454 ReportPdhError(res, false);455 }456 }457 458 if (validPaths.Count == 0)459 {460 string msg = string.Format(CultureInfo.InvariantCulture, _resourceMgr.GetString("CounterPathsInFilesInvalid"));461 Exception exc = new Exception(msg);462 ThrowTerminatingError(new ErrorRecord(exc, "CounterPathsInFilesInvalid", ErrorCategory.InvalidResult, null));463 }464 465 res = _pdhHelper.OpenQuery();466 if (res != 0)467 {468 ReportPdhError(res, false);469 }470 471 if (_startTime != DateTime.MinValue || _endTime != DateTime.MaxValue)472 {473 res = _pdhHelper.SetQueryTimeRange(_startTime, _endTime);474 if (res != 0)475 {476 ReportPdhError(res, true);477 }478 }479 480 res = _pdhHelper.AddCounters(ref validPaths, true);481 if (res != 0)482 {483 ReportPdhError(res, true);484 }485 486 PerformanceCounterSampleSet nextSet;487 488 uint samplesRead = 0;489 490 while (!_stopping)491 {492 res = _pdhHelper.ReadNextSet(out nextSet, false);493 if (res == PdhResults.PDH_NO_MORE_DATA)494 {495 break;496 }497 498 if (res != 0 && res != PdhResults.PDH_INVALID_DATA)499 {500 ReportPdhError(res, false);501 continue;502 }503 504 //505 // Display data506 //507 WriteSampleSetObject(nextSet, (samplesRead == 0));508 509 samplesRead++;510 511 if (_maxSamples != KEEP_ON_SAMPLING && samplesRead >= _maxSamples)512 {513 break;514 }515 }516 }517 518 //519 // ValidateFilePaths() helper.520 // Validates the _resolvedPaths: present for all parametersets.521 // We cannot have more than 32 blg files, or more than one CSV or TSC file.522 // Files have to all be of the same type (.blg, .csv, .tsv).523 //524 private void ValidateFilePaths()525 {526 Debug.Assert(_resolvedPaths.Count > 0);527 528 string firstExt = System.IO.Path.GetExtension(_resolvedPaths[0]);529 foreach (string fileName in _resolvedPaths)530 {531 WriteVerbose(fileName);532 string curExtension = System.IO.Path.GetExtension(fileName);533 534 if (!curExtension.Equals(".blg", StringComparison.OrdinalIgnoreCase)535 && !curExtension.Equals(".csv", StringComparison.OrdinalIgnoreCase)536 && !curExtension.Equals(".tsv", StringComparison.OrdinalIgnoreCase))537 {538 string msg = string.Format(CultureInfo.InvariantCulture, _resourceMgr.GetString("CounterNotALogFile"), fileName);539 Exception exc = new Exception(msg);540 ThrowTerminatingError(new ErrorRecord(exc, "CounterNotALogFile", ErrorCategory.InvalidResult, null));541 return;542 }543 544 if (!curExtension.Equals(firstExt, StringComparison.OrdinalIgnoreCase))545 {546 string msg = string.Format(CultureInfo.InvariantCulture, _resourceMgr.GetString("CounterNoMixedLogTypes"), fileName);547 Exception exc = new Exception(msg);548 ThrowTerminatingError(new ErrorRecord(exc, "CounterNoMixedLogTypes", ErrorCategory.InvalidResult, null));549 return;550 }551 }552 553 if (firstExt.Equals(".blg", StringComparison.OrdinalIgnoreCase))554 {555 if (_resolvedPaths.Count > 32)556 {557 string msg = string.Format(CultureInfo.InvariantCulture, _resourceMgr.GetString("Counter32FileLimit"));558 Exception exc = new Exception(msg);559 ThrowTerminatingError(new ErrorRecord(exc, "Counter32FileLimit", ErrorCategory.InvalidResult, null));560 return;561 }562 }563 else if (_resolvedPaths.Count > 1)564 {565 string msg = string.Format(CultureInfo.InvariantCulture, _resourceMgr.GetString("Counter1FileLimit"));566 Exception exc = new Exception(msg);567 ThrowTerminatingError(new ErrorRecord(exc, "Counter1FileLimit", ErrorCategory.InvalidResult, null));568 return;569 }570 }571 572 //573 // ResolveFilePath helper.574 // Returns a string collection of resolved file paths.575 // Writes non-terminating errors for invalid paths576 // and returns an empty collection.577 //578 private bool ResolveFilePaths()579 {580 StringCollection retColl = new StringCollection();581 582 foreach (string origPath in _accumulatedFileNames)583 {584 Collection<PathInfo> resolvedPathSubset = null;585 try586 {587 resolvedPathSubset = SessionState.Path.GetResolvedPSPathFromPSPath(origPath);588 }589 catch (PSNotSupportedException notSupported)590 {591 WriteError(new ErrorRecord(notSupported, string.Empty, ErrorCategory.ObjectNotFound, origPath));592 continue;593 }594 catch (System.Management.Automation.DriveNotFoundException driveNotFound)595 {596 WriteError(new ErrorRecord(driveNotFound, string.Empty, ErrorCategory.ObjectNotFound, origPath));597 continue;598 }599 catch (ProviderNotFoundException providerNotFound)600 {601 WriteError(new ErrorRecord(providerNotFound, string.Empty, ErrorCategory.ObjectNotFound, origPath));602 continue;603 }604 catch (ItemNotFoundException pathNotFound)605 {606 WriteError(new ErrorRecord(pathNotFound, string.Empty, ErrorCategory.ObjectNotFound, origPath));607 continue;608 }609 catch (Exception exc)610 {611 WriteError(new ErrorRecord(exc, string.Empty, ErrorCategory.ObjectNotFound, origPath));612 continue;613 }614 615 foreach (PathInfo pi in resolvedPathSubset)616 {617 //618 // Check the provider: only FileSystem provider paths are acceptable.619 //620 if (pi.Provider.Name != "FileSystem")621 {622 string msg = _resourceMgr.GetString("NotAFileSystemPath");623 Exception exc = new Exception(string.Format(CultureInfo.InvariantCulture, msg, origPath));624 WriteError(new ErrorRecord(exc, "NotAFileSystemPath", ErrorCategory.InvalidArgument, origPath));625 continue;626 }627 628 _resolvedPaths.Add(pi.ProviderPath.ToLowerInvariant());629 }630 }631 632 return (_resolvedPaths.Count > 0);633 }634 635 private void ReportPdhError(uint res, bool bTerminate)636 {637 string msg;638 uint formatRes = CommonUtilities.FormatMessageFromModule(res, "pdh.dll", out msg);639 if (formatRes != 0)640 {641 msg = string.Format(CultureInfo.InvariantCulture, _resourceMgr.GetString("CounterApiError"), res);642 }643 644 Exception exc = new Exception(msg);645 if (bTerminate)646 {647 ThrowTerminatingError(new ErrorRecord(exc, "CounterApiError", ErrorCategory.InvalidResult, null));648 }649 else650 {651 WriteError(new ErrorRecord(exc, "CounterApiError", ErrorCategory.InvalidResult, null));652 }653 }654 655 //656 // WriteSampleSetObject() helper.657 // In addition to writing the PerformanceCounterSampleSet object,658 // it writes a single error if one of the samples has an invalid (non-zero) status.659 // The only exception is the first set, where we allow for the formatted value to be 0 -660 // this is expected for CSV and TSV files.661 662 private void WriteSampleSetObject(PerformanceCounterSampleSet set, bool firstSet)663 {664 if (!firstSet)665 {666 foreach (PerformanceCounterSample sample in set.CounterSamples)667 {668 if (sample.Status != 0)669 {670 string msg = string.Format(CultureInfo.InvariantCulture, _resourceMgr.GetString("CounterSampleDataInvalid"));671 Exception exc = new Exception(msg);672 WriteError(new ErrorRecord(exc, "CounterApiError", ErrorCategory.InvalidResult, null));673 break;674 }675 }676 }677 678 WriteObject(set);679 }680 }681}682 