PowerShell/src/Microsoft.PowerShell.Commands.Diagnostics/GetEventCommand.cs

2063 lines
84 KiB
C#

// Copyright (c) Microsoft Corporation.
// Licensed under the MIT License.
using System;
using System.Collections;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Collections.Specialized;
using System.Diagnostics.CodeAnalysis;
using System.Diagnostics.Eventing.Reader;
using System.Globalization;
using System.Management.Automation;
using System.Net;
using System.Resources;
using System.Security.Principal;
using System.Text;
using System.Xml;
[assembly: CLSCompliant(false)]
namespace Microsoft.PowerShell.Commands
{
/// <summary>
/// Class that implements the Get-WinEvent cmdlet.
/// </summary>
[Cmdlet(VerbsCommon.Get, "WinEvent", DefaultParameterSetName = "GetLogSet", HelpUri = "https://go.microsoft.com/fwlink/?LinkID=2096581")]
public sealed class GetWinEventCommand : PSCmdlet
{
/// <summary>
/// ListLog parameter.
/// </summary>
[Parameter(
Position = 0,
Mandatory = true,
ParameterSetName = "ListLogSet",
ValueFromPipeline = false,
ValueFromPipelineByPropertyName = false,
HelpMessageBaseName = "GetEventResources",
HelpMessageResourceId = "ListLogParamHelp")]
[AllowEmptyCollection]
[SuppressMessage("Microsoft.Performance", "CA1819:PropertiesShouldNotReturnArrays",
Scope = "member",
Target = "Microsoft.PowerShell.Commands.GetEvent.ListLog",
Justification = "A string[] is required here because that is the type Powershell supports")]
public string[] ListLog { get; set; } = { "*" };
/// <summary>
/// GetLog parameter.
/// </summary>
[Parameter(
Position = 0,
ParameterSetName = "GetLogSet",
ValueFromPipeline = true,
ValueFromPipelineByPropertyName = true,
HelpMessageBaseName = "GetEventResources",
HelpMessageResourceId = "GetLogParamHelp")]
[SuppressMessage("Microsoft.Performance", "CA1819:PropertiesShouldNotReturnArrays",
Scope = "member",
Target = "Microsoft.PowerShell.Commands.GetEvent.LogName",
Justification = "A string[] is required here because that is the type Powershell supports")]
public string[] LogName { get; set; } = { "*" };
/// <summary>
/// ListProvider parameter.
/// </summary>
[Parameter(
Position = 0,
Mandatory = true,
ParameterSetName = "ListProviderSet",
ValueFromPipeline = false,
ValueFromPipelineByPropertyName = false,
HelpMessageBaseName = "GetEventResources",
HelpMessageResourceId = "ListProviderParamHelp")]
[AllowEmptyCollection]
[SuppressMessage("Microsoft.Performance", "CA1819:PropertiesShouldNotReturnArrays",
Scope = "member",
Target = "Microsoft.PowerShell.Commands.GetEvent.ListProvider",
Justification = "A string[] is required here because that is the type Powershell supports")]
public string[] ListProvider { get; set; } = { "*" };
/// <summary>
/// ProviderName parameter.
/// </summary>
[Parameter(
Position = 0,
Mandatory = true,
ParameterSetName = "GetProviderSet",
ValueFromPipelineByPropertyName = true,
HelpMessageBaseName = "GetEventResources",
HelpMessageResourceId = "GetProviderParamHelp")]
[SuppressMessage("Microsoft.Performance", "CA1819:PropertiesShouldNotReturnArrays",
Scope = "member",
Target = "Microsoft.PowerShell.Commands.GetEvent.ProviderName",
Justification = "A string[] is required here because that is the type Powershell supports")]
public string[] ProviderName { get; set; }
/// <summary>
/// Path parameter.
/// </summary>
[Parameter(
Position = 0,
Mandatory = true,
ParameterSetName = "FileSet",
ValueFromPipelineByPropertyName = true,
HelpMessageBaseName = "GetEventResources",
HelpMessageResourceId = "PathParamHelp")]
[Alias("PSPath")]
[SuppressMessage("Microsoft.Performance", "CA1819:PropertiesShouldNotReturnArrays",
Scope = "member",
Target = "Microsoft.PowerShell.Commands.GetEvent.Path",
Justification = "A string[] is required here because that is the type Powershell supports")]
public string[] Path { get; set; }
/// <summary>
/// MaxEvents parameter.
/// </summary>
[Parameter(
ParameterSetName = "FileSet",
ValueFromPipeline = false,
ValueFromPipelineByPropertyName = false,
HelpMessageBaseName = "GetEventResources",
HelpMessageResourceId = "MaxEventsParamHelp")]
[Parameter(
ParameterSetName = "GetProviderSet",
ValueFromPipeline = false,
ValueFromPipelineByPropertyName = false,
HelpMessageBaseName = "GetEventResources",
HelpMessageResourceId = "MaxEventsParamHelp")]
[Parameter(
ParameterSetName = "GetLogSet",
ValueFromPipeline = false,
ValueFromPipelineByPropertyName = false,
HelpMessageBaseName = "GetEventResources",
HelpMessageResourceId = "MaxEventsParamHelp")]
[Parameter(
ParameterSetName = "HashQuerySet",
ValueFromPipeline = false,
ValueFromPipelineByPropertyName = false,
HelpMessageBaseName = "GetEventResources",
HelpMessageResourceId = "MaxEventsParamHelp")]
[Parameter(
ParameterSetName = "XmlQuerySet",
ValueFromPipeline = false,
ValueFromPipelineByPropertyName = false,
HelpMessageBaseName = "GetEventResources",
HelpMessageResourceId = "MaxEventsParamHelp")]
[ValidateRange((long)1, long.MaxValue)]
public long MaxEvents { get; set; } = -1;
/// <summary>
/// ComputerName parameter.
/// </summary>
[Parameter(
ParameterSetName = "ListProviderSet",
HelpMessageBaseName = "GetEventResources",
HelpMessageResourceId = "ComputerNameParamHelp")]
[Parameter(
ParameterSetName = "GetProviderSet",
HelpMessageBaseName = "GetEventResources",
HelpMessageResourceId = "ComputerNameParamHelp")]
[Parameter(
ParameterSetName = "ListLogSet",
HelpMessageBaseName = "GetEventResources",
HelpMessageResourceId = "ComputerNameParamHelp")]
[Parameter(
ParameterSetName = "GetLogSet",
HelpMessageBaseName = "GetEventResources",
HelpMessageResourceId = "ComputerNameParamHelp")]
[Parameter(
ParameterSetName = "HashQuerySet",
HelpMessageBaseName = "GetEventResources",
HelpMessageResourceId = "ComputerNameParamHelp")]
[Parameter(
ParameterSetName = "XmlQuerySet",
HelpMessageBaseName = "GetEventResources",
HelpMessageResourceId = "ComputerNameParamHelp")]
[ValidateNotNull]
[Alias("Cn")]
public string ComputerName { get; set; } = string.Empty;
/// <summary>
/// Credential parameter.
/// </summary>
[Parameter(ParameterSetName = "ListProviderSet")]
[Parameter(ParameterSetName = "GetProviderSet")]
[Parameter(ParameterSetName = "ListLogSet")]
[Parameter(ParameterSetName = "GetLogSet")]
[Parameter(ParameterSetName = "HashQuerySet")]
[Parameter(ParameterSetName = "XmlQuerySet")]
[Parameter(ParameterSetName = "FileSet")]
[Credential]
public PSCredential Credential { get; set; } = PSCredential.Empty;
/// <summary>
/// FilterXPath parameter.
/// </summary>
[Parameter(
ParameterSetName = "FileSet",
ValueFromPipeline = false,
ValueFromPipelineByPropertyName = false,
HelpMessageBaseName = "GetEventResources")]
[Parameter(
ParameterSetName = "GetProviderSet",
ValueFromPipeline = false,
ValueFromPipelineByPropertyName = false,
HelpMessageBaseName = "GetEventResources")]
[Parameter(
ParameterSetName = "GetLogSet",
ValueFromPipeline = false,
ValueFromPipelineByPropertyName = false,
HelpMessageBaseName = "GetEventResources")]
[ValidateNotNull]
public string FilterXPath { get; set; } = "*";
/// <summary>
/// FilterXml parameter.
/// </summary>
[Parameter(
Position = 0,
Mandatory = true,
ValueFromPipeline = false,
ValueFromPipelineByPropertyName = false,
ParameterSetName = "XmlQuerySet",
HelpMessageBaseName = "GetEventResources")]
[SuppressMessage("Microsoft.Design", "CA1059:MembersShouldNotExposeCertainConcreteTypes",
Scope = "member",
Target = "Microsoft.PowerShell.Commands.GetEvent.FilterXml",
Justification = "An XmlDocument is required here because that is the type Powershell supports")]
public XmlDocument FilterXml { get; set; }
/// <summary>
/// FilterHashtable parameter.
/// </summary>
[Parameter(
Position = 0,
Mandatory = true,
ValueFromPipeline = false,
ValueFromPipelineByPropertyName = false,
ParameterSetName = "HashQuerySet",
HelpMessageBaseName = "GetEventResources")]
[SuppressMessage("Microsoft.Performance", "CA1819:PropertiesShouldNotReturnArrays",
Scope = "member",
Target = "Microsoft.PowerShell.Commands.GetEvent.FilterHashtable",
Justification = "A string[] is required here because that is the type Powershell supports")]
public Hashtable[] FilterHashtable { get; set; }
/// <summary>
/// Force switch.
/// </summary>
[Parameter(ParameterSetName = "ListLogSet")]
[Parameter(ParameterSetName = "GetProviderSet")]
[Parameter(ParameterSetName = "GetLogSet")]
[Parameter(ParameterSetName = "HashQuerySet")]
public SwitchParameter Force { get; set; }
/// <summary>
/// Oldest switch.
/// </summary>
[Parameter(ParameterSetName = "FileSet")]
[Parameter(ParameterSetName = "GetProviderSet")]
[Parameter(ParameterSetName = "GetLogSet")]
[Parameter(ParameterSetName = "HashQuerySet")]
[Parameter(ParameterSetName = "XmlQuerySet")]
public SwitchParameter Oldest
{
get { return _oldest; }
set { _oldest = value; }
}
private bool _oldest = false;
//
// Query builder constant strings
//
private const string queryListOpen = "<QueryList>";
private const string queryListClose = "</QueryList>";
private const string queryTemplate = "<Query Id=\"{0}\" Path=\"{1}\"><Select Path=\"{1}\">{2}</Select></Query>";
private const string queryOpenerTemplate = "<Query Id=\"{0}\" Path=\"{1}\"><Select Path=\"{1}\">*";
private const string queryCloser = "</Query>";
private const string SelectCloser = "</Select>";
private const string suppressOpener = "<Suppress>*";
private const string suppressCloser = "</Suppress>";
private const char propOpen = '[';
private const char propClose = ']';
private const string filePrefix = "file://";
private const string NamedDataTemplate = "((EventData[Data[@Name='{0}']='{1}']) or (UserData/*/{0}='{1}'))";
private const string DataTemplate = "(EventData/Data='{0}')";
private const string SystemTimePeriodTemplate = "(System/TimeCreated[@SystemTime&gt;='{0}' and @SystemTime&lt;='{1}'])";
private const string SystemTimeStartTemplate = "(System/TimeCreated[@SystemTime&gt;='{0}'])";
private const string SystemTimeEndTemplate = "(System/TimeCreated[@SystemTime&lt;='{0}'])";
private const string SystemLevelTemplate = "(System/Level=";
private const string SystemEventIDTemplate = "(System/EventID=";
private const string SystemSecurityTemplate = "(System/Security[@UserID='{0}'])";
private const string SystemKeywordsTemplate = "System[band(Keywords,{0})]";
//
// Other private members and constants
//
private ResourceManager _resourceMgr = null;
private readonly Dictionary<string, StringCollection> _providersByLogMap = new();
private StringCollection _logNamesMatchingWildcard = null;
private readonly StringCollection _resolvedPaths = new();
private readonly List<string> _accumulatedLogNames = new();
private readonly List<string> _accumulatedProviderNames = new();
private readonly List<string> _accumulatedFileNames = new();
private const uint MAX_EVENT_BATCH = 100;
//
// Hashtable query key names
//
private const string hashkey_logname_lc = "logname";
private const string hashkey_providername_lc = "providername";
private const string hashkey_path_lc = "path";
private const string hashkey_keywords_lc = "keywords";
private const string hashkey_id_lc = "id";
private const string hashkey_level_lc = "level";
private const string hashkey_starttime_lc = "starttime";
private const string hashkey_endtime_lc = "endtime";
private const string hashkey_userid_lc = "userid";
private const string hashkey_data_lc = "data";
private const string hashkey_supress_lc = "suppresshashfilter";
/// <summary>
/// BeginProcessing() is invoked once per pipeline: we will load System.Core.dll here.
/// </summary>
protected override void BeginProcessing()
{
_resourceMgr = Microsoft.PowerShell.Commands.Diagnostics.Common.CommonUtilities.GetResourceManager();
}
/// <summary>
/// EndProcessing() is invoked once per pipeline.
/// </summary>
protected override void EndProcessing()
{
switch (ParameterSetName)
{
case "GetLogSet":
ProcessGetLog();
break;
case "FileSet":
ProcessFile();
break;
case "GetProviderSet":
ProcessGetProvider();
break;
default:
break;
}
}
/// <summary>
/// ProcessRecord() override.
/// This is the main entry point for the cmdlet.
/// </summary>
protected override void ProcessRecord()
{
switch (ParameterSetName)
{
case "ListLogSet":
ProcessListLog();
break;
case "ListProviderSet":
ProcessListProvider();
break;
case "GetLogSet":
AccumulatePipelineLogNames();
break;
case "FileSet":
AccumulatePipelineFileNames();
break;
case "HashQuerySet":
ProcessHashQuery();
break;
case "GetProviderSet":
AccumulatePipelineProviderNames();
break;
case "XmlQuerySet":
ProcessFilterXml();
break;
default:
WriteDebug(string.Format(CultureInfo.InvariantCulture, "Invalid parameter set name: {0}", ParameterSetName));
break;
}
}
//
// AccumulatePipelineCounters() accumulates log names in the pipeline scenario:
// we do not want to construct a query until all the log names are supplied.
//
private void AccumulatePipelineLogNames()
{
_accumulatedLogNames.AddRange(LogName);
}
//
// AccumulatePipelineProviderNames() accumulates provider names in the pipeline scenario:
// we do not want to construct a query until all the provider names are supplied.
//
private void AccumulatePipelineProviderNames()
{
_accumulatedProviderNames.AddRange(LogName);
}
//
// AccumulatePipelineFileNames() accumulates log file paths in the pipeline scenario:
// we do not want to construct a query until all the file names are supplied.
//
private void AccumulatePipelineFileNames()
{
_accumulatedFileNames.AddRange(LogName);
}
//
// Process GetLog parameter set
//
private void ProcessGetLog()
{
using (EventLogSession eventLogSession = CreateSession())
{
FindLogNamesMatchingWildcards(eventLogSession, _accumulatedLogNames);
if (_logNamesMatchingWildcard.Count == 0)
{
return;
}
EventLogQuery logQuery;
if (_logNamesMatchingWildcard.Count > 1)
{
string query = BuildStructuredQuery(eventLogSession);
logQuery = new EventLogQuery(null, PathType.LogName, query);
logQuery.TolerateQueryErrors = true;
}
else
{
logQuery = new EventLogQuery(_logNamesMatchingWildcard[0], PathType.LogName, FilterXPath);
}
logQuery.Session = eventLogSession;
logQuery.ReverseDirection = !_oldest;
ReadEvents(logQuery);
}
}
//
// Process GetProviderSet parameter set
//
private void ProcessGetProvider()
{
using (EventLogSession eventLogSession = CreateSession())
{
FindProvidersByLogForWildcardPatterns(eventLogSession, ProviderName);
if (_providersByLogMap.Count == 0)
{
//
// Just return: errors already written above for each unmatched provider name pattern.
//
return;
}
EventLogQuery logQuery = null;
if (_providersByLogMap.Count > 1)
{
string query = BuildStructuredQuery(eventLogSession);
logQuery = new EventLogQuery(null, PathType.LogName, query);
logQuery.TolerateQueryErrors = true;
}
else
{
//
// There's only one key at this point, but we need an enumerator to get to it.
//
foreach (string log in _providersByLogMap.Keys)
{
logQuery = new EventLogQuery(log, PathType.LogName, AddProviderPredicatesToFilter(_providersByLogMap[log]));
WriteVerbose(string.Format(CultureInfo.InvariantCulture, "Log {0} will be queried", log));
}
}
logQuery.Session = eventLogSession;
logQuery.ReverseDirection = !_oldest;
ReadEvents(logQuery);
}
}
//
// Process ListLog parameter set
//
private void ProcessListLog()
{
using (EventLogSession eventLogSession = CreateSession())
{
foreach (string logPattern in ListLog)
{
bool bMatchFound = false;
WildcardPattern wildLogPattern = new(logPattern, WildcardOptions.IgnoreCase);
foreach (string logName in eventLogSession.GetLogNames())
{
if (((!WildcardPattern.ContainsWildcardCharacters(logPattern))
&& string.Equals(logPattern, logName, StringComparison.OrdinalIgnoreCase))
||
(wildLogPattern.IsMatch(logName)))
{
try
{
EventLogConfiguration logObj = new(logName, eventLogSession);
//
// Skip direct channels matching the wildcard unless -Force is present.
//
if (!Force.IsPresent &&
WildcardPattern.ContainsWildcardCharacters(logPattern) &&
(logObj.LogType == EventLogType.Debug ||
logObj.LogType == EventLogType.Analytical))
{
continue;
}
EventLogInformation logInfoObj = eventLogSession.GetLogInformation(logName, PathType.LogName);
PSObject outputObj = new(logObj);
outputObj.Properties.Add(new PSNoteProperty("FileSize", logInfoObj.FileSize));
outputObj.Properties.Add(new PSNoteProperty("IsLogFull", logInfoObj.IsLogFull));
outputObj.Properties.Add(new PSNoteProperty("LastAccessTime", logInfoObj.LastAccessTime));
outputObj.Properties.Add(new PSNoteProperty("LastWriteTime", logInfoObj.LastWriteTime));
outputObj.Properties.Add(new PSNoteProperty("OldestRecordNumber", logInfoObj.OldestRecordNumber));
outputObj.Properties.Add(new PSNoteProperty("RecordCount", logInfoObj.RecordCount));
WriteObject(outputObj);
bMatchFound = true;
}
catch (Exception exc)
{
string msg = string.Format(CultureInfo.InvariantCulture,
_resourceMgr.GetString("LogInfoUnavailable"),
logName, exc.Message);
Exception outerExc = new(msg, exc);
WriteError(new ErrorRecord(outerExc, "LogInfoUnavailable", ErrorCategory.NotSpecified, null));
continue;
}
}
}
if (!bMatchFound)
{
string msg = _resourceMgr.GetString("NoMatchingLogsFound");
Exception exc = new(string.Format(CultureInfo.InvariantCulture, msg, ComputerName, logPattern));
WriteError(new ErrorRecord(exc, "NoMatchingLogsFound", ErrorCategory.ObjectNotFound, null));
}
}
}
}
//
// Process ListProvider parameter set
//
private void ProcessListProvider()
{
using (EventLogSession eventLogSession = CreateSession())
{
foreach (string provPattern in ListProvider)
{
bool bMatchFound = false;
WildcardPattern wildProvPattern = new(provPattern, WildcardOptions.IgnoreCase);
foreach (string provName in eventLogSession.GetProviderNames())
{
if (((!WildcardPattern.ContainsWildcardCharacters(provPattern))
&& string.Equals(provPattern, provName, StringComparison.OrdinalIgnoreCase))
||
(wildProvPattern.IsMatch(provName)))
{
try
{
ProviderMetadata provObj = new(provName, eventLogSession, CultureInfo.CurrentCulture);
WriteObject(provObj);
bMatchFound = true;
}
catch (System.Diagnostics.Eventing.Reader.EventLogException exc)
{
string msg = string.Format(CultureInfo.InvariantCulture,
_resourceMgr.GetString("ProviderMetadataUnavailable"),
provName, exc.Message);
Exception outerExc = new(msg, exc);
WriteError(new ErrorRecord(outerExc, "ProviderMetadataUnavailable", ErrorCategory.NotSpecified, null));
continue;
}
}
}
if (!bMatchFound)
{
string msg = string.Format(CultureInfo.InvariantCulture, _resourceMgr.GetString("NoMatchingProvidersFound"),
ComputerName, provPattern);
Exception exc = new(msg);
WriteError(new ErrorRecord(exc, "NoMatchingProvidersFound", ErrorCategory.ObjectNotFound, null));
}
}
}
}
//
// Process FilterXml parameter set
//
private void ProcessFilterXml()
{
using (EventLogSession eventLogSession = CreateSession())
{
if (!Oldest.IsPresent)
{
//
// Do minimal parsing of xmlQuery to determine if any direct channels or ETL files are in it.
//
XmlElement root = FilterXml.DocumentElement;
XmlNodeList queryNodes = root.SelectNodes("//Query//Select");
foreach (XmlNode queryNode in queryNodes)
{
XmlAttributeCollection attribs = queryNode.Attributes;
foreach (XmlAttribute attrib in attribs)
{
if (attrib.Name.Equals("Path", StringComparison.OrdinalIgnoreCase))
{
string logName = attrib.Value;
if (logName.StartsWith(filePrefix, StringComparison.OrdinalIgnoreCase))
{
TerminateForNonEvtxFileWithoutOldest(logName);
}
ValidateLogName(logName, eventLogSession);
}
}
}
}
EventLogQuery logQuery = new(null, PathType.LogName, FilterXml.InnerXml);
logQuery.Session = eventLogSession;
logQuery.ReverseDirection = !_oldest;
ReadEvents(logQuery);
}
}
//
// Process FileSet parameter set
//
private void ProcessFile()
{
using (EventLogSession eventLogSession = CreateSession())
{
//
// At this point, _path array contains paths that might have wildcards,
// environment variables or PS drives. Let's resolve those.
//
for (int i = 0; i < Path.Length; i++)
{
StringCollection resolvedPaths = ValidateAndResolveFilePath(Path[i]);
foreach (string resolvedPath in resolvedPaths)
{
_resolvedPaths.Add(resolvedPath);
WriteVerbose(string.Format(CultureInfo.InvariantCulture, "Found file {0}", resolvedPath));
}
}
EventLogQuery logQuery = null;
if (_resolvedPaths.Count == 0)
{
return;
}
else if (_resolvedPaths.Count > 1)
{
string query = BuildStructuredQuery(eventLogSession);
logQuery = new EventLogQuery(null, PathType.FilePath, query);
logQuery.TolerateQueryErrors = true;
}
else
{
logQuery = new EventLogQuery(_resolvedPaths[0], PathType.FilePath, FilterXPath);
}
logQuery.Session = eventLogSession;
logQuery.ReverseDirection = !_oldest;
ReadEvents(logQuery);
}
}
//
// Process HashQuerySet parameter set
//
private void ProcessHashQuery()
{
CheckHashTablesForNullValues();
using (EventLogSession eventLogSession = CreateSession())
{
string query = BuildStructuredQuery(eventLogSession);
if (query.Length == 0)
{
return;
}
EventLogQuery logQuery = new(null, PathType.FilePath, query);
logQuery.Session = eventLogSession;
logQuery.TolerateQueryErrors = true;
logQuery.ReverseDirection = !_oldest;
ReadEvents(logQuery);
}
}
//
// CreateSession creates an EventLogSession connected to a target machine or localhost.
// If _credential argument is PSCredential.Empty, the session will be created for the current context.
//
private EventLogSession CreateSession()
{
EventLogSession eventLogSession = null;
if (ComputerName == string.Empty)
{
// Set _computerName to "localhost" for future error messages,
// but do not use it for the connection to avoid RPC overhead.
ComputerName = "localhost";
if (Credential == PSCredential.Empty)
{
return new EventLogSession();
}
}
else if (Credential == PSCredential.Empty)
{
return new EventLogSession(ComputerName);
}
// If we are here, either both computer name and credential were passed initially,
// or credential only - we will use it with "localhost"
NetworkCredential netCred = (NetworkCredential)Credential;
eventLogSession = new EventLogSession(ComputerName,
netCred.Domain,
netCred.UserName,
Credential.Password,
SessionAuthentication.Default
);
//
// Force the destruction of cached password
//
netCred.Password = string.Empty;
return eventLogSession;
}
//
// ReadEvents helper.
//
private void ReadEvents(EventLogQuery logQuery)
{
using (EventLogReader readerObj = new(logQuery))
{
long numEvents = 0;
EventRecord evtObj = null;
while (true)
{
try
{
evtObj = readerObj.ReadEvent();
}
catch (Exception exc)
{
WriteError(new ErrorRecord(exc, exc.Message, ErrorCategory.NotSpecified, null));
continue;
}
if (evtObj == null)
{
break;
}
if (MaxEvents != -1 && numEvents >= MaxEvents)
{
break;
}
PSObject outputObj = new(evtObj);
string evtMessage = _resourceMgr.GetString("NoEventMessage");
try
{
evtMessage = evtObj.FormatDescription();
}
catch (Exception exc)
{
WriteError(new ErrorRecord(exc, exc.Message, ErrorCategory.NotSpecified, null));
}
outputObj.Properties.Add(new PSNoteProperty("Message", evtMessage));
//
// Enumerate the object one level to get to event payload
//
WriteObject(outputObj, true);
numEvents++;
}
if (numEvents == 0)
{
string msg = _resourceMgr.GetString("NoMatchingEventsFound");
Exception exc = new(msg);
WriteError(new ErrorRecord(exc, "NoMatchingEventsFound", ErrorCategory.ObjectNotFound, null));
}
}
}
//
// BuildStructuredQuery() builds a structured query from cmdlet arguments.
//
private string BuildStructuredQuery(EventLogSession eventLogSession)
{
StringBuilder result = new();
switch (ParameterSetName)
{
case "ListLogSet":
break;
case "ListProviderSet":
break;
case "GetProviderSet":
{
result.Append(queryListOpen);
uint queryId = 0;
foreach (string log in _providersByLogMap.Keys)
{
string providerFilter = AddProviderPredicatesToFilter(_providersByLogMap[log]);
result.AppendFormat(CultureInfo.InvariantCulture, queryTemplate, new object[] { queryId++, log, providerFilter });
}
result.Append(queryListClose);
}
break;
case "GetLogSet":
{
const int WindowsEventLogAPILimit = 256;
if (_logNamesMatchingWildcard.Count > WindowsEventLogAPILimit)
{
string msg = _resourceMgr.GetString("LogCountLimitExceeded");
Exception exc = new(string.Format(CultureInfo.InvariantCulture, msg, _logNamesMatchingWildcard.Count, WindowsEventLogAPILimit));
ThrowTerminatingError(new ErrorRecord(exc, "LogCountLimitExceeded", ErrorCategory.LimitsExceeded, null));
}
result.Append(queryListOpen);
uint queryId = 0;
foreach (string log in _logNamesMatchingWildcard)
{
result.AppendFormat(CultureInfo.InvariantCulture, queryTemplate, new object[] { queryId++, log, FilterXPath });
}
result.Append(queryListClose);
}
break;
case "FileSet":
{
result.Append(queryListOpen);
uint queryId = 0;
foreach (string filePath in _resolvedPaths)
{
string properFilePath = filePrefix + filePath;
result.AppendFormat(CultureInfo.InvariantCulture, queryTemplate, new object[] { queryId++, properFilePath, FilterXPath });
}
result.Append(queryListClose);
}
break;
case "HashQuerySet":
result.Append(BuildStructuredQueryFromHashTable(eventLogSession));
break;
default:
WriteDebug(string.Format(CultureInfo.InvariantCulture, "Invalid parameter set name: {0}", ParameterSetName));
break;
}
WriteVerbose(string.Format(CultureInfo.InvariantCulture, _resourceMgr.GetString("QueryTrace"), result.ToString()));
return result.ToString();
}
//
// BuildXPathFromHashTable() build xpath from hashtable
//
private string BuildXPathFromHashTable(Hashtable hash)
{
StringBuilder xpathString = new(string.Empty);
bool bDateTimeHandled = false;
foreach (string key in hash.Keys)
{
string added = string.Empty;
switch (key.ToLowerInvariant())
{
case hashkey_logname_lc:
case hashkey_path_lc:
case hashkey_providername_lc:
break;
case hashkey_id_lc:
added = HandleEventIdHashValue(hash[key]);
break;
case hashkey_level_lc:
added = HandleLevelHashValue(hash[key]);
break;
case hashkey_keywords_lc:
added = HandleKeywordHashValue(hash[key]);
break;
case hashkey_starttime_lc:
if (bDateTimeHandled)
{
break;
}
added = HandleStartTimeHashValue(hash[key], hash);
bDateTimeHandled = true;
break;
case hashkey_endtime_lc:
if (bDateTimeHandled)
{
break;
}
added = HandleEndTimeHashValue(hash[key], hash);
bDateTimeHandled = true;
break;
case hashkey_data_lc:
added = HandleDataHashValue(hash[key]);
break;
case hashkey_userid_lc:
added = HandleContextHashValue(hash[key]);
break;
case hashkey_supress_lc:
break;
default:
{
//
// None of the recognized values: this must be a named event data field
//
// Fix Issue #2327
added = HandleNamedDataHashValue(key, hash[key]);
}
break;
}
if (added.Length > 0)
{
if (xpathString.Length != 0)
{
xpathString.Append(" and ");
}
xpathString.Append(added);
}
}
return xpathString.ToString();
}
//
// BuildStructuredQueryFromHashTable() helper.
// Builds a structured query from the hashtable (Selector) argument.
//
private string BuildStructuredQueryFromHashTable(EventLogSession eventLogSession)
{
StringBuilder result = new(string.Empty);
result.Append(queryListOpen);
uint queryId = 0;
foreach (Hashtable hash in FilterHashtable)
{
string xpathString = string.Empty;
string xpathStringSuppress = string.Empty;
CheckHashTableForQueryPathPresence(hash);
//
// Local queriedLogsQueryMap will hold names of logs or files to be queried
// mapped to the actual query strings being built up.
//
Dictionary<string, string> queriedLogsQueryMap = new();
//
// queriedLogsQueryMapSuppress is the same as queriedLogsQueryMap but for <Suppress>
//
Dictionary<string, string> queriedLogsQueryMapSuppress = new();
//
// Process log, _path, or provider parameters first
// to create initial partially-filled query templates.
// Error out for direct channels unless -oldest is present.
//
// Order is important! Process "providername" key after "logname" and "file".
//
if (hash.ContainsKey(hashkey_logname_lc))
{
List<string> logPatterns = new();
if (hash[hashkey_logname_lc] is Array)
{
foreach (object elt in (Array)hash[hashkey_logname_lc])
{
logPatterns.Add(elt.ToString());
}
}
else
{
logPatterns.Add(hash[hashkey_logname_lc].ToString());
}
FindLogNamesMatchingWildcards(eventLogSession, logPatterns);
foreach (string logName in _logNamesMatchingWildcard)
{
queriedLogsQueryMap.Add(logName.ToLowerInvariant(),
string.Format(CultureInfo.InvariantCulture, queryOpenerTemplate, queryId++, logName));
queriedLogsQueryMapSuppress.Add(logName.ToLowerInvariant(),
string.Format(CultureInfo.InvariantCulture, suppressOpener, queryId++, logName));
}
}
if (hash.ContainsKey(hashkey_path_lc))
{
if (hash[hashkey_path_lc] is Array)
{
foreach (object elt in (Array)hash[hashkey_path_lc])
{
StringCollection resolvedPaths = ValidateAndResolveFilePath(elt.ToString());
foreach (string resolvedPath in resolvedPaths)
{
queriedLogsQueryMap.Add(filePrefix + resolvedPath.ToLowerInvariant(),
string.Format(CultureInfo.InvariantCulture, queryOpenerTemplate, queryId++, filePrefix + resolvedPath));
queriedLogsQueryMapSuppress.Add(filePrefix + resolvedPath.ToLowerInvariant(),
string.Format(CultureInfo.InvariantCulture, suppressOpener, queryId++, filePrefix + resolvedPath));
}
}
}
else
{
StringCollection resolvedPaths = ValidateAndResolveFilePath(hash[hashkey_path_lc].ToString());
foreach (string resolvedPath in resolvedPaths)
{
queriedLogsQueryMap.Add(filePrefix + resolvedPath.ToLowerInvariant(),
string.Format(CultureInfo.InvariantCulture, queryOpenerTemplate, queryId++, filePrefix + resolvedPath));
queriedLogsQueryMapSuppress.Add(filePrefix + resolvedPath.ToLowerInvariant(),
string.Format(CultureInfo.InvariantCulture, suppressOpener, queryId++, filePrefix + resolvedPath));
}
}
}
if (hash.ContainsKey(hashkey_providername_lc))
{
List<string> provPatterns = new();
if (hash[hashkey_providername_lc] is Array)
{
foreach (object elt in (Array)hash[hashkey_providername_lc])
{
provPatterns.Add(elt.ToString());
}
}
else
{
provPatterns.Add(hash[hashkey_providername_lc].ToString());
}
FindProvidersByLogForWildcardPatterns(eventLogSession, provPatterns);
//
// If "providername" key is used alone, we will construct a query across all of the providers' logs.
// Otherwise, we will use the provider names to add predicates to "logname" and "path" queries.
//
if (!hash.ContainsKey(hashkey_path_lc) && !hash.ContainsKey(hashkey_logname_lc))
{
foreach (string keyLogName in _providersByLogMap.Keys)
{
string providersPredicate = BuildProvidersPredicate(_providersByLogMap[keyLogName]);
string query = string.Format(CultureInfo.InvariantCulture, queryOpenerTemplate, queryId++, keyLogName);
queriedLogsQueryMap.Add(keyLogName.ToLowerInvariant(),
query + "[" + providersPredicate);
queriedLogsQueryMapSuppress.Add(keyLogName.ToLowerInvariant(),
string.Format(CultureInfo.InvariantCulture, suppressOpener, queryId++, keyLogName.ToLowerInvariant()));
}
}
else
{
List<string> keysList = new(queriedLogsQueryMap.Keys);
bool bRemovedIrrelevantLogs = false;
foreach (string queriedLog in keysList)
{
if (queriedLog.StartsWith(filePrefix, StringComparison.Ordinal))
{
queriedLogsQueryMap[queriedLog] += "[" + BuildAllProvidersPredicate();
}
else
{
if (_providersByLogMap.ContainsKey(queriedLog))
{
string providersPredicate = BuildProvidersPredicate(_providersByLogMap[queriedLog]);
queriedLogsQueryMap[queriedLog] += "[" + providersPredicate;
}
else
{
WriteVerbose(string.Format(CultureInfo.InvariantCulture, _resourceMgr.GetString("SpecifiedProvidersDontWriteToLog"), queriedLog));
queriedLogsQueryMap.Remove(queriedLog);
queriedLogsQueryMapSuppress.Remove(queriedLog);
bRemovedIrrelevantLogs = true;
}
}
}
//
// Write an error if we have removed all the logs as irrelevant
//
if (bRemovedIrrelevantLogs && (queriedLogsQueryMap.Count == 0))
{
string msg = string.Format(CultureInfo.InvariantCulture, _resourceMgr.GetString("LogsAndProvidersDontOverlap"));
Exception exc = new(msg);
WriteError(new ErrorRecord(exc, "LogsAndProvidersDontOverlap", ErrorCategory.InvalidArgument, null));
continue;
}
}
}
//
// If none of the logs/paths/providers were valid, queriedLogsQueryMap is empty.
// Simply continue to the next hashtable since all the errors have been written already.
//
if (queriedLogsQueryMap.Count == 0)
{
continue;
}
//
// At this point queriedLogsQueryMap contains all the query openings: missing the actual XPaths
// Let's build xpathString to attach to each query opening.
//
xpathString = BuildXPathFromHashTable(hash);
//
// Build xpath for <Suppress>
//
Hashtable suppresshash = hash[hashkey_supress_lc] as Hashtable;
if (suppresshash != null)
{
xpathStringSuppress = BuildXPathFromHashTable(suppresshash);
}
//
// Complete each query with the XPath.
// Handle the case where the query opener already has provider predicate(s).
// Add the queries from queriedLogsQueryMap into the resulting string.
// Add <Suppress> from queriedLogsQueryMapSuppress into the resulting string.
//
foreach (string keyLogName in queriedLogsQueryMap.Keys)
{
// For every Log a separate query is
string query = queriedLogsQueryMap[keyLogName];
result.Append(query);
if (query.EndsWith('*'))
{
//
// No provider predicate: just add the XPath string
//
if (xpathString.Length != 0)
{
result.Append(propOpen).Append(xpathString).Append(propClose);
}
}
else
{
//
// Add xpathString to provider predicates.
//
if (xpathString.Length != 0)
{
result.Append(" and ").Append(xpathString);
}
result.Append(propClose);
}
result.Append(SelectCloser);
if (xpathStringSuppress.Length != 0)
{
// Add <Suppress>*xpathStringSuppress</Suppress> into query
string suppress = queriedLogsQueryMapSuppress[keyLogName];
result.Append(suppress);
result.Append(propOpen).Append(xpathStringSuppress).Append(propClose);
result.Append(suppressCloser);
}
result.Append(queryCloser);
}
}
result.Append(queryListClose);
return result.ToString();
}
//
// HandleEventIdHashValue helper for hashtable structured query builder.
// Constructs and returns EventId XPath portion as a string.
//
private static string HandleEventIdHashValue(object value)
{
StringBuilder ret = new();
Array idsArray = value as Array;
if (idsArray != null)
{
ret.Append('(');
for (int i = 0; i < idsArray.Length; i++)
{
ret.Append(SystemEventIDTemplate).Append(idsArray.GetValue(i).ToString()).Append(')');
if (i < (idsArray.Length - 1))
{
ret.Append(" or ");
}
}
ret.Append(')');
}
else
{
ret.Append(SystemEventIDTemplate).Append(value).Append(')');
}
return ret.ToString();
}
//
// HandleLevelHashValue helper for hashtable structured query builder.
// Constructs and returns Level XPath portion as a string.
//
private static string HandleLevelHashValue(object value)
{
StringBuilder ret = new();
Array levelsArray = value as Array;
if (levelsArray != null)
{
ret.Append('(');
for (int i = 0; i < levelsArray.Length; i++)
{
ret.Append(SystemLevelTemplate).Append(levelsArray.GetValue(i).ToString()).Append(')');
if (i < (levelsArray.Length - 1))
{
ret.Append(" or ");
}
}
ret.Append(')');
}
else
{
ret.Append(SystemLevelTemplate).Append(value).Append(')');
}
return ret.ToString();
}
//
// HandleKeywordHashValue helper for hashtable structured query builder.
// Constructs and returns Keyword XPath portion as a string.
//
private string HandleKeywordHashValue(object value)
{
long keywordsMask = 0;
long keywordLong = 0;
Array keywordArray = value as Array;
if (keywordArray != null)
{
foreach (object keyword in keywordArray)
{
if (KeywordStringToInt64(keyword.ToString(), ref keywordLong))
{
keywordsMask |= keywordLong;
}
}
}
else
{
if (!KeywordStringToInt64(value.ToString(), ref keywordLong))
{
return string.Empty;
}
keywordsMask |= keywordLong;
}
return string.Format(CultureInfo.InvariantCulture, SystemKeywordsTemplate, keywordsMask);
}
//
// HandleContextHashValue helper for hashtable structured query builder.
// Constructs and returns UserID XPath portion as a string.
// Handles both SIDs and domain account names.
// Writes an error and returns an empty string if the SID or account names are not valid.
//
private string HandleContextHashValue(object value)
{
SecurityIdentifier sidCandidate = null;
try
{
sidCandidate = new SecurityIdentifier(value.ToString());
}
catch (ArgumentException)
{
WriteDebug(string.Format(CultureInfo.InvariantCulture, _resourceMgr.GetString("InvalidSIDFormat"), value));
}
if (sidCandidate == null)
{
try
{
NTAccount acct = new(value.ToString());
sidCandidate = (SecurityIdentifier)acct.Translate(typeof(SecurityIdentifier));
}
catch (ArgumentException exc)
{
string msg = string.Format(CultureInfo.InvariantCulture, _resourceMgr.GetString("InvalidContext"), value.ToString());
Exception outerExc = new(msg, exc);
WriteError(new ErrorRecord(outerExc, "InvalidContext", ErrorCategory.InvalidArgument, null));
return string.Empty;
}
}
return string.Format(CultureInfo.InvariantCulture, SystemSecurityTemplate, sidCandidate.ToString());
}
//
// HandleStartTimeHashValue helper for hashtable structured query builder.
// Constructs and returns TimeCreated XPath portion as a string.
// NOTE that it also handles the hashtable "endtime" value (if supplied).
//
private string HandleStartTimeHashValue(object value, Hashtable hash)
{
StringBuilder ret = new();
DateTime startTime = new();
if (!StringToDateTime(value.ToString(), ref startTime))
{
return string.Empty;
}
startTime = startTime.ToUniversalTime();
string startTimeFormatted = startTime.ToString("s", CultureInfo.InvariantCulture) + "." + startTime.Millisecond.ToString("d3", CultureInfo.InvariantCulture) + "Z";
if (hash.ContainsKey(hashkey_endtime_lc))
{
DateTime endTime = new();
if (!StringToDateTime(hash[hashkey_endtime_lc].ToString(), ref endTime))
{
return string.Empty;
}
endTime = endTime.ToUniversalTime();
string endTimeFormatted = endTime.ToString("s", CultureInfo.InvariantCulture) + "." + endTime.Millisecond.ToString("d3", CultureInfo.InvariantCulture) + "Z";
ret.AppendFormat(CultureInfo.InvariantCulture,
SystemTimePeriodTemplate,
startTimeFormatted,
endTimeFormatted);
}
else
{
ret.AppendFormat(CultureInfo.InvariantCulture,
SystemTimeStartTemplate,
startTimeFormatted);
}
return ret.ToString();
}
//
// HandleEndTimeHashValue helper for hashtable structured query builder.
// Constructs and returns TimeCreated XPath portion as a string.
// NOTE that it also handles the hashtable "starttime" value (if supplied).
//
private string HandleEndTimeHashValue(object value, Hashtable hash)
{
StringBuilder ret = new();
DateTime endTime = new();
if (!StringToDateTime(value.ToString(), ref endTime))
{
return string.Empty;
}
endTime = endTime.ToUniversalTime();
string endTimeFormatted = endTime.ToString("s", CultureInfo.InvariantCulture) + "."
+ endTime.Millisecond.ToString("d3", CultureInfo.InvariantCulture) + "Z";
if (hash.ContainsKey(hashkey_starttime_lc))
{
DateTime startTime = new();
if (!StringToDateTime(hash[hashkey_starttime_lc].ToString(), ref startTime))
{
return string.Empty;
}
startTime = startTime.ToUniversalTime();
string startTimeFormatted = startTime.ToString("s", CultureInfo.InvariantCulture) + "."
+ startTime.Millisecond.ToString("d3", CultureInfo.InvariantCulture) + "Z";
ret.AppendFormat(CultureInfo.InvariantCulture,
SystemTimePeriodTemplate,
startTimeFormatted,
endTimeFormatted);
}
else
{
ret.AppendFormat(CultureInfo.InvariantCulture,
SystemTimeEndTemplate,
endTimeFormatted);
}
return ret.ToString();
}
//
// HandleDataHashValue helper for hashtable structured query builder.
// Constructs and returns EventData/Data XPath portion as a string.
//
private static string HandleDataHashValue(object value)
{
StringBuilder ret = new();
Array dataArray = value as Array;
if (dataArray != null)
{
ret.Append('(');
for (int i = 0; i < dataArray.Length; i++)
{
ret.AppendFormat(CultureInfo.InvariantCulture, DataTemplate, dataArray.GetValue(i).ToString());
if (i < (dataArray.Length - 1))
{
ret.Append(" or ");
}
}
ret.Append(')');
}
else
{
ret.AppendFormat(CultureInfo.InvariantCulture, DataTemplate, value);
}
return ret.ToString();
}
//
// HandleNamedDataHashValue helper for hashtable structured query builder.
// Constructs and returns named event data field XPath portion as a string.
// Fix Issue #2327
//
private static string HandleNamedDataHashValue(string key, object value)
{
StringBuilder ret = new();
Array dataArray = value as Array;
if (dataArray != null)
{
ret.Append('(');
for (int i = 0; i < dataArray.Length; i++)
{
ret.AppendFormat(CultureInfo.InvariantCulture,
NamedDataTemplate,
key, dataArray.GetValue(i).ToString());
if (i < (dataArray.Length - 1))
{
ret.Append(" or ");
}
}
ret.Append(')');
}
else
{
ret.AppendFormat(CultureInfo.InvariantCulture,
NamedDataTemplate,
key, value);
}
return ret.ToString();
}
//
// Helper checking whether at least one of log, _path, provider is specified.
// It will ThrowTerminatingError in case none of those keys are present.
//
private void CheckHashTableForQueryPathPresence(Hashtable hash)
{
bool isLogHash = (hash.ContainsKey(hashkey_logname_lc));
bool isPathHash = (hash.ContainsKey(hashkey_path_lc));
bool isProviderHash = (hash.ContainsKey(hashkey_providername_lc));
if (!isLogHash && !isProviderHash && !isPathHash)
{
string msg = _resourceMgr.GetString("LogProviderOrPathNeeded");
Exception exc = new(msg);
ThrowTerminatingError(new ErrorRecord(exc, "LogProviderOrPathNeeded", ErrorCategory.InvalidArgument, null));
}
}
//
// TerminateForNonEvtxFileWithoutOldest terminates for .evt and .etl files unless -Oldest is specified.
//
private void TerminateForNonEvtxFileWithoutOldest(string fileName)
{
if (!Oldest.IsPresent)
{
if (System.IO.Path.GetExtension(fileName).Equals(".etl", StringComparison.OrdinalIgnoreCase) ||
System.IO.Path.GetExtension(fileName).Equals(".evt", StringComparison.OrdinalIgnoreCase))
{
string msg = _resourceMgr.GetString("SpecifyOldestForEtlEvt");
Exception exc = new(string.Format(CultureInfo.InvariantCulture, msg, fileName));
ThrowTerminatingError(new ErrorRecord(exc, "SpecifyOldestForEtlEvt", ErrorCategory.InvalidArgument, fileName));
}
}
}
//
// ValidateLogName writes an error if logName is not a valid log.
// It also terminates for direct ETW channels unless -Oldest is specified.
//
private bool ValidateLogName(string logName, EventLogSession eventLogSession)
{
EventLogConfiguration logObj;
try
{
logObj = new EventLogConfiguration(logName, eventLogSession);
}
catch (EventLogNotFoundException)
{
string msg = _resourceMgr.GetString("NoMatchingLogsFound");
Exception exc = new(string.Format(CultureInfo.InvariantCulture, msg, ComputerName, logName));
WriteError(new ErrorRecord(exc, "NoMatchingLogsFound", ErrorCategory.ObjectNotFound, logName));
return false;
}
catch (Exception exc)
{
string msg = string.Format(CultureInfo.InvariantCulture,
_resourceMgr.GetString("LogInfoUnavailable"),
logName, exc.Message);
Exception outerExc = new(msg, exc);
WriteError(new ErrorRecord(outerExc, "LogInfoUnavailable", ErrorCategory.NotSpecified, null));
return false;
}
if (!Oldest.IsPresent)
{
if (logObj.LogType == EventLogType.Debug || logObj.LogType == EventLogType.Analytical)
{
string msg = _resourceMgr.GetString("SpecifyOldestForLog");
Exception exc = new(string.Format(CultureInfo.InvariantCulture, msg, logName));
ThrowTerminatingError(new ErrorRecord(exc, "SpecifyOldestForLog", ErrorCategory.InvalidArgument, logName));
}
}
return true;
}
//
// KeywordStringToInt64 helper converts a string to Int64.
// Returns true and keyLong ref if successful.
// Writes an error and returns false if keyString cannot be converted.
//
private bool KeywordStringToInt64(string keyString, ref long keyLong)
{
try
{
keyLong = Convert.ToInt64(keyString, CultureInfo.InvariantCulture);
}
catch (Exception exc)
{
string msg = _resourceMgr.GetString("KeywordLongExpected");
Exception outerExc = new(string.Format(CultureInfo.InvariantCulture, msg, keyString), exc);
WriteError(new ErrorRecord(outerExc, "KeywordLongExpected", ErrorCategory.InvalidArgument, null));
return false;
}
return true;
}
//
// StringToDateTime helper converts a string to DateTime object.
// Returns true and DateTime ref if successful.
// Writes an error and returns false if dtString cannot be converted.
//
private bool StringToDateTime(string dtString, ref DateTime dt)
{
try
{
dt = DateTime.Parse(dtString, CultureInfo.CurrentCulture);
}
catch (FormatException exc)
{
string msg = _resourceMgr.GetString("DateTimeExpected");
Exception outerExc = new(string.Format(CultureInfo.InvariantCulture, msg, dtString), exc);
WriteError(new ErrorRecord(outerExc, "DateTimeExpected", ErrorCategory.InvalidArgument, null));
return false;
}
return true;
}
//
// ValidateAndResolveFilePath helper.
// Returns a string collection of resolved file paths.
// Writes non-terminating errors for invalid paths
// and returns an empty collection.
//
private StringCollection ValidateAndResolveFilePath(string path)
{
StringCollection retColl = new();
Collection<PathInfo> resolvedPathSubset = null;
try
{
resolvedPathSubset = SessionState.Path.GetResolvedPSPathFromPSPath(path);
}
catch (PSNotSupportedException notSupported)
{
WriteError(new ErrorRecord(notSupported, string.Empty, ErrorCategory.ObjectNotFound, path));
return retColl;
}
catch (System.Management.Automation.DriveNotFoundException driveNotFound)
{
WriteError(new ErrorRecord(driveNotFound, string.Empty, ErrorCategory.ObjectNotFound, path));
return retColl;
}
catch (ProviderNotFoundException providerNotFound)
{
WriteError(new ErrorRecord(providerNotFound, string.Empty, ErrorCategory.ObjectNotFound, path));
return retColl;
}
catch (ItemNotFoundException pathNotFound)
{
WriteError(new ErrorRecord(pathNotFound, string.Empty, ErrorCategory.ObjectNotFound, path));
return retColl;
}
catch (Exception exc)
{
WriteError(new ErrorRecord(exc, string.Empty, ErrorCategory.ObjectNotFound, path));
return retColl;
}
foreach (PathInfo pi in resolvedPathSubset)
{
//
// Check the provider: only FileSystem provider paths are acceptable.
//
if (pi.Provider.Name != "FileSystem")
{
string msg = _resourceMgr.GetString("NotAFileSystemPath");
Exception exc = new(string.Format(CultureInfo.InvariantCulture, msg, path));
WriteError(new ErrorRecord(exc, "NotAFileSystemPath", ErrorCategory.InvalidArgument, path));
continue;
}
//
// Check the extension: only .evt, .evtx, and .etl files are allowed.
// If the file was specified without wildcards, display an error.
// Otherwise, skip silently.
//
if (!System.IO.Path.GetExtension(pi.Path).Equals(".evt", StringComparison.OrdinalIgnoreCase) &&
!System.IO.Path.GetExtension(pi.Path).Equals(".evtx", StringComparison.OrdinalIgnoreCase) &&
!System.IO.Path.GetExtension(pi.Path).Equals(".etl", StringComparison.OrdinalIgnoreCase))
{
if (!WildcardPattern.ContainsWildcardCharacters(path))
{
string msg = _resourceMgr.GetString("NotALogFile");
Exception exc = new(string.Format(CultureInfo.InvariantCulture, msg, pi.ProviderPath));
WriteError(new ErrorRecord(exc, "NotALogFile", ErrorCategory.InvalidArgument, path));
}
continue;
}
TerminateForNonEvtxFileWithoutOldest(pi.ProviderPath);
retColl.Add(pi.ProviderPath.ToLowerInvariant());
}
return retColl;
}
//
// CheckHashTablesForNullValues() checks all _selector values
// and writes a terminating error when it encounters a null
// as a single value or as part of an array.
//
private void CheckHashTablesForNullValues()
{
foreach (Hashtable hash in FilterHashtable)
{
foreach (string key in hash.Keys)
{
object value = hash[key];
if (value == null)
{
string msg = _resourceMgr.GetString("NullNotAllowedInHashtable");
Exception exc = new(string.Format(CultureInfo.InvariantCulture, msg, key));
ThrowTerminatingError(new ErrorRecord(exc, "NullNotAllowedInHashtable", ErrorCategory.InvalidArgument, key));
}
else
{
Array eltArray = value as Array;
if (eltArray != null)
{
foreach (object elt in eltArray)
{
if (elt == null)
{
string msg = _resourceMgr.GetString("NullNotAllowedInHashtable");
Exception exc = new(string.Format(CultureInfo.InvariantCulture, msg, key));
ThrowTerminatingError(new ErrorRecord(exc, "NullNotAllowedInHashtable", ErrorCategory.InvalidArgument, key));
}
}
}
}
}
}
}
//
// AddProviderPredicatesToFilter() builds an XPath query
// by adding provider predicates to _filter.
// Note that this is by no means an XPath expression parser
// and will may produce garbage if the _filterXPath expression provided by the user is invalid.
// However, we are relying on the EventLog XPath parser to reject the garbage later on.
//
private string AddProviderPredicatesToFilter(StringCollection providers)
{
if (providers.Count == 0)
{
return FilterXPath;
}
string ret = FilterXPath;
string predicate = BuildProvidersPredicate(providers);
if (FilterXPath.Equals("*", StringComparison.OrdinalIgnoreCase))
{
ret += "[" + predicate + "]";
}
else
{
//
// Extend the XPath provided in the _filter
//
int lastPredClose = FilterXPath.LastIndexOf(']');
if (lastPredClose == -1)
{
ret += "[" + predicate + "]";
}
else
{
ret = ret.Insert(lastPredClose, " and " + predicate);
}
}
return ret;
}
//
// BuildProvidersPredicate() builds a predicate expression like:
// "System/Provider[@Name='a' or @Name='b']"
// for all provider names specified in the "providers" argument.
//
private static string BuildProvidersPredicate(StringCollection providers)
{
if (providers.Count == 0)
{
return string.Empty;
}
StringBuilder predicate = new("System/Provider[");
for (int i = 0; i < providers.Count; i++)
{
predicate.Append("@Name='").Append(providers[i]).Append('\'');
if (i < (providers.Count - 1))
{
predicate.Append(" or ");
}
}
predicate.Append(']');
return predicate.ToString();
}
//
// BuildAllProvidersPredicate() builds a predicate expression like:
// "System/Provider[@Name='a' or @Name='b']"
// for all unique provider names specified in _providersByLogMap.
// Eliminates duplicates, too, since the same provider can
// be writing to several different logs.
//
private string BuildAllProvidersPredicate()
{
if (_providersByLogMap.Count == 0)
{
return string.Empty;
}
StringBuilder predicate = new("System/Provider[");
List<string> uniqueProviderNames = new();
foreach (string logKey in _providersByLogMap.Keys)
{
for (int i = 0; i < _providersByLogMap[logKey].Count; i++)
{
string lowerCaseProviderName = _providersByLogMap[logKey][i].ToLowerInvariant();
if (!uniqueProviderNames.Contains(lowerCaseProviderName))
{
uniqueProviderNames.Add(lowerCaseProviderName);
}
}
}
for (int i = 0; i < uniqueProviderNames.Count; i++)
{
predicate.Append("@Name='").Append(uniqueProviderNames[i]).Append('\'');
if (i < uniqueProviderNames.Count - 1)
{
predicate.Append(" or ");
}
}
predicate.Append(']');
return predicate.ToString();
}
//
// AddLogsForProviderToInternalMap helper.
// Retrieves log names to which _providerName writes.
// NOTE: there are many misconfigured providers in the system.
// We therefore catch EventLogException exceptions and write them out as non-terminating errors.
// The results are added to _providersByLogMap dictionary.
//
private void AddLogsForProviderToInternalMap(EventLogSession eventLogSession, string providerName)
{
try
{
ProviderMetadata providerMetadata = new(providerName, eventLogSession, CultureInfo.CurrentCulture);
System.Collections.IEnumerable logLinks = providerMetadata.LogLinks;
foreach (EventLogLink logLink in logLinks)
{
if (!_providersByLogMap.ContainsKey(logLink.LogName.ToLowerInvariant()))
{
//
// Skip direct ETW channels unless -force is present.
// Error out for direct channels unless -oldest is present.
//
EventLogConfiguration logObj = new(logLink.LogName, eventLogSession);
if (logObj.LogType == EventLogType.Debug || logObj.LogType == EventLogType.Analytical)
{
if (!Force.IsPresent)
{
continue;
}
ValidateLogName(logLink.LogName, eventLogSession);
}
WriteVerbose(string.Format(CultureInfo.InvariantCulture, _resourceMgr.GetString("ProviderLogLink"), providerName, logLink.LogName));
StringCollection provColl = new();
provColl.Add(providerName.ToLowerInvariant());
_providersByLogMap.Add(logLink.LogName.ToLowerInvariant(), provColl);
}
else
{
//
// Log is there: add provider, if needed
//
StringCollection coll = _providersByLogMap[logLink.LogName.ToLowerInvariant()];
if (!coll.Contains(providerName.ToLowerInvariant()))
{
WriteVerbose(string.Format(CultureInfo.InvariantCulture, _resourceMgr.GetString("ProviderLogLink"), providerName, logLink.LogName));
coll.Add(providerName.ToLowerInvariant());
}
}
}
}
catch (System.Diagnostics.Eventing.Reader.EventLogException exc)
{
string msg = string.Format(CultureInfo.InvariantCulture,
_resourceMgr.GetString("ProviderMetadataUnavailable"),
providerName, exc.Message);
Exception outerExc = new(msg, exc);
WriteError(new ErrorRecord(outerExc, "ProviderMetadataUnavailable", ErrorCategory.NotSpecified, null));
return;
}
}
//
// FindLogNamesMatchingWildcards helper.
// Finds all logs whose names match wildcard patterns in the 'logPatterns' argument.
// For each non-matched pattern, a non-terminating error is written.
// The results are added to _logNamesMatchingWildcard array.
//
private void FindLogNamesMatchingWildcards(EventLogSession eventLogSession, IEnumerable<string> logPatterns)
{
if (_logNamesMatchingWildcard == null)
{
_logNamesMatchingWildcard = new StringCollection();
}
else
{
_logNamesMatchingWildcard.Clear();
}
foreach (string logPattern in logPatterns)
{
bool bMatched = false;
WildcardPattern wildLogPattern = new(logPattern, WildcardOptions.IgnoreCase);
foreach (string actualLogName in eventLogSession.GetLogNames())
{
if (((!WildcardPattern.ContainsWildcardCharacters(logPattern))
&& (logPattern.Equals(actualLogName, StringComparison.OrdinalIgnoreCase)))
||
(wildLogPattern.IsMatch(actualLogName)))
{
//
// Skip direct ETW channels matching wildcards unless -force is present.
// Error out for direct channels unless -oldest is present.
//
EventLogConfiguration logObj;
try
{
logObj = new EventLogConfiguration(actualLogName, eventLogSession);
}
catch (Exception exc)
{
string msg = string.Format(CultureInfo.InvariantCulture,
_resourceMgr.GetString("LogInfoUnavailable"),
actualLogName, exc.Message);
Exception outerExc = new(msg, exc);
WriteError(new ErrorRecord(outerExc, "LogInfoUnavailable", ErrorCategory.NotSpecified, null));
continue;
}
if (logObj.LogType == EventLogType.Debug || logObj.LogType == EventLogType.Analytical)
{
if (WildcardPattern.ContainsWildcardCharacters(logPattern) && !Force.IsPresent)
{
continue;
}
ValidateLogName(actualLogName, eventLogSession);
}
if (!_logNamesMatchingWildcard.Contains(actualLogName.ToLowerInvariant()))
{
_logNamesMatchingWildcard.Add(actualLogName.ToLowerInvariant());
}
bMatched = true;
}
}
if (!bMatched)
{
string msg = _resourceMgr.GetString("NoMatchingLogsFound");
Exception exc = new(string.Format(CultureInfo.InvariantCulture, msg, ComputerName, logPattern));
WriteError(new ErrorRecord(exc, "NoMatchingLogsFound", ErrorCategory.ObjectNotFound, logPattern));
}
}
}
//
// FindProvidersByLogForWildcardPatterns helper.
// Finds all providers whose names match wildcard patterns in 'providerPatterns' argument.
// For each non-matched pattern, a non-terminating error is written.
// The results are added to _providersByLogMap dictionary (keyed by log names to which these providers write).
//
private void FindProvidersByLogForWildcardPatterns(EventLogSession eventLogSession, IEnumerable<string> providerPatterns)
{
_providersByLogMap.Clear();
foreach (string provPattern in providerPatterns)
{
bool bMatched = false;
WildcardPattern wildProvPattern = new(provPattern, WildcardOptions.IgnoreCase);
foreach (string provName in eventLogSession.GetProviderNames())
{
if (((!WildcardPattern.ContainsWildcardCharacters(provPattern))
&& (provPattern.Equals(provName, StringComparison.OrdinalIgnoreCase)))
||
(wildProvPattern.IsMatch(provName)))
{
WriteVerbose(string.Format(CultureInfo.InvariantCulture, "Found matching provider: {0}", provName));
AddLogsForProviderToInternalMap(eventLogSession, provName);
bMatched = true;
}
}
if (!bMatched)
{
string msg = _resourceMgr.GetString("NoMatchingProvidersFound");
Exception exc = new(string.Format(CultureInfo.InvariantCulture, msg, ComputerName, provPattern));
WriteError(new ErrorRecord(exc, "NoMatchingProvidersFound", ErrorCategory.ObjectNotFound, provPattern));
}
}
}
}
}