Introduction

Get-WinEvent Reference on Technet doesn't go into detail on how to use the FilterXPath parameter to filter for events; however, it directs you to XPath Reference on MSDN and Event Selection on MSDN. This post attempts to summarize the documents on XPath specific to building complex XPath queries for events.

In this post, I am going to explain how the following XPath filter works to get all of the logon events for the past 24 hours for a specific user.

Get-WinEvent -LogName Security -FilterXPath "*[System[EventID=4624 and TimeCreated[timediff(@SystemTime) <= 86400000]] and EventData[Data[@Name='TargetUserName']='jdoe']]"

Getting the XML

Since XPath filters on XML, we need to see the xml representation of the event we want to retrieve in order to understand the syntax. Open the Event Viewer (eventvwr.msc) and open the event for which you want to filter. Go to the Details Tab, and select the XML View. The following is the xml from a sample logon event.

<Event xmlns="http://schemas.microsoft.com/win/2004/08/events/event">
  <System>
    <Provider Name="Microsoft-Windows-Security-Auditing" Guid="{54849625-5478-4994-A5BA-3E3B0328C30D}" />
    <EventID>4624</EventID>
    <Version>1</Version>
    <Level>0</Level>
    <Task>12544</Task>
    <Opcode>0</Opcode>
    <Keywords>0x8020000000000000</Keywords>
    <TimeCreated SystemTime="2014-12-06T00:01:10.833450200Z" />
    <EventRecordID>23999</EventRecordID>
    <Correlation />
    <Execution ProcessID="552" ThreadID="504" />
    <Channel>Security</Channel>
    <Computer>computer-name</Computer>
    <Security />
  </System>
  <EventData>
    <Data Name="SubjectUserSid">S-1-5-18</Data>
    <Data Name="SubjectUserName">computer-name$</Data>
    <Data Name="SubjectDomainName">WORKGROUP</Data>
    <Data Name="SubjectLogonId">0x3e7</Data>
    <Data Name="TargetUserSid">S-1-5-21-1004</Data>
    <Data Name="TargetUserName">jdoe</Data>
    <Data Name="TargetDomainName">computer-name</Data>
    <Data Name="TargetLogonId">0x33648</Data>
    <Data Name="LogonType">2</Data>
    <Data Name="LogonProcessName">User32 </Data>
    <Data Name="AuthenticationPackageName">Negotiate</Data>
    <Data Name="WorkstationName">computer-name</Data>
    <Data Name="LogonGuid">{00000000-0000-0000-0000-000000000000}</Data>
    <Data Name="TransmittedServices">-</Data>
    <Data Name="LmPackageName">-</Data>
    <Data Name="KeyLength">0</Data>
    <Data Name="ProcessId">0x210</Data>
    <Data Name="ProcessName">C:\Windows\System32\winlogon.exe</Data>
    <Data Name="IpAddress">127.0.0.1</Data>
    <Data Name="IpPort">0</Data>
    <Data Name="ImpersonationLevel">%%1833</Data>
  </EventData>
</Event>

Exploring the XPath

We'll start by breaking down the following syntax:

"*[System[EventID=4624 and TimeCreated[timediff(@SystemTime) <= 86400000]] and EventData[Data[@Name='TargetUserName']='jdoe']]"

Notice that it starts with an *, and every thing else is inside a set of brackets. Removing the syntax inside the brackets:

"*[]"

What is happening here is that the asterisk character means to get all the events, and the brackets are limiting those events to just the ones that match the criteria on the inside. Note that these broken-down examples will not work on their own.

Next, we'll look at the criteria inside the first/outer set of brackets.

System[] and EventData[]

This tells us that only events that have a System element that matches the filter in its brackets AND an EventData element that matches the criteria in its brackets. Notice that System and EventData are the elements in our XML event directly underneath the Event element.

<Event xmlns="http://schemas.microsoft.com/win/2004/08/events/event">
  <System>
  </System>
  <EventData>
  </EventData>
</Event>

Now, we'll take a look at the criteria for the System element.

EventID=4624 and TimeCreated[]

This says that we only want events where the EventID is 4624 and the TimeCreated element that matches the criteria in its brackets. Now, we'll look at the criteria for the TimeCreated element.

timediff(@SystemTime) <= 86400000

This criteria specifies events that occurred less than one day ago. See Understanding Time Values. This is done by computing the amount of time that has passed since the event was created. The timediff function is used to compute that value, and is detailed further in Event Selection on MSDN. When used like above, with one argument, it computes the difference between @SystemTime and the current time. Now, we'll look at the XML for the TimeCreated element in our event.

<TimeCreated SystemTime="2014-12-06T00:01:10.833450200Z" />

Notice that SystemTime is an attribute of TimeCreated. An attribute is a value defined inside the tag's angle brackets. When referring to attributes, the name is prefaced with the @ symbol. So, the filter is saying that the difference between the SystemTime attribute of the TimeCreated element and the current time is less than or equal to one day.

Now, we'll look at the EventData filter criteria.

Data[@Name='TargetUserName']='jdoe'

We now know enough to understand what this criteria is saying. It will only return events where the EventData element has a Data element, and that Data element has an attribute called Name that is equal to TargetUserName AND that the value of the Data element is jdoe. It matches the following line of XML.

<Data Name="TargetUserName">jdoe</Data>

And the entire filter again:

"*[System[EventID=4624 and TimeCreated[timediff(@SystemTime) <= 86400000]] and EventData[Data[@Name='TargetUserName']='jdoe']]"

Which means all events that have a System element where the EventID is 4624 and the difference between the SystemTime attribute of the TimeCreated element and the current time is less than or equal to one day, and there exists within the EventData element a Data element with an attribute called Name that is set to TargetUserName and the value of the element is jdoe.

Alternate Synonymous Syntax

Get-WinEvent -LogName Security -FilterXPath "*/System/EventID=4624 and */System/TimeCreated[timediff(@SystemTime) <= 86400000] and */EventData/Data[@Name='TargetUserName']='jdoe'" 
Get-WinEvent -LogName Security -FilterXPath "*[System[EventID=4624 and TimeCreated[timediff(@SystemTime) <= 86400000]] and EventData/Data[@Name='TargetUserName']='jdoe']"

These alternate syntaxes illustrate that when there is only a single criterion to test for, the brackets can be replaced with a forward slash (/).

Understanding Time Values

The time values here are represented as milliseconds. One day would be 24 hours times 60 minutes times 60 seconds times 1000 milliseconds. The result would be 86400000.

The value can be calculated easily using the New-TimeSpan cmdlet. The following examples illustrate how to get the timespan for 1 week and 8 hours respectively.

New-TimeSpan -Days 7 | Select-Object -ExpandProperty TotalMilliseconds
New-TimeSpan -Hours 8 | Select-Object -ExpandProperty TotalMilliseconds

A note on encoding less than (<) and greater than (>)

A lot of the documentation will show the less than and greater than signs as &lt; and &gt; respectively. In XML those characters have to be encoded. My testing shows that you have to use the actual less than and greater than symbols even if the documentation shows the use of the encoded versions.

Additional Examples

# Gets all the 4624 events 
Get-WinEvent -LogName Security -FilterXPath "*/System/EventID=4624"
# Gets all events except 4624
Get-WinEvent -LogName Security -FilterXPath "*/System/EventID!=4624"
# Gets all events except 4624 and 4648
Get-WinEvent -LogName Security -FilterXPath "*/System[EventID!=4624 and EventID!=4648]"
# Gets all events Warning and above
Get-WinEvent -LogName System -FilterXPath "*/System/Level<=3"

Next Post