Parsing Windows Eventlogs in Powershell

Published: 2013-02-28
Last Updated: 2013-02-28 11:26:11 UTC
by Daniel Wesemann (Version: 1)
3 comment(s)

Recently, while chasing a malware, I wanted to review the local security log of a third party server to which I didn't have direct access. The administrator was willing to provide "a limited export" for my offline analysis.

Newer Windows versions nicely enough provide more than one option to accomplish this.

1. You can use the graphical event viewer GUI, and "Save-as", to export the file in EVTX, XML, TXT or CSV Format.

2. You can use wevtutil.exe at the command line to accomplish pretty much the same, but in a scriptable fashion. Wevtutil.exe  can export the entire log. It also supports an XPath filter that allows to query and export only certain log lines and attributes. Unfortunately, the syntax of these filters

wevtutil qe Security /q:"*[System[Provider[@Name='Microsoft-Windows-Security-Auditing'] and (EventID=4624)]]"

is a mess, and not easy to stomach for someone more used to the pristine beauty of egrep and regexp's :).

3. A third option is to make use of Powershell and the "get-winevent" or "get-eventlog" cmdlet

get-eventlog -logname security -newest 10000 | Export-clixml seclog.xml

is a pretty quick way to get the latest 10'000 records out of the security log. This is the option I chose, because I (somewhat naively) figured that this would be the fastest way to get a quick look. Not surprisingly, the export-xml command left me with an XML file, which is again not easy to stomach for someone more used to the pristine beauty of egrep and syslog :). But Powershell isn't bad, either. On the analysis workstation, you can stuff the entire log into a variable, thusly:

PS C:\TEMP> $seclog = Import-Clixml seclog.xml

and then use the power of Powershell to get a rapid tally:

PS C:\TEMP> $seclog | group eventid -noelement | sort count

Count Name
----- ----
    1 4662
    1 5058
    1 5061
    1 4904
    2 4648
    2 5140
    5 4611
    6 6144
    6 4735
   12 4985
   17 4634
   19 4672
   20 4674
   20 4624
  128 4663
  175 4673

KB947226 helps to translate the EventIDs into readable information. Once we know which events are of interest, we can then extract them:

PS C:\TEMP> $seclog | ? { $_.eventid -match '5140' } | fl *

Message : A network share object was accessed.

              Security ID:        S-1-5-21-394181-2045529214-8259512215-1280
              Account Name:       TRA29C
              Account Domain:     AMER
              Logon ID:           0x311a28b

          Network Information:
              Object Type:        File
              Source Address:
              Source Port:        6539

          Share Information:
              Share Name:        \\*\C$
              Share Path:        \??\C:\

All the Powershell formatting and querying and pattern match functions can now be used to cut and dice the information to find the haystalk in the cow pie.

If you have any clever Powershell Jiu-Jitsu up your sleeve to deal with unwieldy event logs, please let us know, or share in the comments below.


3 comment(s)


I have also found the flexibility of 'like" statements in PS to be very useful when querying the message portion of event logs. For example; the following are Object Access logs for an add or delete of a file.

get-winevent -path "C:\Logs\Comp1.evtx", "C:\Logs\Comp2.evtx" | where {$_.Id -eq "4663" -and $_.message -like "*0x10000*" -or $_.Id -eq 4663 -and $_.message -like "*0x6*"} > C:\Logs\stdout.csv
I like this format I took from blogs I can't remember any more... This is for printing, but you can get the log name from the Event Viewer. Note that the properties are in the order they occur on the details tab of Ev Vw
$filter = @{ LogName = "Microsoft-Windows-PrintService/Operational"
ID = 307
StartTime = [DateTime]::Today.AddDays(-1)
EndTime = [DateTime]::Today
$event = Get-WinEvent -FilterHashtable $filter -ComputerName $computer -ErrorAction Stop |
select `
@{label='Time Printed'; Expression={get-date $_.TimeCreated -format s}}, `
@{label='Document ID'; Expression={$[0].value}}, `
@{label='Document Name'; Expression={$[1].value}}, `
@{label='User ID'; Expression={$[2].value}} | Do lots of stuff
Don't forget LogParser!

LogParer -i:EVT -resolveSIDs:on -o:CSV -oDQuotes:on "SELECT TimeGenerated,EventID,EventType,EventCategory,Strings,SID,Message,Data INTO Report.csv FROM \\SERVER\Security WHERE SID LIKE 'S-%'"

SQL-ish syntax and it can read from EVT directly or from EVT binary files. Also, can read lots of other formats and output to many different formats.

Diary Archives