jdgregson
jdgregson

Reputation: 1587

Most efficient way to search event log messages

Suppose I want to find the newest occurrence of event 4688 that contains the string 0x1278. I am able to find the event by getting a certain number of events and then searching the message for that string:

Get-WinEvent -MaxEvents 1000 -FilterHashTable @{LogName="Security";Id=4688} | Where-Object {$_.Message -match "0x1278"}

There are two issues with this approach:

  1. The script must always wait for 1000 events to be returned, even if the event being searched for was at index 3.
  2. If the event was older and would have been at index 1034, too few events were checked and it wasn't found when it should have been.

Is there a way to address these issues? Ideally the event should be found in the shortest time possible.

Upvotes: 2

Views: 3162

Answers (2)

Mathias R. Jessen
Mathias R. Jessen

Reputation: 174485

Use -FilterXPath to offload filtering to the event log service!

This approach won't allow us to search the text of the rendered log message, but it will allow us to very granularly query structured data in the event.

Assuming that you're searching 0x1278 because it's a process ID event, we can query for that specific event with the following XPath expression:

*[System[EventID=4688] and EventData[Data[@Name='NewProcessId']='0x3e8']]

Used with Get-WinEvent, we end up with something like:

Get-WinEvent -MaxEvents 1000 -FilterXPath "*[System[EventID=4688] and EventData[Data[@Name='NewProcessId']='0x3e8']]" -LogName "Security"

Now the eventlog service only needs to return one event, making your Get-WinEvent query execute much faster

Upvotes: 2

jdgregson
jdgregson

Reputation: 1587

Instead of piping the array of events to Where-Object, pipe it to ForEach-Object, assign the first match to a variable, and then break out of the loop. If you remove the -MaxEvents parameter, all events will be searched until a match is found or there are no more events:

PS C:\WINDOWS\system32> Get-WinEvent -FilterHashTable @{LogName="Security";id=4688} | ForEach-Object {if ($_.Message -match "0x1278") {$result = $_; break;}}
PS C:\WINDOWS\system32> $result


   ProviderName: Microsoft-Windows-Security-Auditing

TimeCreated                     Id LevelDisplayName Message
-----------                     -- ---------------- -------
2/18/2020 10:14:55 AM         4688 Information      A new process has been created....

Upvotes: 2

Related Questions