Easy Event Log Querying with PowerShell

If you’re using any kind of native Active Directory (AD) auditing today you probably love the information it generates in the security event log. Native AD auditing is awesome about generating loads of useful information as to what happened and when. The problem arises when you actually want to read that information and figure out what’s going on! Native AD auditing generates hundreds of event types on one of many different domain controllers or client systems depending on the type of auditing.

Native AD auditing is known for generating lots of useful information but also generates lots of not-so-useful data. At the same time, the useful information isn’t just recorded as a single event like “User A logged onto computer Y” or “User B removed a GPO while attached to domain controller H”. It’s not that simple. AD auditing can potentially generate 3, 4 or more different kinds of events that correlate to a single actual event you’re looking for making it impossible to just eyeball the event log.

Using PowerShell’s native event log parsing you can pull out all of these events and, if coded right, can match up actual real-world events with event IDs.

Let’s run through an example of how to get this done. Let’s say I need to find out who launched notepad on a few different computers and when. After enabling Audit Process Creation and getting it applied to the machines in question I launch notepad on one of the affected machines and get an event like this; event ID 4688 with the time and the EXE that was launched (notepad.exe).

1

That’s great but this event is buried under thousands of other events. How do I get to this information quickly and on multiple machines? With PowerShell script, we’ll need to first find all of the computers in the OU that we applied the audit policy to. For simplicity, in our case, I used the Domain Controllers OU. I’ll need to get all of the computers in that OU. To do that, I’ll use the Get-ADComputer cmdlet.

Get-ADComputer -SearchBase ‘OU=Domain Controllers,DC=lab,DC=local’ -Filter * | Select-Object Name

2

I now have a list of all the computers I want to target. Next, I need to know what event IDs I’m looking for. I learned from the MS Technet AD auditing link that I’m looking for event ID 4688. Let’s check for event ID 4688 on all of these computers.

(Get-ADComputer -SearchBase ‘OU=Domain Controllers,DC=lab,DC=local’ -Filter *).Name | Get-EventLog -LogName Security -InstanceId 4688

3

You can see that I got back a lot of events but these events don’t mean anything to me now. Which computer did the event come from? Was it the event for notepad.exe? Let’s get more granular. From this point, I don’t expect you to follow along exactly what I’m doing. Unfortunately, there’s no way to query the message box like there is event ID, so we can’t use Get-EventLog to do this. We’ll have to use Get-WinEvent. 

## Create the XPath query

$EventFilterXPath = “Event[System[EventID=’4688′]] and Event[EventData[Data[@Name=’NewProcessName’] and (Data=’C:\Windows\System32\notepad.exe’)]]” 

## Run the query against all computers

(Get-ADComputer -SearchBase ‘OU=Domain Controllers,DC=lab,DC=local’ -Filter *).Name | foreach { Get-WinEvent -ComputerName $_ -LogName Security -FilterXPath $EventFilterXPath } 

Now we actually have all the events that we need but we need to find the computer names that they’re coming from and we also don’t know the username. Let’s fix that.

(Get-ADComputer -SearchBase ‘OU=Domain Controllers,DC=lab,DC=local’ -Filter *).Name | foreach { Get-WinEvent -ComputerName $_ -LogName Security -FilterXPath $EventFilterXPath } | Select-Object @{n=’ComputerName’;e={$_.MachineName}},@{n=’Time’;e={$_.TimeCreated}},@{n=’Account’;e={[regex]::Matches($_.Message,’Account Name:\s+(.*)\n’).Groups[1].Value.Trim()}} | Format-Table -Autosiz

4

Scary code, I know. Sometimes that’s what you must do when writing scripts. I wonder if there’s a product that can report on AD auditing like this and make it much simpler.