FUNctions: Episode VI, Return of the Logs

Logs? Again? Really, Ryan? Give me something more interesting!

I f*&^ing love logs! I love writing logs. I love reading logs. I love smelling the exhaust of my laptop while my computer is opening a log. (that last one is a joke.)

This week’s entry tackles getting the Windows Defender logs from Event Viewer for the past 10 days. It comes from a friend/ former coworker. We had just implemented ASR (Attack Surface Reduction) rules in our Microsoft Tenant, and were getting spammed with support tickets for related blocks. In our attempt to ease our troubleshooting, we came up with this function to grab only the related ASR related logs from Event Viewer on remote machines. Its since been slightly modified to encompass all logs from the operational logs of Windows Defender.

FYI: ASR log IDs are 1123 (for rule = triggered) and 1124 (for rule = blocked).

TL;DR: GitHub

Section 1 | What’s the deal with XML?

You can simply get events from Windows Event Viewer usingthe Get-WinEvents cmdlet, but the real star of this writeup is the XML query we write to hone in our search.

$xmlQuery = @'
<QueryList>
<Query Path="Microsoft-Windows-Windows Defender/Operational">
<Select Path="Microsoft-Windows-Windows Defender/Operational">*[System[(Level=1  or Level=2 or Level=3 or Level=4) and TimeCreated[timediff(@SystemTime) &lt;= 864000000]]]</Select>
</Query>
</QueryList>
'@

As you can see, we are creating an XML query for PowerShell that does the following, in order:

  1. Query the Event Viewer section for Windows Defender operational events
  2. Filters for Level 1, 2, 3, or 4 events AND filters by the time created
    • You can remove any of the “Level X” portions to narrow your search
    • The TimeCreated property is a bit funky to handle. Its in milliseconds. So in this example 864 million milliseconds = 10 days.

Then we simply pump that XML query into a Get-WinEvent command, take those events and eventually pipe it to an Export-CSV command.

  $Events= Get-WinEvent -ComputerName $ComputerName -FilterXML $xmlQuery
  $Events | Select-Object -Property TimeCreated,Message,ID | Export-CSV "C:\Temp\DefenderEvents-$ComputerName.CSV" -NoTypeInformation -Encoding UTF8

So the full function looks like this:

Function Get-DefenderEvents
{
 Param([parameter(Mandatory=$true)]
    [alias("Computer")]$ComputerName)
$xmlQuery = @'
<QueryList>
<Query Path="Microsoft-Windows-Windows Defender/Operational">
<Select Path="Microsoft-Windows-Windows Defender/Operational">*[System[(Level=1  or Level=2 or Level=3 or Level=4) and TimeCreated[timediff(@SystemTime) &lt;= 864000000]]]</Select>
</Query>
</QueryList>
'@

  $Events= Get-WinEvent -ComputerName $ComputerName -FilterXML $xmlQuery
  $Events | Select-Object -Property TimeCreated,Message,ID | Export-CSV "C:\Temp\DefenderEvents-$ComputerName.CSV" -NoTypeInformation -Encoding UTF8
}

Easy! But the syntax on XML queries in PowerShell is rough if you aren’t familiar with the topic.

This function will pull what you need to troubleshoot ASR rules on your remote Windows endpoints. Its short, sweet, and efficient. Once you peruse your exported .CSV you’ll be able to identify what Defender is doing behind the scenes.

I hope this helps speed up your throubleshooting!

As always:

This project is provided “as is” without any warranty of any kind, express or implied. Use it at your own risk. The authors and contributors are not responsible for any damage, data loss, or other issues that may arise from using this software. You are solely responsible for any actions taken based on this code.