In this module
IR1.9 Native Windows IR — When You Have Nothing but the OS
Native Windows IR — When You Have Nothing but the OS
When the forensic tools are not available yet
You are on a call with a panicking sysadmin. A server is behaving strangely and they think it is compromised. You need them to capture volatile data — running processes, network connections, logged-in users — before anyone reboots the system. They do not have KAPE. They do not have EZTools. They have a command prompt and PowerShell. What do you tell them to run? Native Windows commands are the fallback when proper forensic tools have not been deployed yet — and knowing them means you can guide a non-forensic responder through critical evidence capture over the phone.
Every forensic tool in this course — KAPE, EZTools, Velociraptor, Volatility 3 — is superior to native Windows commands for its specific purpose. KAPE's two-pass collection with raw disk access captures locked files that native commands cannot touch. EZTools parse binary artifacts into structured timeline data that native commands cannot produce. Velociraptor provides enterprise-scale hunting that native commands cannot replicate. Volatility 3 analyzes memory structures that native commands cannot access.
# NATIVE: Complete process inventory with command lines and parent relationships
# This is the native equivalent of Volatility PsList + CmdLine + PsTree
$processes = Get-CimInstance Win32_Process | ForEach-Object {
$parent = Get-CimInstance Win32_Process -Filter "ProcessId=$($_.ParentProcessId)" -ErrorAction SilentlyContinue
$owner = try { $_.GetOwner() } catch { $null }
[PSCustomObject]@{
PID = $_.ProcessId
Name = $_.Name
PPID = $_.ParentProcessId
ParentName = if ($parent) { $parent.Name } else { "N/A (exited)" }
CommandLine = $_.CommandLine
ExecutablePath = $_.ExecutablePath
Owner = if ($owner) { "$($owner.Domain)\$($owner.User)" } else { "N/A" }
CreationDate = $_.CreationDate
SessionId = $_.SessionId
HandleCount = $_.HandleCount
ThreadCount = $_.ThreadCount
WorkingSetMB = [math]::Round($_.WorkingSetSize / 1MB, 1)
}
}
$processes | Export-Csv "C:\IR\Evidence\processes_native.csv" -NoTypeInformation
$processes | Sort-Object CreationDate -Descending | Format-Table PID, Name, PPID, ParentName, CreationDate -AutoSize | Out-String | Write-Host# CMD FALLBACK (if PowerShell is restricted or unavailable):
tasklist /v /fo csv > C:\IR\Evidence\tasklist.csv
wmic process get processid,parentprocessid,name,commandline,executablepath,creationdate /format:csv > C:\IR\Evidence\wmic_processes.csv# NATIVE: Active network connections mapped to owning process
# Equivalent of Volatility NetScan + Velociraptor connections artifact
$connections = Get-NetTCPConnection |
Where-Object { $_.State -eq 'Established' -or $_.State -eq 'Listen' } |
Select-Object LocalAddress, LocalPort, RemoteAddress, RemotePort, State,
@{N='ProcessName'; E={(Get-Process -Id $_.OwningProcess -EA 0).ProcessName}},
@{N='PID'; E={$_.OwningProcess}},
@{N='ProcessPath'; E={(Get-Process -Id $_.OwningProcess -EA 0).Path}},
CreationTime
$connections | Export-Csv "C:\IR\Evidence\connections_native.csv" -NoTypeInformation
# NATIVE: DNS cache — recently resolved domains (C2 indicator)
# DNS cache entries persist for minutes after the connection closes
# Even if netstat shows no active C2 connection, the DNS resolution
# for the C2 domain may still be cached here
Get-DnsClientCache | Select-Object Entry, RecordName, RecordType, Data, TimeToLive, Section |
Export-Csv "C:\IR\Evidence\dns_cache_native.csv" -NoTypeInformation
# NATIVE: ARP table — MAC-to-IP mappings for the local network
# Reveals which hosts this system has communicated with recently
Get-NetNeighbor | Where-Object { $_.State -ne 'Unreachable' } |
Select-Object IPAddress, LinkLayerAddress, State, InterfaceAlias |
Export-Csv "C:\IR\Evidence\arp_native.csv" -NoTypeInformation
# NATIVE: Network shares — check for attacker-created shares
Get-SmbShare | Select-Object Name, Path, Description, CurrentUsers |
Export-Csv "C:\IR\Evidence\shares_native.csv" -NoTypeInformation
# NATIVE: Active SMB sessions — who is connected to this system
Get-SmbSession -ErrorAction SilentlyContinue |
Select-Object ClientComputerName, ClientUserName, NumOpens |
Export-Csv "C:\IR\Evidence\smb_sessions_native.csv" -NoTypeInformation
# NATIVE: Open files on shares — what remote users are accessing
Get-SmbOpenFile -ErrorAction SilentlyContinue |
Select-Object ClientComputerName, ClientUserName, Path |
Export-Csv "C:\IR\Evidence\smb_openfiles_native.csv" -NoTypeInformation
# NATIVE: Listening ports — what services are exposed
Get-NetTCPConnection -State Listen |
Select-Object LocalAddress, LocalPort,
@{N='Process'; E={(Get-Process -Id $_.OwningProcess -EA 0).ProcessName}} |
Sort-Object LocalPort |
Export-Csv "C:\IR\Evidence\listening_ports_native.csv" -NoTypeInformation
# NATIVE: Firewall rules — check for attacker modifications
Get-NetFirewallRule | Where-Object { $_.Enabled -eq 'True' -and $_.Direction -eq 'Inbound' -and $_.Action -eq 'Allow' } |
Select-Object DisplayName, Profile, LocalPort, RemoteAddress |
Export-Csv "C:\IR\Evidence\firewall_inbound_native.csv" -NoTypeInformation# NATIVE: Scheduled tasks — most common persistence mechanism (T1053.005)
$tasks = Get-ScheduledTask | Where-Object { $_.State -ne 'Disabled' } | ForEach-Object {
$info = Get-ScheduledTaskInfo -TaskName $_.TaskName -TaskPath $_.TaskPath -ErrorAction SilentlyContinue
[PSCustomObject]@{
TaskName = $_.TaskName
TaskPath = $_.TaskPath
State = $_.State
Actions = ($_.Actions | ForEach-Object { "$($_.Execute) $($_.Arguments)" }) -join "; "
Triggers = ($_.Triggers | ForEach-Object { $_.GetType().Name }) -join "; "
RunAs = $_.Principal.UserId
LastRunTime = $info.LastRunTime
NextRunTime = $info.NextRunTime
}
}
$tasks | Export-Csv "C:\IR\Evidence\schtasks_native.csv" -NoTypeInformation
# NATIVE: Services — service persistence (T1543.003)
Get-CimInstance Win32_Service |
Select-Object Name, DisplayName, State, StartMode, PathName, StartName, Description |
Export-Csv "C:\IR\Evidence\services_native.csv" -NoTypeInformation
# NATIVE: Registry Run keys — autostart persistence (T1547.001)
$runKeys = @(
"HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\Run",
"HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\RunOnce",
"HKCU:\SOFTWARE\Microsoft\Windows\CurrentVersion\Run",
"HKCU:\SOFTWARE\Microsoft\Windows\CurrentVersion\RunOnce",
"HKLM:\SOFTWARE\WOW6432Node\Microsoft\Windows\CurrentVersion\Run"
)
$runResults = foreach ($key in $runKeys) {
if (Test-Path $key) {
$props = Get-ItemProperty $key -ErrorAction SilentlyContinue
$props.PSObject.Properties |
Where-Object { $_.Name -notin @('PSPath','PSParentPath','PSChildName','PSDrive','PSProvider') } |
ForEach-Object {
[PSCustomObject]@{ Key = $key; Name = $_.Name; Value = $_.Value }
}
}
}
$runResults | Export-Csv "C:\IR\Evidence\run_keys_native.csv" -NoTypeInformation
# NATIVE: Startup folder contents
$startupPaths = @(
"$env:APPDATA\Microsoft\Windows\Start Menu\Programs\Startup",
"C:\ProgramData\Microsoft\Windows\Start Menu\Programs\StartUp"
)
$startupFiles = foreach ($p in $startupPaths) {
Get-ChildItem $p -ErrorAction SilentlyContinue |
Select-Object Name, FullName, CreationTime, LastWriteTime, Length
}
$startupFiles | Export-Csv "C:\IR\Evidence\startup_folders_native.csv" -NoTypeInformation
# NATIVE: Local user accounts — check for attacker-created accounts (T1136.001)
Get-LocalUser | Select-Object Name, Enabled, LastLogon, PasswordLastSet, PasswordExpires,
Description, SID, @{N='PasswordNeverExpires'; E={$_.PasswordNeverExpires}} |
Export-Csv "C:\IR\Evidence\local_users_native.csv" -NoTypeInformation
# NATIVE: Local admin group — unauthorized privilege escalation
Get-LocalGroupMember -Group "Administrators" -ErrorAction SilentlyContinue |
Select-Object Name, ObjectClass, PrincipalSource |
Export-Csv "C:\IR\Evidence\local_admins_native.csv" -NoTypeInformation
# NATIVE: WMI event subscriptions — advanced persistence (T1546.003)
Get-WMIObject -Namespace root\Subscription -Class __EventFilter -ErrorAction SilentlyContinue |
Select-Object Name, Query, QueryLanguage |
Export-Csv "C:\IR\Evidence\wmi_filters_native.csv" -NoTypeInformation
Get-WMIObject -Namespace root\Subscription -Class CommandLineEventConsumer -ErrorAction SilentlyContinue |
Select-Object Name, CommandLineTemplate, ExecutablePath |
Export-Csv "C:\IR\Evidence\wmi_consumers_native.csv" -NoTypeInformation# NATIVE: High-value event IDs — the events that matter for IR
# Each query targets a specific investigation question
# 4624 — Successful logons: who logged in, when, from where, how
Get-WinEvent -FilterHashtable @{LogName='Security'; Id=4624; StartTime=(Get-Date).AddDays(-7)} -MaxEvents 2000 -EA 0 |
Select-Object TimeCreated,
@{N='User'; E={$_.Properties[5].Value}},
@{N='Domain'; E={$_.Properties[6].Value}},
@{N='LogonType'; E={$_.Properties[8].Value}},
@{N='LogonProcess'; E={$_.Properties[9].Value}},
@{N='SourceIP'; E={$_.Properties[18].Value}},
@{N='SourcePort'; E={$_.Properties[19].Value}} |
Export-Csv "C:\IR\Evidence\logons_native.csv" -NoTypeInformation
# LogonType 2=Interactive, 3=Network, 4=Batch, 5=Service, 7=Unlock,
# 10=RemoteInteractive(RDP), 11=CachedInteractive
# 4625 — Failed logons: brute force, password spray, credential stuffing
Get-WinEvent -FilterHashtable @{LogName='Security'; Id=4625; StartTime=(Get-Date).AddDays(-7)} -MaxEvents 2000 -EA 0 |
Select-Object TimeCreated,
@{N='User'; E={$_.Properties[5].Value}},
@{N='SourceIP'; E={$_.Properties[19].Value}},
@{N='SubStatus'; E={$_.Properties[9].Value}} |
Export-Csv "C:\IR\Evidence\failed_logons_native.csv" -NoTypeInformation
# 4688 — Process creation: what executed (requires audit policy)
Get-WinEvent -FilterHashtable @{LogName='Security'; Id=4688; StartTime=(Get-Date).AddDays(-1)} -MaxEvents 5000 -EA 0 |
Select-Object TimeCreated,
@{N='NewProcess'; E={$_.Properties[5].Value}},
@{N='CommandLine'; E={$_.Properties[8].Value}},
@{N='ParentProcess'; E={$_.Properties[13].Value}},
@{N='User'; E={$_.Properties[1].Value}} |
Export-Csv "C:\IR\Evidence\process_creation_native.csv" -NoTypeInformation
# 7045 — Service installed: persistence detection
Get-WinEvent -FilterHashtable @{LogName='System'; Id=7045} -MaxEvents 200 -EA 0 |
Select-Object TimeCreated,
@{N='ServiceName'; E={$_.Properties[0].Value}},
@{N='ImagePath'; E={$_.Properties[1].Value}},
@{N='ServiceType'; E={$_.Properties[2].Value}},
@{N='StartType'; E={$_.Properties[3].Value}},
@{N='AccountName'; E={$_.Properties[4].Value}} |
Export-Csv "C:\IR\Evidence\service_installs_native.csv" -NoTypeInformation
# 4104 — PowerShell ScriptBlock logging: attacker commands
Get-WinEvent -FilterHashtable @{LogName='Microsoft-Windows-PowerShell/Operational'; Id=4104} -MaxEvents 1000 -EA 0 |
Select-Object TimeCreated,
@{N='ScriptBlock'; E={$_.Properties[2].Value}},
@{N='Path'; E={$_.Properties[4].Value}} |
Export-Csv "C:\IR\Evidence\powershell_scripts_native.csv" -NoTypeInformation
# 1102 — Audit log cleared: anti-forensics indicator
Get-WinEvent -FilterHashtable @{LogName='Security'; Id=1102} -MaxEvents 50 -EA 0 |
Select-Object TimeCreated, @{N='ClearedBy'; E={$_.Properties[1].Value}} |
Export-Csv "C:\IR\Evidence\log_cleared_native.csv" -NoTypeInformation
# CRITICAL BRIDGE: Export raw .evtx files for EvtxECmd analysis
# This is the most important native command for connecting to the
# dedicated tool pipeline — wevtutil exports the binary .evtx files
# that EvtxECmd can parse with 700+ maps on the forensic workstation
$logsToExport = @(
'Security', 'System', 'Application',
'Microsoft-Windows-PowerShell/Operational',
'Microsoft-Windows-Sysmon/Operational',
'Microsoft-Windows-TaskScheduler/Operational',
'Microsoft-Windows-TerminalServices-RemoteConnectionManager/Operational',
'Microsoft-Windows-Windows Defender/Operational'
)
foreach ($log in $logsToExport) {
$safeName = $log -replace '[/\\ ]', '_'
wevtutil epl $log "C:\IR\Evidence\${safeName}.evtx" 2>$null
if ($?) { Write-Host " Exported: $log" -ForegroundColor Green }
}# Collect-Native.ps1 — Native IR collection requiring zero tool installation
# Include in the jump bag alongside KAPE and Velociraptor collector
# Usage: .\Collect-Native.ps1 -OutputDir "C:\IR\Evidence\NativeCollection"
param([string]$OutputDir = "C:\IR\Evidence\Native_$(hostname)_$(Get-Date -Format 'yyyyMMdd_HHmm')")
New-Item -ItemType Directory -Path $OutputDir -Force | Out-Null
$startTime = Get-Date
Write-Host "=== Native IR Collection — $(hostname) ===" -ForegroundColor Cyan
Write-Host "Output: $OutputDir" -ForegroundColor White
Write-Host "Started: $(Get-Date -Format 'yyyy-MM-dd HH:mm:ss UTC' -AsUTC)" -ForegroundColor White
# System context
systeminfo > "$OutputDir\systeminfo.txt"
whoami /all > "$OutputDir\whoami.txt"
ipconfig /all > "$OutputDir\ipconfig.txt"
# Processes (volatile — collect first)
Get-CimInstance Win32_Process | Select-Object ProcessId, ParentProcessId, Name, CommandLine, ExecutablePath, CreationDate |
Export-Csv "$OutputDir\processes.csv" -NoTypeInformation
Write-Host " [1/7] Processes: DONE" -ForegroundColor Green
# Network (volatile — collect second)
Get-NetTCPConnection | Where-Object { $_.State -ne 'Bound' } |
Select-Object LocalAddress, LocalPort, RemoteAddress, RemotePort, State, OwningProcess, CreationTime |
Export-Csv "$OutputDir\connections.csv" -NoTypeInformation
Get-DnsClientCache | Export-Csv "$OutputDir\dns_cache.csv" -NoTypeInformation
Get-NetNeighbor | Where-Object { $_.State -ne 'Unreachable' } | Export-Csv "$OutputDir\arp.csv" -NoTypeInformation
Write-Host " [2/7] Network: DONE" -ForegroundColor Green
# Persistence
Get-ScheduledTask | Where-Object { $_.State -ne 'Disabled' } |
Select-Object TaskName, TaskPath, State, @{N='Actions'; E={($_.Actions | ForEach-Object { "$($_.Execute) $($_.Arguments)" }) -join "; "}} |
Export-Csv "$OutputDir\scheduled_tasks.csv" -NoTypeInformation
Get-CimInstance Win32_Service | Select-Object Name, State, StartMode, PathName, StartName |
Export-Csv "$OutputDir\services.csv" -NoTypeInformation
Get-LocalUser | Export-Csv "$OutputDir\local_users.csv" -NoTypeInformation
Get-LocalGroupMember -Group "Administrators" -EA 0 | Export-Csv "$OutputDir\local_admins.csv" -NoTypeInformation
Write-Host " [3/7] Persistence: DONE" -ForegroundColor Green
# Registry Run keys
$runKeys = @("HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\Run","HKCU:\SOFTWARE\Microsoft\Windows\CurrentVersion\Run")
foreach ($key in $runKeys) {
if (Test-Path $key) { Get-ItemProperty $key | Out-File "$OutputDir\run_keys.txt" -Append }
}
Write-Host " [4/7] Registry: DONE" -ForegroundColor Green
# WMI persistence
Get-WMIObject -Namespace root\Subscription -Class __EventFilter -EA 0 | Out-File "$OutputDir\wmi_persistence.txt"
Get-WMIObject -Namespace root\Subscription -Class CommandLineEventConsumer -EA 0 | Out-File "$OutputDir\wmi_persistence.txt" -Append
Write-Host " [5/7] WMI: DONE" -ForegroundColor Green
# Firewall and shares
Get-NetFirewallRule | Where-Object { $_.Enabled -eq 'True' -and $_.Direction -eq 'Inbound' -and $_.Action -eq 'Allow' } |
Select-Object DisplayName, Profile | Export-Csv "$OutputDir\firewall_inbound.csv" -NoTypeInformation
Get-SmbShare | Export-Csv "$OutputDir\shares.csv" -NoTypeInformation
Write-Host " [6/7] Firewall/Shares: DONE" -ForegroundColor Green
# Event log export (bridge to EvtxECmd analysis)
$logs = @('Security','System','Application','Microsoft-Windows-PowerShell/Operational',
'Microsoft-Windows-Sysmon/Operational','Microsoft-Windows-TaskScheduler/Operational')
foreach ($log in $logs) {
$safe = $log -replace '[/\\ ]', '_'
wevtutil epl $log "$OutputDir\${safe}.evtx" 2>$null
}
Write-Host " [7/7] Event logs exported: DONE" -ForegroundColor Green
$elapsed = (Get-Date) - $startTime
Write-Host "`n=== Collection complete in $([math]::Round($elapsed.TotalSeconds))s ===" -ForegroundColor Cyan
Write-Host "Transfer $OutputDir to the forensic workstation." -ForegroundColor White
Write-Host "Parse .evtx files with EvtxECmd. Run Hayabusa for threat detection." -ForegroundColor WhiteBuild it: Run the native collection and compare to KAPE
Run Collect-Native
Run Collect-Native.ps1 on your forensic workstation. Then run KAPE with !SANS_Triage + !EZParser on the same system. Compare the outputs: what does KAPE collect that the native script does not? (Answer: $MFT, locked registry hives, Prefetch files, Amcache, ShimCache, browser artifacts, Jump Lists, LNK files, and parsed timeline output.) What does the native script collect that KAPE does not emphasize? (Answer: live process inventory with parent-child relationships, active network connections with process attribution, DNS cache, ARP table, SMB sessions, firewall rules.) The two approaches are complementary — not competing.
Investigate: Find the bridge between native and dedicated analysis
In the native collection output, find the exported .evtx files. Transfer them to a separate directory. Run EvtxECmd against them: EvtxECmd.exe -d "path\to\exported\evtx" --csv output --csvf parsed.csv. Open the parsed CSV in Timeline Explorer. Now run Hayabusa: hayabusa.exe csv-timeline -d "path\to\exported\evtx" -o hayabusa.csv -T -E --no-color. Open the Hayabusa output in Timeline Explorer. You now have full EvtxECmd parsing (700+ maps) and full Hayabusa threat detection (4,000+ Sigma rules) against event logs that were collected using nothing but the built-in wevtutil command. This is the bridge.
Beyond this investigation
The techniques taught in this subsection apply beyond the specific scenario presented here. The same evidence sources, tools, and analytical methods are used across ransomware, BEC, insider threat, and APT investigations — the context changes but the methodology is consistent.
You discover evidence that the attacker has been in the environment for 90 days. The CISO asks: 'Why did our SOC not detect this sooner?' How do you answer constructively?
Answer with facts, not defensiveness. 'The attacker used [specific techniques] that our current detection rules do not cover. The investigation identified [N] detection gaps — [list the specific ATT&CK techniques that were not detected]. The IR-to-DE handoff includes these gaps as detection engineering sprint items. Estimated time to close: [N weeks].' This answer is honest (we missed it), specific (here is what we missed and why), and forward-looking (here is how we fix it). The PIR action items transform the detection failure into a measurable improvement program.