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.Diagnostics.CodeAnalysis;10using System.Diagnostics.Eventing.Reader;11using System.Globalization;12using System.Management.Automation;13using System.Net;14using System.Resources;15using System.Security.Principal;16using System.Text;17using System.Xml;18 19[assembly: CLSCompliant(false)]20 21namespace Microsoft.PowerShell.Commands22{23 /// <summary>24 /// Class that implements the Get-WinEvent cmdlet.25 /// </summary>26 [OutputType(typeof(EventRecord), ParameterSetName = new string[] { "GetLogSet", "GetProviderSet", "FileSet", "HashQuerySet", "XmlQuerySet" })]27 [OutputType(typeof(ProviderMetadata), ParameterSetName = new string[] { "ListProviderSet" })]28 [OutputType(typeof(EventLogConfiguration), ParameterSetName = new string[] { "ListLogSet" })]29 [Cmdlet(VerbsCommon.Get, "WinEvent", DefaultParameterSetName = "GetLogSet", HelpUri = "https://go.microsoft.com/fwlink/?LinkID=2096581")]30 public sealed class GetWinEventCommand : PSCmdlet31 {32 /// <summary>33 /// ListLog parameter.34 /// </summary>35 [Parameter(36 Position = 0,37 Mandatory = true,38 ParameterSetName = "ListLogSet",39 ValueFromPipeline = false,40 ValueFromPipelineByPropertyName = false,41 HelpMessageBaseName = "GetEventResources",42 HelpMessageResourceId = "ListLogParamHelp")]43 [AllowEmptyCollection]44 [SuppressMessage("Microsoft.Performance", "CA1819:PropertiesShouldNotReturnArrays",45 Scope = "member",46 Target = "Microsoft.PowerShell.Commands.GetEvent.ListLog",47 Justification = "A string[] is required here because that is the type Powershell supports")]48 public string[] ListLog { get; set; } = { "*" };49 50 /// <summary>51 /// GetLog parameter.52 /// </summary>53 [Parameter(54 Position = 0,55 ParameterSetName = "GetLogSet",56 ValueFromPipeline = true,57 ValueFromPipelineByPropertyName = true,58 HelpMessageBaseName = "GetEventResources",59 HelpMessageResourceId = "GetLogParamHelp")]60 [SuppressMessage("Microsoft.Performance", "CA1819:PropertiesShouldNotReturnArrays",61 Scope = "member",62 Target = "Microsoft.PowerShell.Commands.GetEvent.LogName",63 Justification = "A string[] is required here because that is the type Powershell supports")]64 public string[] LogName { get; set; } = { "*" };65 66 /// <summary>67 /// ListProvider parameter.68 /// </summary>69 [Parameter(70 Position = 0,71 Mandatory = true,72 ParameterSetName = "ListProviderSet",73 ValueFromPipeline = false,74 ValueFromPipelineByPropertyName = false,75 HelpMessageBaseName = "GetEventResources",76 HelpMessageResourceId = "ListProviderParamHelp")]77 [AllowEmptyCollection]78 [SuppressMessage("Microsoft.Performance", "CA1819:PropertiesShouldNotReturnArrays",79 Scope = "member",80 Target = "Microsoft.PowerShell.Commands.GetEvent.ListProvider",81 Justification = "A string[] is required here because that is the type Powershell supports")]82 public string[] ListProvider { get; set; } = { "*" };83 84 /// <summary>85 /// ProviderName parameter.86 /// </summary>87 [Parameter(88 Position = 0,89 Mandatory = true,90 ParameterSetName = "GetProviderSet",91 ValueFromPipelineByPropertyName = true,92 HelpMessageBaseName = "GetEventResources",93 HelpMessageResourceId = "GetProviderParamHelp")]94 [SuppressMessage("Microsoft.Performance", "CA1819:PropertiesShouldNotReturnArrays",95 Scope = "member",96 Target = "Microsoft.PowerShell.Commands.GetEvent.ProviderName",97 Justification = "A string[] is required here because that is the type Powershell supports")]98 public string[] ProviderName { get; set; }99 100 /// <summary>101 /// Path parameter.102 /// </summary>103 [Parameter(104 Position = 0,105 Mandatory = true,106 ParameterSetName = "FileSet",107 ValueFromPipelineByPropertyName = true,108 HelpMessageBaseName = "GetEventResources",109 HelpMessageResourceId = "PathParamHelp")]110 [Alias("PSPath")]111 [SuppressMessage("Microsoft.Performance", "CA1819:PropertiesShouldNotReturnArrays",112 Scope = "member",113 Target = "Microsoft.PowerShell.Commands.GetEvent.Path",114 Justification = "A string[] is required here because that is the type Powershell supports")]115 public string[] Path { get; set; }116 117 /// <summary>118 /// MaxEvents parameter.119 /// </summary>120 [Parameter(121 ParameterSetName = "FileSet",122 ValueFromPipeline = false,123 ValueFromPipelineByPropertyName = false,124 HelpMessageBaseName = "GetEventResources",125 HelpMessageResourceId = "MaxEventsParamHelp")]126 [Parameter(127 ParameterSetName = "GetProviderSet",128 ValueFromPipeline = false,129 ValueFromPipelineByPropertyName = false,130 HelpMessageBaseName = "GetEventResources",131 HelpMessageResourceId = "MaxEventsParamHelp")]132 [Parameter(133 ParameterSetName = "GetLogSet",134 ValueFromPipeline = false,135 ValueFromPipelineByPropertyName = false,136 HelpMessageBaseName = "GetEventResources",137 HelpMessageResourceId = "MaxEventsParamHelp")]138 [Parameter(139 ParameterSetName = "HashQuerySet",140 ValueFromPipeline = false,141 ValueFromPipelineByPropertyName = false,142 HelpMessageBaseName = "GetEventResources",143 HelpMessageResourceId = "MaxEventsParamHelp")]144 [Parameter(145 ParameterSetName = "XmlQuerySet",146 ValueFromPipeline = false,147 ValueFromPipelineByPropertyName = false,148 HelpMessageBaseName = "GetEventResources",149 HelpMessageResourceId = "MaxEventsParamHelp")]150 [ValidateRange((long)1, long.MaxValue)]151 public long MaxEvents { get; set; } = -1;152 153 /// <summary>154 /// ComputerName parameter.155 /// </summary>156 [Parameter(157 ParameterSetName = "ListProviderSet",158 HelpMessageBaseName = "GetEventResources",159 HelpMessageResourceId = "ComputerNameParamHelp")]160 [Parameter(161 ParameterSetName = "GetProviderSet",162 HelpMessageBaseName = "GetEventResources",163 HelpMessageResourceId = "ComputerNameParamHelp")]164 [Parameter(165 ParameterSetName = "ListLogSet",166 HelpMessageBaseName = "GetEventResources",167 HelpMessageResourceId = "ComputerNameParamHelp")]168 [Parameter(169 ParameterSetName = "GetLogSet",170 HelpMessageBaseName = "GetEventResources",171 HelpMessageResourceId = "ComputerNameParamHelp")]172 [Parameter(173 ParameterSetName = "HashQuerySet",174 HelpMessageBaseName = "GetEventResources",175 HelpMessageResourceId = "ComputerNameParamHelp")]176 [Parameter(177 ParameterSetName = "XmlQuerySet",178 HelpMessageBaseName = "GetEventResources",179 HelpMessageResourceId = "ComputerNameParamHelp")]180 [ValidateNotNull]181 [Alias("Cn")]182 public string ComputerName { get; set; } = string.Empty;183 184 /// <summary>185 /// Credential parameter.186 /// </summary>187 [Parameter(ParameterSetName = "ListProviderSet")]188 [Parameter(ParameterSetName = "GetProviderSet")]189 [Parameter(ParameterSetName = "ListLogSet")]190 [Parameter(ParameterSetName = "GetLogSet")]191 [Parameter(ParameterSetName = "HashQuerySet")]192 [Parameter(ParameterSetName = "XmlQuerySet")]193 [Parameter(ParameterSetName = "FileSet")]194 [Credential]195 public PSCredential Credential { get; set; } = PSCredential.Empty;196 197 /// <summary>198 /// FilterXPath parameter.199 /// </summary>200 [Parameter(201 ParameterSetName = "FileSet",202 ValueFromPipeline = false,203 ValueFromPipelineByPropertyName = false,204 HelpMessageBaseName = "GetEventResources")]205 [Parameter(206 ParameterSetName = "GetProviderSet",207 ValueFromPipeline = false,208 ValueFromPipelineByPropertyName = false,209 HelpMessageBaseName = "GetEventResources")]210 [Parameter(211 ParameterSetName = "GetLogSet",212 ValueFromPipeline = false,213 ValueFromPipelineByPropertyName = false,214 HelpMessageBaseName = "GetEventResources")]215 [ValidateNotNull]216 public string FilterXPath { get; set; } = "*";217 218 /// <summary>219 /// FilterXml parameter.220 /// </summary>221 [Parameter(222 Position = 0,223 Mandatory = true,224 ValueFromPipeline = false,225 ValueFromPipelineByPropertyName = false,226 ParameterSetName = "XmlQuerySet",227 HelpMessageBaseName = "GetEventResources")]228 public XmlDocument FilterXml { get; set; }229 230 /// <summary>231 /// FilterHashtable parameter.232 /// </summary>233 [Parameter(234 Position = 0,235 Mandatory = true,236 ValueFromPipeline = false,237 ValueFromPipelineByPropertyName = false,238 ParameterSetName = "HashQuerySet",239 HelpMessageBaseName = "GetEventResources")]240 [SuppressMessage("Microsoft.Performance", "CA1819:PropertiesShouldNotReturnArrays",241 Scope = "member",242 Target = "Microsoft.PowerShell.Commands.GetEvent.FilterHashtable",243 Justification = "A string[] is required here because that is the type Powershell supports")]244 public Hashtable[] FilterHashtable { get; set; }245 246 /// <summary>247 /// Force switch.248 /// </summary>249 [Parameter(ParameterSetName = "ListLogSet")]250 [Parameter(ParameterSetName = "GetProviderSet")]251 [Parameter(ParameterSetName = "GetLogSet")]252 [Parameter(ParameterSetName = "HashQuerySet")]253 public SwitchParameter Force { get; set; }254 255 /// <summary>256 /// Oldest switch.257 /// </summary>258 [Parameter(ParameterSetName = "FileSet")]259 [Parameter(ParameterSetName = "GetProviderSet")]260 [Parameter(ParameterSetName = "GetLogSet")]261 [Parameter(ParameterSetName = "HashQuerySet")]262 [Parameter(ParameterSetName = "XmlQuerySet")]263 public SwitchParameter Oldest264 {265 get { return _oldest; }266 267 set { _oldest = value; }268 }269 270 private bool _oldest = false;271 272 //273 // Query builder constant strings274 //275 private const string queryListOpen = "<QueryList>";276 private const string queryListClose = "</QueryList>";277 private const string queryTemplate = "<Query Id=\"{0}\" Path=\"{1}\"><Select Path=\"{1}\">{2}</Select></Query>";278 private const string queryOpenerTemplate = "<Query Id=\"{0}\" Path=\"{1}\"><Select Path=\"{1}\">*";279 private const string queryCloser = "</Query>";280 private const string SelectCloser = "</Select>";281 private const string suppressOpener = "<Suppress>*";282 private const string suppressCloser = "</Suppress>";283 private const char propOpen = '[';284 private const char propClose = ']';285 private const string filePrefix = "file://";286 private const string NamedDataTemplate = "((EventData[Data[@Name='{0}']='{1}']) or (UserData/*/{0}='{1}'))";287 private const string DataTemplate = "(EventData/Data='{0}')";288 private const string SystemTimePeriodTemplate = "(System/TimeCreated[@SystemTime>='{0}' and @SystemTime<='{1}'])";289 private const string SystemTimeStartTemplate = "(System/TimeCreated[@SystemTime>='{0}'])";290 private const string SystemTimeEndTemplate = "(System/TimeCreated[@SystemTime<='{0}'])";291 private const string SystemLevelTemplate = "(System/Level=";292 private const string SystemEventIDTemplate = "(System/EventID=";293 private const string SystemSecurityTemplate = "(System/Security[@UserID='{0}'])";294 private const string SystemKeywordsTemplate = "System[band(Keywords,{0})]";295 296 //297 // Other private members and constants298 //299 private ResourceManager _resourceMgr = null;300 private readonly Dictionary<string, StringCollection> _providersByLogMap = new();301 302 private StringCollection _logNamesMatchingWildcard = null;303 private readonly StringCollection _resolvedPaths = new();304 305 private readonly List<string> _accumulatedLogNames = new();306 private readonly List<string> _accumulatedProviderNames = new();307 private readonly List<string> _accumulatedFileNames = new();308 309 private const uint MAX_EVENT_BATCH = 100;310 311 //312 // Hashtable query key names313 //314 private const string hashkey_logname_lc = "logname";315 private const string hashkey_providername_lc = "providername";316 private const string hashkey_path_lc = "path";317 private const string hashkey_keywords_lc = "keywords";318 private const string hashkey_id_lc = "id";319 private const string hashkey_level_lc = "level";320 private const string hashkey_starttime_lc = "starttime";321 private const string hashkey_endtime_lc = "endtime";322 private const string hashkey_userid_lc = "userid";323 private const string hashkey_data_lc = "data";324 private const string hashkey_supress_lc = "suppresshashfilter";325 326 /// <summary>327 /// BeginProcessing() is invoked once per pipeline: we will load System.Core.dll here.328 /// </summary>329 protected override void BeginProcessing()330 {331 _resourceMgr = Microsoft.PowerShell.Commands.Diagnostics.Common.CommonUtilities.GetResourceManager();332 }333 334 /// <summary>335 /// EndProcessing() is invoked once per pipeline.336 /// </summary>337 protected override void EndProcessing()338 {339 switch (ParameterSetName)340 {341 case "GetLogSet":342 ProcessGetLog();343 break;344 345 case "FileSet":346 ProcessFile();347 break;348 349 case "GetProviderSet":350 ProcessGetProvider();351 break;352 353 default:354 break;355 }356 }357 358 /// <summary>359 /// ProcessRecord() override.360 /// This is the main entry point for the cmdlet.361 /// </summary>362 protected override void ProcessRecord()363 {364 switch (ParameterSetName)365 {366 case "ListLogSet":367 ProcessListLog();368 break;369 370 case "ListProviderSet":371 ProcessListProvider();372 break;373 374 case "GetLogSet":375 AccumulatePipelineLogNames();376 break;377 378 case "FileSet":379 AccumulatePipelineFileNames();380 break;381 382 case "HashQuerySet":383 ProcessHashQuery();384 break;385 386 case "GetProviderSet":387 AccumulatePipelineProviderNames();388 break;389 390 case "XmlQuerySet":391 ProcessFilterXml();392 break;393 394 default:395 WriteDebug(string.Create(CultureInfo.InvariantCulture, $"Invalid parameter set name: {ParameterSetName}"));396 break;397 }398 }399 400 //401 // AccumulatePipelineCounters() accumulates log names in the pipeline scenario:402 // we do not want to construct a query until all the log names are supplied.403 //404 private void AccumulatePipelineLogNames()405 {406 _accumulatedLogNames.AddRange(LogName);407 }408 409 //410 // AccumulatePipelineProviderNames() accumulates provider names in the pipeline scenario:411 // we do not want to construct a query until all the provider names are supplied.412 //413 private void AccumulatePipelineProviderNames()414 {415 _accumulatedProviderNames.AddRange(LogName);416 }417 418 //419 // AccumulatePipelineFileNames() accumulates log file paths in the pipeline scenario:420 // we do not want to construct a query until all the file names are supplied.421 //422 private void AccumulatePipelineFileNames()423 {424 _accumulatedFileNames.AddRange(LogName);425 }426 427 //428 // Process GetLog parameter set429 //430 private void ProcessGetLog()431 {432 using (EventLogSession eventLogSession = CreateSession())433 {434 FindLogNamesMatchingWildcards(eventLogSession, _accumulatedLogNames);435 if (_logNamesMatchingWildcard.Count == 0)436 {437 return;438 }439 440 EventLogQuery logQuery;441 if (_logNamesMatchingWildcard.Count > 1)442 {443 string query = BuildStructuredQuery(eventLogSession);444 logQuery = new EventLogQuery(null, PathType.LogName, query);445 logQuery.TolerateQueryErrors = true;446 }447 else448 {449 logQuery = new EventLogQuery(_logNamesMatchingWildcard[0], PathType.LogName, FilterXPath);450 }451 452 logQuery.Session = eventLogSession;453 logQuery.ReverseDirection = !_oldest;454 455 ReadEvents(logQuery);456 }457 }458 459 //460 // Process GetProviderSet parameter set461 //462 private void ProcessGetProvider()463 {464 using (EventLogSession eventLogSession = CreateSession())465 {466 FindProvidersByLogForWildcardPatterns(eventLogSession, ProviderName);467 468 if (_providersByLogMap.Count == 0)469 {470 //471 // Just return: errors already written above for each unmatched provider name pattern.472 //473 return;474 }475 476 EventLogQuery logQuery = null;477 if (_providersByLogMap.Count > 1)478 {479 string query = BuildStructuredQuery(eventLogSession);480 logQuery = new EventLogQuery(null, PathType.LogName, query);481 logQuery.TolerateQueryErrors = true;482 }483 else484 {485 //486 // There's only one key at this point, but we need an enumerator to get to it.487 //488 foreach (string log in _providersByLogMap.Keys)489 {490 logQuery = new EventLogQuery(log, PathType.LogName, AddProviderPredicatesToFilter(_providersByLogMap[log]));491 WriteVerbose(string.Create(CultureInfo.InvariantCulture, $"Log {log} will be queried"));492 }493 }494 495 logQuery.Session = eventLogSession;496 logQuery.ReverseDirection = !_oldest;497 498 ReadEvents(logQuery);499 }500 }501 502 //503 // Process ListLog parameter set504 //505 private void ProcessListLog()506 {507 using (EventLogSession eventLogSession = CreateSession())508 {509 foreach (string logPattern in ListLog)510 {511 bool bMatchFound = false;512 WildcardPattern wildLogPattern = new(logPattern, WildcardOptions.IgnoreCase);513 514 foreach (string logName in eventLogSession.GetLogNames())515 {516 if (((!WildcardPattern.ContainsWildcardCharacters(logPattern))517 && string.Equals(logPattern, logName, StringComparison.OrdinalIgnoreCase))518 ||519 (wildLogPattern.IsMatch(logName)))520 {521 try522 {523 EventLogConfiguration logObj = new(logName, eventLogSession);524 525 //526 // Skip direct channels matching the wildcard unless -Force is present.527 //528 if (!Force.IsPresent &&529 WildcardPattern.ContainsWildcardCharacters(logPattern) &&530 (logObj.LogType == EventLogType.Debug ||531 logObj.LogType == EventLogType.Analytical))532 {533 continue;534 }535 536 EventLogInformation logInfoObj = eventLogSession.GetLogInformation(logName, PathType.LogName);537 538 PSObject outputObj = new(logObj);539 540 outputObj.Properties.Add(new PSNoteProperty("FileSize", logInfoObj.FileSize));541 outputObj.Properties.Add(new PSNoteProperty("IsLogFull", logInfoObj.IsLogFull));542 outputObj.Properties.Add(new PSNoteProperty("LastAccessTime", logInfoObj.LastAccessTime));543 outputObj.Properties.Add(new PSNoteProperty("LastWriteTime", logInfoObj.LastWriteTime));544 outputObj.Properties.Add(new PSNoteProperty("OldestRecordNumber", logInfoObj.OldestRecordNumber));545 outputObj.Properties.Add(new PSNoteProperty("RecordCount", logInfoObj.RecordCount));546 547 WriteObject(outputObj);548 bMatchFound = true;549 }550 catch (Exception exc)551 {552 string msg = string.Format(CultureInfo.InvariantCulture,553 _resourceMgr.GetString("LogInfoUnavailable"),554 logName, exc.Message);555 Exception outerExc = new(msg, exc);556 WriteError(new ErrorRecord(outerExc, "LogInfoUnavailable", ErrorCategory.NotSpecified, null));557 continue;558 }559 }560 }561 562 if (!bMatchFound)563 {564 string msg = _resourceMgr.GetString("NoMatchingLogsFound");565 Exception exc = new(string.Format(CultureInfo.InvariantCulture, msg, ComputerName, logPattern));566 WriteError(new ErrorRecord(exc, "NoMatchingLogsFound", ErrorCategory.ObjectNotFound, null));567 }568 }569 }570 }571 572 //573 // Process ListProvider parameter set574 //575 private void ProcessListProvider()576 {577 using (EventLogSession eventLogSession = CreateSession())578 {579 foreach (string provPattern in ListProvider)580 {581 bool bMatchFound = false;582 WildcardPattern wildProvPattern = new(provPattern, WildcardOptions.IgnoreCase);583 584 foreach (string provName in eventLogSession.GetProviderNames())585 {586 if (((!WildcardPattern.ContainsWildcardCharacters(provPattern))587 && string.Equals(provPattern, provName, StringComparison.OrdinalIgnoreCase))588 ||589 (wildProvPattern.IsMatch(provName)))590 {591 try592 {593 ProviderMetadata provObj = new(provName, eventLogSession, CultureInfo.CurrentCulture);594 WriteObject(provObj);595 bMatchFound = true;596 }597 catch (System.Diagnostics.Eventing.Reader.EventLogException exc)598 {599 string msg = string.Format(CultureInfo.InvariantCulture,600 _resourceMgr.GetString("ProviderMetadataUnavailable"),601 provName, exc.Message);602 Exception outerExc = new(msg, exc);603 WriteError(new ErrorRecord(outerExc, "ProviderMetadataUnavailable", ErrorCategory.NotSpecified, null));604 continue;605 }606 }607 }608 609 if (!bMatchFound)610 {611 string msg = string.Format(CultureInfo.InvariantCulture, _resourceMgr.GetString("NoMatchingProvidersFound"),612 ComputerName, provPattern);613 Exception exc = new(msg);614 WriteError(new ErrorRecord(exc, "NoMatchingProvidersFound", ErrorCategory.ObjectNotFound, null));615 }616 }617 }618 }619 620 //621 // Process FilterXml parameter set622 //623 private void ProcessFilterXml()624 {625 using (EventLogSession eventLogSession = CreateSession())626 {627 if (!Oldest.IsPresent)628 {629 //630 // Do minimal parsing of xmlQuery to determine if any direct channels or ETL files are in it.631 //632 XmlElement root = FilterXml.DocumentElement;633 XmlNodeList queryNodes = root.SelectNodes("//Query//Select");634 foreach (XmlNode queryNode in queryNodes)635 {636 XmlAttributeCollection attribs = queryNode.Attributes;637 foreach (XmlAttribute attrib in attribs)638 {639 if (attrib.Name.Equals("Path", StringComparison.OrdinalIgnoreCase))640 {641 string logName = attrib.Value;642 643 if (logName.StartsWith(filePrefix, StringComparison.OrdinalIgnoreCase))644 {645 TerminateForNonEvtxFileWithoutOldest(logName);646 }647 648 ValidateLogName(logName, eventLogSession);649 }650 }651 }652 }653 654 EventLogQuery logQuery = new(null, PathType.LogName, FilterXml.InnerXml);655 logQuery.Session = eventLogSession;656 logQuery.ReverseDirection = !_oldest;657 658 ReadEvents(logQuery);659 }660 }661 662 //663 // Process FileSet parameter set664 //665 private void ProcessFile()666 {667 using (EventLogSession eventLogSession = CreateSession())668 {669 //670 // At this point, _path array contains paths that might have wildcards,671 // environment variables or PS drives. Let's resolve those.672 //673 for (int i = 0; i < Path.Length; i++)674 {675 StringCollection resolvedPaths = ValidateAndResolveFilePath(Path[i]);676 foreach (string resolvedPath in resolvedPaths)677 {678 _resolvedPaths.Add(resolvedPath);679 WriteVerbose(string.Create(CultureInfo.InvariantCulture, $"Found file {resolvedPath}"));680 }681 }682 683 EventLogQuery logQuery = null;684 if (_resolvedPaths.Count == 0)685 {686 return;687 }688 else if (_resolvedPaths.Count > 1)689 {690 string query = BuildStructuredQuery(eventLogSession);691 logQuery = new EventLogQuery(null, PathType.FilePath, query);692 logQuery.TolerateQueryErrors = true;693 }694 else695 {696 logQuery = new EventLogQuery(_resolvedPaths[0], PathType.FilePath, FilterXPath);697 }698 699 logQuery.Session = eventLogSession;700 logQuery.ReverseDirection = !_oldest;701 702 ReadEvents(logQuery);703 }704 }705 706 //707 // Process HashQuerySet parameter set708 //709 private void ProcessHashQuery()710 {711 CheckHashTablesForNullValues();712 713 using (EventLogSession eventLogSession = CreateSession())714 {715 string query = BuildStructuredQuery(eventLogSession);716 if (query.Length == 0)717 {718 return;719 }720 721 EventLogQuery logQuery = new(null, PathType.FilePath, query);722 logQuery.Session = eventLogSession;723 logQuery.TolerateQueryErrors = true;724 logQuery.ReverseDirection = !_oldest;725 726 ReadEvents(logQuery);727 }728 }729 730 //731 // CreateSession creates an EventLogSession connected to a target machine or localhost.732 // If _credential argument is PSCredential.Empty, the session will be created for the current context.733 //734 private EventLogSession CreateSession()735 {736 EventLogSession eventLogSession = null;737 738 if (ComputerName == string.Empty)739 {740 // Set _computerName to "localhost" for future error messages,741 // but do not use it for the connection to avoid RPC overhead.742 ComputerName = "localhost";743 744 if (Credential == PSCredential.Empty)745 {746 return new EventLogSession();747 }748 }749 else if (Credential == PSCredential.Empty)750 {751 return new EventLogSession(ComputerName);752 }753 754 // If we are here, either both computer name and credential were passed initially,755 // or credential only - we will use it with "localhost"756 757 NetworkCredential netCred = (NetworkCredential)Credential;758 eventLogSession = new EventLogSession(ComputerName,759 netCred.Domain,760 netCred.UserName,761 Credential.Password,762 SessionAuthentication.Default763 );764 //765 // Force the destruction of cached password766 //767 netCred.Password = string.Empty;768 769 return eventLogSession;770 }771 772 //773 // ReadEvents helper.774 //775 private void ReadEvents(EventLogQuery logQuery)776 {777 using (EventLogReader readerObj = new(logQuery))778 {779 long numEvents = 0;780 EventRecord evtObj = null;781 782 while (true)783 {784 try785 {786 evtObj = readerObj.ReadEvent();787 }788 catch (Exception exc)789 {790 WriteError(new ErrorRecord(exc, exc.Message, ErrorCategory.NotSpecified, null));791 continue;792 }793 794 if (evtObj == null)795 {796 break;797 }798 799 if (MaxEvents != -1 && numEvents >= MaxEvents)800 {801 break;802 }803 804 PSObject outputObj = new(evtObj);805 806 string evtMessage = _resourceMgr.GetString("NoEventMessage");807 try808 {809 evtMessage = evtObj.FormatDescription();810 }811 catch (Exception exc)812 {813 WriteError(new ErrorRecord(exc, exc.Message, ErrorCategory.NotSpecified, null));814 }815 816 outputObj.Properties.Add(new PSNoteProperty("Message", evtMessage));817 818 //819 // Enumerate the object one level to get to event payload820 //821 WriteObject(outputObj, true);822 numEvents++;823 }824 825 if (numEvents == 0)826 {827 string msg = _resourceMgr.GetString("NoMatchingEventsFound");828 Exception exc = new(msg);829 WriteError(new ErrorRecord(exc, "NoMatchingEventsFound", ErrorCategory.ObjectNotFound, null));830 }831 }832 }833 834 //835 // BuildStructuredQuery() builds a structured query from cmdlet arguments.836 //837 private string BuildStructuredQuery(EventLogSession eventLogSession)838 {839 StringBuilder result = new();840 841 switch (ParameterSetName)842 {843 case "ListLogSet":844 break;845 846 case "ListProviderSet":847 break;848 849 case "GetProviderSet":850 {851 result.Append(queryListOpen);852 uint queryId = 0;853 854 foreach (string log in _providersByLogMap.Keys)855 {856 string providerFilter = AddProviderPredicatesToFilter(_providersByLogMap[log]);857 result.AppendFormat(CultureInfo.InvariantCulture, queryTemplate, new object[] { queryId++, log, providerFilter });858 }859 860 result.Append(queryListClose);861 }862 863 break;864 865 case "GetLogSet":866 {867 const int WindowsEventLogAPILimit = 256;868 if (_logNamesMatchingWildcard.Count > WindowsEventLogAPILimit)869 {870 string msg = _resourceMgr.GetString("LogCountLimitExceeded");871 Exception exc = new(string.Format(CultureInfo.InvariantCulture, msg, _logNamesMatchingWildcard.Count, WindowsEventLogAPILimit));872 ThrowTerminatingError(new ErrorRecord(exc, "LogCountLimitExceeded", ErrorCategory.LimitsExceeded, null));873 }874 875 result.Append(queryListOpen);876 uint queryId = 0;877 foreach (string log in _logNamesMatchingWildcard)878 {879 result.AppendFormat(CultureInfo.InvariantCulture, queryTemplate, new object[] { queryId++, log, FilterXPath });880 }881 882 result.Append(queryListClose);883 }884 885 break;886 887 case "FileSet":888 {889 result.Append(queryListOpen);890 uint queryId = 0;891 foreach (string filePath in _resolvedPaths)892 {893 string properFilePath = filePrefix + filePath;894 result.AppendFormat(CultureInfo.InvariantCulture, queryTemplate, new object[] { queryId++, properFilePath, FilterXPath });895 }896 897 result.Append(queryListClose);898 }899 900 break;901 902 case "HashQuerySet":903 result.Append(BuildStructuredQueryFromHashTable(eventLogSession));904 break;905 906 default:907 WriteDebug(string.Create(CultureInfo.InvariantCulture, $"Invalid parameter set name: {ParameterSetName}"));908 break;909 }910 911 WriteVerbose(string.Format(CultureInfo.InvariantCulture, _resourceMgr.GetString("QueryTrace"), result.ToString()));912 913 return result.ToString();914 }915 916 //917 // BuildXPathFromHashTable() build xpath from hashtable918 //919 private string BuildXPathFromHashTable(Hashtable hash)920 {921 StringBuilder xpathString = new(string.Empty);922 bool bDateTimeHandled = false;923 924 foreach (string key in hash.Keys)925 {926 string added = string.Empty;927 928 switch (key.ToLowerInvariant())929 {930 case hashkey_logname_lc:931 case hashkey_path_lc:932 case hashkey_providername_lc:933 break;934 case hashkey_id_lc:935 added = HandleEventIdHashValue(hash[key]);936 break;937 938 case hashkey_level_lc:939 added = HandleLevelHashValue(hash[key]);940 break;941 942 case hashkey_keywords_lc:943 added = HandleKeywordHashValue(hash[key]);944 break;945 946 case hashkey_starttime_lc:947 if (bDateTimeHandled)948 {949 break;950 }951 952 added = HandleStartTimeHashValue(hash[key], hash);953 954 bDateTimeHandled = true;955 break;956 957 case hashkey_endtime_lc:958 if (bDateTimeHandled)959 {960 break;961 }962 963 added = HandleEndTimeHashValue(hash[key], hash);964 965 bDateTimeHandled = true;966 break;967 968 case hashkey_data_lc:969 added = HandleDataHashValue(hash[key]);970 break;971 972 case hashkey_userid_lc:973 added = HandleContextHashValue(hash[key]);974 break;975 976 case hashkey_supress_lc:977 break;978 default:979 {980 //981 // None of the recognized values: this must be a named event data field982 //983 // Fix Issue #2327984 added = HandleNamedDataHashValue(key, hash[key]);985 }986 987 break;988 }989 990 if (added.Length > 0)991 {992 if (xpathString.Length != 0)993 {994 xpathString.Append(" and ");995 }996 997 xpathString.Append(added);998 }999 }1000 1001 return xpathString.ToString();1002 }1003 1004 //1005 // BuildStructuredQueryFromHashTable() helper.1006 // Builds a structured query from the hashtable (Selector) argument.1007 //1008 private string BuildStructuredQueryFromHashTable(EventLogSession eventLogSession)1009 {1010 StringBuilder result = new(string.Empty);1011 1012 result.Append(queryListOpen);1013 1014 uint queryId = 0;1015 1016 foreach (Hashtable hash in FilterHashtable)1017 {1018 string xpathString = string.Empty;1019 string xpathStringSuppress = string.Empty;1020 1021 CheckHashTableForQueryPathPresence(hash);1022 1023 //1024 // Local queriedLogsQueryMap will hold names of logs or files to be queried1025 // mapped to the actual query strings being built up.1026 //1027 Dictionary<string, string> queriedLogsQueryMap = new();1028 1029 //1030 // queriedLogsQueryMapSuppress is the same as queriedLogsQueryMap but for <Suppress>1031 //1032 Dictionary<string, string> queriedLogsQueryMapSuppress = new();1033 1034 //1035 // Process log, _path, or provider parameters first1036 // to create initial partially-filled query templates.1037 // Error out for direct channels unless -oldest is present.1038 //1039 // Order is important! Process "providername" key after "logname" and "file".1040 //1041 if (hash.ContainsKey(hashkey_logname_lc))1042 {1043 List<string> logPatterns = new();1044 if (hash[hashkey_logname_lc] is Array)1045 {1046 foreach (object elt in (Array)hash[hashkey_logname_lc])1047 {1048 logPatterns.Add(elt.ToString());1049 }1050 }1051 else1052 {1053 logPatterns.Add(hash[hashkey_logname_lc].ToString());1054 }1055 1056 FindLogNamesMatchingWildcards(eventLogSession, logPatterns);1057 1058 foreach (string logName in _logNamesMatchingWildcard)1059 {1060 queriedLogsQueryMap.Add(logName.ToLowerInvariant(),1061 string.Format(CultureInfo.InvariantCulture, queryOpenerTemplate, queryId++, logName));1062 queriedLogsQueryMapSuppress.Add(logName.ToLowerInvariant(),1063 string.Format(CultureInfo.InvariantCulture, suppressOpener, queryId++, logName));1064 }1065 }1066 1067 if (hash.ContainsKey(hashkey_path_lc))1068 {1069 if (hash[hashkey_path_lc] is Array)1070 {1071 foreach (object elt in (Array)hash[hashkey_path_lc])1072 {1073 StringCollection resolvedPaths = ValidateAndResolveFilePath(elt.ToString());1074 foreach (string resolvedPath in resolvedPaths)1075 {1076 queriedLogsQueryMap.Add(filePrefix + resolvedPath.ToLowerInvariant(),1077 string.Format(CultureInfo.InvariantCulture, queryOpenerTemplate, queryId++, filePrefix + resolvedPath));1078 queriedLogsQueryMapSuppress.Add(filePrefix + resolvedPath.ToLowerInvariant(),1079 string.Format(CultureInfo.InvariantCulture, suppressOpener, queryId++, filePrefix + resolvedPath));1080 }1081 }1082 }1083 else1084 {1085 StringCollection resolvedPaths = ValidateAndResolveFilePath(hash[hashkey_path_lc].ToString());1086 foreach (string resolvedPath in resolvedPaths)1087 {1088 queriedLogsQueryMap.Add(filePrefix + resolvedPath.ToLowerInvariant(),1089 string.Format(CultureInfo.InvariantCulture, queryOpenerTemplate, queryId++, filePrefix + resolvedPath));1090 queriedLogsQueryMapSuppress.Add(filePrefix + resolvedPath.ToLowerInvariant(),1091 string.Format(CultureInfo.InvariantCulture, suppressOpener, queryId++, filePrefix + resolvedPath));1092 }1093 }1094 }1095 1096 if (hash.ContainsKey(hashkey_providername_lc))1097 {1098 List<string> provPatterns = new();1099 if (hash[hashkey_providername_lc] is Array)1100 {1101 foreach (object elt in (Array)hash[hashkey_providername_lc])1102 {1103 provPatterns.Add(elt.ToString());1104 }1105 }1106 else1107 {1108 provPatterns.Add(hash[hashkey_providername_lc].ToString());1109 }1110 1111 FindProvidersByLogForWildcardPatterns(eventLogSession, provPatterns);1112 1113 //1114 // If "providername" key is used alone, we will construct a query across all of the providers' logs.1115 // Otherwise, we will use the provider names to add predicates to "logname" and "path" queries.1116 //1117 if (!hash.ContainsKey(hashkey_path_lc) && !hash.ContainsKey(hashkey_logname_lc))1118 {1119 foreach (string keyLogName in _providersByLogMap.Keys)1120 {1121 string providersPredicate = BuildProvidersPredicate(_providersByLogMap[keyLogName]);1122 string query = string.Format(CultureInfo.InvariantCulture, queryOpenerTemplate, queryId++, keyLogName);1123 queriedLogsQueryMap.Add(keyLogName.ToLowerInvariant(),1124 query + "[" + providersPredicate);1125 queriedLogsQueryMapSuppress.Add(keyLogName.ToLowerInvariant(),1126 string.Format(CultureInfo.InvariantCulture, suppressOpener, queryId++, keyLogName.ToLowerInvariant()));1127 }1128 }1129 else1130 {1131 List<string> keysList = new(queriedLogsQueryMap.Keys);1132 bool bRemovedIrrelevantLogs = false;1133 foreach (string queriedLog in keysList)1134 {1135 if (queriedLog.StartsWith(filePrefix, StringComparison.Ordinal))1136 {1137 queriedLogsQueryMap[queriedLog] += "[" + BuildAllProvidersPredicate();1138 }1139 else1140 {1141 if (_providersByLogMap.ContainsKey(queriedLog))1142 {1143 string providersPredicate = BuildProvidersPredicate(_providersByLogMap[queriedLog]);1144 queriedLogsQueryMap[queriedLog] += "[" + providersPredicate;1145 }1146 else1147 {1148 WriteVerbose(string.Format(CultureInfo.InvariantCulture, _resourceMgr.GetString("SpecifiedProvidersDontWriteToLog"), queriedLog));1149 queriedLogsQueryMap.Remove(queriedLog);1150 queriedLogsQueryMapSuppress.Remove(queriedLog);1151 bRemovedIrrelevantLogs = true;1152 }1153 }1154 }1155 //1156 // Write an error if we have removed all the logs as irrelevant1157 //1158 if (bRemovedIrrelevantLogs && (queriedLogsQueryMap.Count == 0))1159 {1160 string msg = string.Format(CultureInfo.InvariantCulture, _resourceMgr.GetString("LogsAndProvidersDontOverlap"));1161 Exception exc = new(msg);1162 WriteError(new ErrorRecord(exc, "LogsAndProvidersDontOverlap", ErrorCategory.InvalidArgument, null));1163 continue;1164 }1165 }1166 }1167 1168 //1169 // If none of the logs/paths/providers were valid, queriedLogsQueryMap is empty.1170 // Simply continue to the next hashtable since all the errors have been written already.1171 //1172 if (queriedLogsQueryMap.Count == 0)1173 {1174 continue;1175 }1176 1177 //1178 // At this point queriedLogsQueryMap contains all the query openings: missing the actual XPaths1179 // Let's build xpathString to attach to each query opening.1180 //1181 xpathString = BuildXPathFromHashTable(hash);1182 1183 //1184 // Build xpath for <Suppress>1185 //1186 if (hash[hashkey_supress_lc] is Hashtable suppresshash)1187 {1188 xpathStringSuppress = BuildXPathFromHashTable(suppresshash);1189 }1190 1191 //1192 // Complete each query with the XPath.1193 // Handle the case where the query opener already has provider predicate(s).1194 // Add the queries from queriedLogsQueryMap into the resulting string.1195 // Add <Suppress> from queriedLogsQueryMapSuppress into the resulting string.1196 //1197 foreach (string keyLogName in queriedLogsQueryMap.Keys)1198 {1199 // For every Log a separate query is1200 string query = queriedLogsQueryMap[keyLogName];