EVTX Log Forensics & High-Speed Parsing
Techniques for extracting and analyzing Windows Event Logs (.evtx) with maximum performance using Get-WinEvent and structured hashtable filters.
⚡ Performance Rule: Always Use -FilterHashtable
Section titled “⚡ Performance Rule: Always Use -FilterHashtable”[!WARNING] Never pipe unfiltered logs to
Where-Object(e.g.Get-WinEvent -LogName Security | Where {$_.Id -eq 4624}). This forces PowerShell to instantiate millions of .NET event objects in memory. Always push the filter directly to the Windows Event Log API via-FilterHashtable.
🔑 Critical Windows Event IDs Reference
Section titled “🔑 Critical Windows Event IDs Reference”| Event ID | Log | Description | Key Forensic Value |
|---|---|---|---|
| 4688 | Security | A new process has been created | Process name, PID, PPID, ProcessCommandLine |
| 4624 | Security | Successful account logon | LogonType (2=Interactive, 3=Network, 10=RDP), Source IP |
| 4625 | Security | Failed account logon | FailureReason, SubStatus, Source IP, Target Account |
| 4672 | Security | Special privileges assigned to new logon | Administrator privilege assignment (SeDebugPrivilege) |
| 4697 / 7045 | Sec / Sys | A service was installed | ServiceName, ImagePath (Persistence indicator) |
| 4720 | Security | A user account was created | Rogue user creation, Creator user |
| 4728 / 4732 | Security | Member added to security group | Privilege escalation to local Administrators group |
| 4104 | PS-Op | Script block execution | Full decrypted script text (Script Block Logging) |
| 1102 / 104 | Sec / Sys | The audit log was cleared | Anti-forensics / log tampering evidence |
🔎 High-Speed Parsing Recipes
Section titled “🔎 High-Speed Parsing Recipes”1. Hunting Process Creation (Event 4688) with Command Lines
Section titled “1. Hunting Process Creation (Event 4688) with Command Lines”- 🎯 What it looks for: Windows Security Log Event ID 4688 records containing suspicious reconnaissance, download, or privilege escalation commands (
powershell,cmd,net,whoami,vssadmin,certutil,bitsadmin). - 💡 Why it matters: When Command Line Process Auditing is enabled, Event 4688 captures the complete argument string passed to any newly spawned process, including the launching parent process and executing user context. This reconstructs the adversary’s exact interactive terminal commands even if shell histories are cleared.
# Extract Event 4688 in the last 2 hours matching suspicious commands$filter = @{ LogName = 'Security' Id = 4688 StartTime = (Get-Date).AddHours(-2)}
Get-WinEvent -FilterHashtable $filter | ForEach-Object { $xml = [xml]$_.ToXml() $eventData = $xml.Event.EventData.Data
$procName = ($eventData | Where-Object { $_.Name -eq 'NewProcessName' }).'#text' $cmdLine = ($eventData | Where-Object { $_.Name -eq 'CommandLine' }).'#text' $parent = ($eventData | Where-Object { $_.Name -eq 'ParentProcessName' }).'#text' $user = ($eventData | Where-Object { $_.Name -eq 'TargetUserName' }).'#text'
[PSCustomObject]@{ TimeCreated = $_.TimeCreated User = $user Process = $procName Parent = $parent CommandLine = $cmdLine }} | Where-Object { $_.CommandLine -match '(powershell|cmd|net|whoami|vssadmin|certutil|bitsadmin)' } | Format-Table -AutoSize2. RDP and Remote Network Logons (Event 4624, Logon Types 3 & 10)
Section titled “2. RDP and Remote Network Logons (Event 4624, Logon Types 3 & 10)”- 🎯 What it looks for: Successful authentication events (Event 4624) categorized as Network logons (Logon Type 3) or Remote Interactive / Remote Desktop logons (Logon Type 10), filtering out local system loopback addresses.
- 💡 Why it matters: Lateral movement across a cloud-managed network manifests as inbound remote connections. Correlating the source IP address with the target user account reveals which internal device or external VPN/bastion address was used to pivot onto the machine.
# Filter for Network (Type 3) and Remote Desktop (Type 10) logons$filter = @{ LogName = 'Security' Id = 4624 StartTime = (Get-Date).AddDays(-1)}
Get-WinEvent -FilterHashtable $filter | ForEach-Object { $xml = [xml]$_.ToXml() $data = $xml.Event.EventData.Data
$logonType = ($data | Where-Object { $_.Name -eq 'LogonType' }).'#text' $targetUser = ($data | Where-Object { $_.Name -eq 'TargetUserName' }).'#text' $ipAddress = ($data | Where-Object { $_.Name -eq 'IpAddress' }).'#text'
if ($logonType -in @('3', '10') -and $ipAddress -ne '-' -and $ipAddress -ne '127.0.0.1') { [PSCustomObject]@{ TimeCreated = $_.TimeCreated User = $targetUser LogonType = if ($logonType -eq '10') { 'RDP (10)' } else { 'Network (3)' } SourceIP = $ipAddress } }} | Format-Table -AutoSize3. PowerShell Script Block Deobfuscation (Event 4104)
Section titled “3. PowerShell Script Block Deobfuscation (Event 4104)”- 🎯 What it looks for: PowerShell Operational Log Event 4104 entries containing in-memory decompilation and execution patterns (
FromBase64String,DownloadString,WebClient,GzipStream,Invoke-Expression,IEX). - 💡 Why it matters: Script Block Logging records the complete content of script blocks executed by PowerShell, regardless of whether the code was executed from a file, invoked interactively, or piped through multiple layers of Base64/XOR obfuscation. PowerShell de-obfuscates the code immediately prior to execution, and Event 4104 captures this final decrypted payload.
# Extract suspicious PowerShell script block executions$filter = @{ LogName = 'Microsoft-Windows-PowerShell/Operational' Id = 4104 StartTime = (Get-Date).AddDays(-3)}
Get-WinEvent -FilterHashtable $filter | ForEach-Object { $xml = [xml]$_.ToXml() $scriptText = $xml.Event.UserData.ExecuteCommandHierarchy.ScriptBlockText
if ($scriptText -match '(FromBase64String|DownloadString|WebClient|GzipStream|Invoke-Expression|IEX)') { [PSCustomObject]@{ TimeCreated = $_.TimeCreated ScriptText = $scriptText.Substring(0, [Math]::Min(300, $scriptText.Length)) # Preview first 300 chars } }} | Format-List4. Direct Offline .evtx File Analysis (XPath Filtering)
Section titled “4. Direct Offline .evtx File Analysis (XPath Filtering)”- 🎯 What it looks for: Queries raw forensic
.evtxfiles exported from a disk image or live response collection, using high-speed XPath queries to extract log clearing attempts (Event 1102), rogue user account creation (Event 4720), and new service installations (Event 7045). - 💡 Why it matters: Forensic analysts frequently triage triage packages or disk images on an analytical workstation without mounting the live operating system. XPath filtering directly queries the offline XML structure, returning critical indicators of compromise in seconds without needing third-party GUI viewers.
# Parse a carved or collected offline EVTX file from a forensic image$evtxPath = "C:\Forensics\Triage\Security.evtx"
Get-WinEvent -Path $evtxPath -FilterXPath "*[System[(EventID=1102 or EventID=4720 or EventID=7045)]]" | Select-Object TimeCreated, Id, Message | Format-Table -Wrap