Filtering Windows events with built-in utilities

Text version speeches on PHD11

A few words about the problem

When responding to incidents, it is sometimes necessary to look at the Windows logs of a machine, and many carry utilities with them to conveniently filter events in the evtx logs. This is due to the fact that the filtering methods proposed by Microsoft look extremely inconvenient.

live response is an area that collects information from a running computer to determine if an incident has occurred.

When conducting live response analysis, it is useful to quickly understand what has been happening with the computer lately.

There are various live response tools: commercial, open source, and built-in OS capabilities.

The use of open source and commercial tools is associated with a number of problems:

Inconvenience of filtering with the eventvwr.msc snap-in

evtx filtering with standard tooling event viewer (eventvwr.msc) is limited in scope.


  • there is no way to display information in columns

  • missing regular expressions and substring search

  • no grouping



In addition, the standard Event Viewer snap-in does not support all features XPathwhich can create additional filtering problems.

Thus, evtx filtering with the standard Event Viewer snap-in and XPath 1.0 is limited and not always convenient. For more flexible and convenient work with event logs, you can use specialized tools for analyzing logs, which provide more filtering and searching for information.

XPath Constraints for Event Filtering

XPath Constraints for Event Filtering

One of the major limitations of XPath 1.0 is that it does not support attribute search. That is, if you want to find events associated with a specific EventID, you can use the element EventIDbut you won’t be able to use nested element attributes to search for events, like so: TargetUserName.

Example event in XML format

Example event in XML format

XPath, in a snap, does not support regular expressions and substring searches, which can be useful when filtering Windows event logs. Regular expressions allow you to search for text strings that match a specific pattern, which can be useful, for example, when searching for IP addresses or filenames.

Thus, the disadvantages of XPath for filtering Windows event logs are the limited ability to search by the attributes of nested elements, the absence of some comparison functions, and the lack of support for regular expressions.

As shown above, ‘Element’ nodes can contain ‘Attributes’ and we can use the ‘@’ wildcard to search for ‘Data’ nodes.

The example below allows you to find all events from the Security log with EventID = 4688. The Path attribute in the Query directive can be omitted. The path to the log is specified in the Path attribute of the Select directive.

  <Query Id="0" Path="Security">
    <Select Path="Security">*[System[EventID=4688]]</Select>

In the example below, we add the use of the logical OR operator to search for an event with EventID 4688 or 4624.

  <Query Id="0" Path="Security">
    <Select Path="Security">*[System[EventID=4688 or EventID=4624]]</Select>

In the following example, let’s add filtering by the XML section – EventData. To combine two conditions in one Select, the logical AND operator is used. The second part of the request begins with the * sign, which means that the top node can take on any value, then we specify the path to the attribute whose value we want to specify in the condition EventData -> Data -> @Attribute=”value”.

  <Query Id="0" Path="Security">
    <Select Path="Security">*[System[EventID=4688]] and 

XPath allows you to search for a value across all attributes, as in the example below. The structure above has changed to EventData -> Data -> @Attribute =”value”. The following queries will find all events where “C:\Windows\System32\lsass.exe” appeared in the attributes

  <Query Id="0" Path="Security">
    <Select Path="Security">*[System[EventID=4688]] and 

The Suppress operator allows you to exclude from the final selection events that match the condition in it. In the example below, we will find all 4624 events where LogonType=5.

  <Query Id="0" Path="Security">
    <Select Path="Security">*[System[EventID=4624]]</Select>
    <Suppress Path="Security">*[EventData[Data[@Name="LogonType"]=5]]</Suppress>

Within one Query, we can specify several Select queries, and it is also possible to request events from different logs.

  <Query Id="0">
    <Select Path="Security">*[System[EventID=4688]]</Select>
    <Select Path="Windows PowerShell">*</Select>

There can be several Query in one QueryList. This is useful for logically splitting queries and filtering them.

    <Query Id="0" Path="Security">
        <Select Path="Security">*[System[EventID=4688]]</Select>
    <Query Id="1" Path="Microsoft-Windows-Sysmon/Operational">
        <Select Path="Microsoft-Windows-Sysmon/Operational">*</Select>

CMD capabilities

CMD is limited to using the two main utilities wevtutil and Findstr. wevtutil allows you to work with log parameters and create queries to them. Wevtutil also uses XPath queries for queries.

wevtutil.exe qe Security /q:"*[EventData[Data[@Name="TargetUserName"]='User1' and Data[@Name="LogonType"]=2]]" /f:text

When using findstr, our possibilities are expanded to find strings of interest to us.

wevtutil.exe qe Security /q:"*[EventData[Data[@Name="LogonType"]=11]]" /f:text | findstr "Account Name"

PowerShell Capabilities

There are two cmdlets in Powershell for working with logs Get-EventLog And Get-WinEvent. We will consider the second cmdlet as it is considered relevant.

The main features of Get-WinEvent are the use of hash tables and Xpath to filter events. To use hash tables, the -FilterHashtable argument is used, you can omit it and build a query immediately with @{}.

Limitation when creating FilterHastale

Let’s look at a few examples of using the cmdlet Get-WinEvent and building pipelines with it.

In the following example, we will output 1000 events from the Security log.

Get-WinEvent -LogName Security -MaxEvents 1000

The same query, but using Format List to make the output readable.

Get-WinEvent -LogName Secutity -MaxEvents 10 | Format-List

We use FilterHashtable. Let’s output events from the Security log with EventId 4688.

Get-WinEvent @{logname="security";ID=4688} -MaxEvents 100 | Format-List

To understand further filters, let’s see how an event is represented in Powershell, for this we output one event and use the cmdlet GetMember.

Get-WinEvent @{logname="security";ID=4688} -MaxEvents 1 | Get-Member

Property Properties is a list that stores the main parameters of the event, which are located in the EventData section of the xml view.

After we learned how to receive events from a specific log and by a specific EventId, let’s see how we can get the data we are interested in. Let’s output events 4688, and display the creation time of the event and {$_.Properties[5].value}, which holds the name of the running process. List item number Properties matches the attribute number in the section EventData xml representation of the event.

Get-WinEvent @{logname="security";ID=4688} -MaxEvents 100 | 
select timecreated,{$_.Properties[5].value} | Format-List

Powershell allows us to create groupings using the Group-Object cmdlet. The next query will group the Sysmon EventId 3 events by the following fields: process, recipient address, recipient domain name, recipient port.

Get-WinEvent @{LogName="*sysmon*";ID=3}  -MaxEvents 10000 | 
Where-Object {$_.Properties[16].Value -ne 443} | 
Group-Object {$_.Properties[4].Value},{$_.Properties[14].Value}, {$_.Properties[15].Value}, {$_.Properties[16].Value} | 
Select-Object Name, Count | Sort-Object Count -Descending  | Format-List

To search for substrings, we can use -Match or -Like.

Get-WinEvent @{LogName="*sysmon*";ID=1}  -MaxEvents 1000 | 
Where-Object {$_.Properties[10].Value -Match ".*cmd.exe" }  | 
Select-Object {$_.Properties[10].Value} | 

Finding events with a known attribute value is faster using XPath queries than using Powershell pipelines. For example: the query below will find all events associated with the user R00t1k\Vadim.

Get-WinEvent -LogName *Sysmon* -FilterXPath "*[EventData[Data[@Name="User"]='LAB\vadim']]" | 
Where-Object {$_.Properties[4].Value -Match ".*WINWORD.exe"} | 

Poweshell allows you to present a message as xml by executing the following code.

$eventlog = Get-WinEvent -FilterHashtable @{LogName="Security";ID=4624} -MaxEvents 1
$xml = [xml]$eventlog.ToXml()

Powershell module Convert-EventLogRecord converts events into a data structure that allows you to access attributes by their name. Pipeline for filtering events with Convert-EventLogRecord will run 2-3 times longer, unlike a pipeline without using it.

# С использованием Convert-EventLogRecord
Get-WinEvent -FilterHashtable @{LogName="Security";ID=4624} | 
Convert-EventLogRecord | Where-Object LogonType -ne 5 | 
Select TimeCreated, TargetUserName, LogonType

# Без использования Convert-EventLogRecord
Get-WinEvent @{LogName="Security";Id=4624} | 
Where-Object {$_.Properties[8].Value -ne 5} | 
Select TimeCreated, {$_.Properties[5].Value}, {$_.Properties[8].Value}

Using cmdlet Out GridView we can display the events in the form of a table.

Get-WinEvent -FilterHashtable @{LogName="Security"; ID=4624} |
    Select-Object TimeCreated, 
@{Name="User"; Expression={$_.Properties[5].Value}}, 
@{Name="LogonType"; Expression={$_.Properties[8].Value}},
@{Name="SrcIp"; Expression={$_.Properties[18].Value}}  |

To display several events in a table, you need to take into account that the serial numbers of attributes for different EventIds can store different data.

 Get-WinEvent -FilterHashtable @{LogName="Security"; ID=4624, 4688} -MaxEvents 1000 | Where-Object {$_.Properties[8].Value -ne 5} |
    ForEach-Object {
        if ($_.Id -eq 4624) {
            $Username = $_.Properties[5].Value
            $LogonType = $_.Properties[8].Value
            $LogonProcess = $_.Properties[9].Value
            $IpAddress = $_.Properties[18].Value
        elseif ($_.Id -eq 4688) {
            $SubjectUserName = $_.Properties[1].Value
            $SubjectUserDomain = $_.Properties[2].Value
            $NewProcessName = $_.Properties[5].Value
            $CommandLine= $_.Properties[8].Value
            $ParrentProcessName= $_.Properties[13].Value
            Time = $_.TimeCreated
            EventID = $_.Id
            Username = $Username
            LogonType = $LogonType
            LogonProcess = $LogonProcess
            IpAddress = $IpAddress
            SubjectUserName = $SubjectUserName
            SubjectUserDomain = $SubjectUserDomain
            NewProcessName = $NewProcessName
            CommandLine = $CommandLine
            ParrentProcessName = $ParrentProcessName
    } | Out-GridView

Before investigating incidents, it is worth spending time on the first step in responding – Preparation. Having found yourself in a situation without a flash drive, with prepared software, you were not at a loss and were able to understand what was happening in the Windows logs. In the second article, we will consider the utilities mentioned in the report.

Similar Posts

Leave a Reply

Your email address will not be published. Required fields are marked *