Skip to content

Instantly share code, notes, and snippets.

@dancwilliams
Last active August 21, 2026 00:40
Show Gist options
  • Select an option

  • Save dancwilliams/d374f9f0edfc7854694cae6adbce0293 to your computer and use it in GitHub Desktop.

Select an option

Save dancwilliams/d374f9f0edfc7854694cae6adbce0293 to your computer and use it in GitHub Desktop.
Triage PS1
# Triage.ps1 — read-only Windows endpoint triage. Run as Administrator:
# Set-ExecutionPolicy -Scope Process Bypass -Force; .\Triage.ps1
# Writes everything to Desktop\triage-<host>-<date>\ ; zip that folder and send it over.
$ErrorActionPreference = 'SilentlyContinue'
$out = "$env:USERPROFILE\Desktop\triage-$env:COMPUTERNAME-$(Get-Date -f yyyyMMdd-HHmm)"
New-Item -ItemType Directory -Path $out -Force | Out-Null
function Save($name, $obj) { $obj | Format-List * | Out-String -Width 300 | Set-Content "$out\$name.txt" }
function SaveT($name, $obj) { $obj | Format-Table -AutoSize | Out-String -Width 300 | Set-Content "$out\$name.txt" }
# 1. Live network: every connection/listener with owning process, path, signature
$procs = Get-Process | Select-Object Id, ProcessName, Path, @{n='Sig';e={(Get-AuthenticodeSignature $_.Path).Status}}, @{n='Company';e={$_.Company}}
$pmap = @{}; $procs | ForEach-Object { $pmap[$_.Id] = $_ }
SaveT net-connections (Get-NetTCPConnection | Where-Object State -in 'Established','Listen' |
Select-Object LocalAddress, LocalPort, RemoteAddress, RemotePort, State, OwningProcess,
@{n='Proc';e={$pmap[$_.OwningProcess].ProcessName}}, @{n='Path';e={$pmap[$_.OwningProcess].Path}}, @{n='Sig';e={$pmap[$_.OwningProcess].Sig}} |
Sort-Object State, RemoteAddress)
SaveT net-udp (Get-NetUDPEndpoint | Select-Object LocalAddress, LocalPort, OwningProcess, @{n='Proc';e={$pmap[$_.OwningProcess].ProcessName}})
SaveT dns-cache (Get-DnsClientCache | Select-Object Entry, Data, TimeToLive | Sort-Object Entry -Unique)
SaveT proxy (Get-ItemProperty 'HKCU:\Software\Microsoft\Windows\CurrentVersion\Internet Settings' | Select-Object ProxyEnable, ProxyServer, AutoConfigURL)
Copy-Item "$env:SystemRoot\System32\drivers\etc\hosts" "$out\hosts.txt"
SaveT dns-servers (Get-DnsClientServerAddress | Where-Object ServerAddresses | Select-Object InterfaceAlias, ServerAddresses)
# 2. Processes: unsigned / odd-location first
SaveT processes (Get-CimInstance Win32_Process | Select-Object ProcessId, ParentProcessId, Name, ExecutablePath, CommandLine |
Sort-Object @{e={$_.ExecutablePath -match '\\Windows\\|\\Program Files'}}, Name)
SaveT processes-unsigned ($procs | Where-Object { $_.Path -and $_.Sig -ne 'Valid' } | Select-Object Id, ProcessName, Path, Sig, Company)
SaveT processes-userdirs ($procs | Where-Object { $_.Path -match '\\AppData\\|\\Temp\\|\\Users\\Public|\\ProgramData\\' } | Select-Object Id, ProcessName, Path, Sig)
# 3. Persistence
$runKeys = 'HKLM:\Software\Microsoft\Windows\CurrentVersion\Run','HKLM:\Software\Microsoft\Windows\CurrentVersion\RunOnce',
'HKLM:\Software\WOW6432Node\Microsoft\Windows\CurrentVersion\Run','HKCU:\Software\Microsoft\Windows\CurrentVersion\Run',
'HKCU:\Software\Microsoft\Windows\CurrentVersion\RunOnce','HKLM:\Software\Microsoft\Windows\CurrentVersion\Explorer\Shell Folders',
'HKCU:\Software\Microsoft\Windows NT\CurrentVersion\Windows','HKLM:\Software\Microsoft\Windows NT\CurrentVersion\Winlogon',
'HKLM:\Software\Microsoft\Windows NT\CurrentVersion\Image File Execution Options','HKLM:\System\CurrentControlSet\Control\Session Manager'
Save reg-autoruns ($runKeys | ForEach-Object { [pscustomobject]@{Key=$_; Values=(Get-ItemProperty $_ | Select-Object * -ExcludeProperty PS* | Out-String)} })
SaveT startup-folders (Get-ChildItem "$env:APPDATA\Microsoft\Windows\Start Menu\Programs\Startup","$env:ProgramData\Microsoft\Windows\Start Menu\Programs\Startup" -Force | Select-Object FullName, LastWriteTime)
SaveT scheduled-tasks (Get-ScheduledTask | Where-Object { $_.State -ne 'Disabled' -and $_.Author -notmatch '^Microsoft|^\$\(' } |
Select-Object TaskName, TaskPath, Author, @{n='Exec';e={($_.Actions | ForEach-Object { "$($_.Execute) $($_.Arguments)" }) -join ' | '}}, Date)
SaveT services-nonms (Get-CimInstance Win32_Service | Where-Object { $_.PathName -notmatch '\\Windows\\' } | Select-Object Name, State, StartMode, PathName, StartName)
SaveT wmi-subscriptions (Get-CimInstance -Namespace root\subscription -ClassName __EventConsumer | Select-Object Name, CommandLineTemplate, ScriptText)
SaveT scheduled-tasks-all (Get-ScheduledTask | Select-Object TaskName, TaskPath, State, Author)
# 4. Recent changes
$cut = (Get-Date).AddDays(-30)
SaveT recent-exe (Get-ChildItem "$env:USERPROFILE","$env:ProgramData","$env:SystemRoot\Temp","C:\Users\Public" -Recurse -Force -Include *.exe,*.dll,*.ps1,*.vbs,*.js,*.bat,*.cmd,*.scr,*.lnk,*.msi,*.hta |
Where-Object { $_.LastWriteTime -gt $cut -and $_.FullName -notmatch '\\node_modules\\|\\.git\\' } | Select-Object FullName, Length, LastWriteTime | Sort-Object LastWriteTime -Descending)
SaveT installed-programs (Get-ItemProperty 'HKLM:\Software\Microsoft\Windows\CurrentVersion\Uninstall\*','HKLM:\Software\WOW6432Node\Microsoft\Windows\CurrentVersion\Uninstall\*','HKCU:\Software\Microsoft\Windows\CurrentVersion\Uninstall\*' |
Where-Object DisplayName | Select-Object DisplayName, Publisher, InstallDate, InstallLocation | Sort-Object InstallDate -Descending)
SaveT local-users (Get-LocalUser | Select-Object Name, Enabled, LastLogon, PasswordLastSet)
SaveT local-admins (Get-LocalGroupMember Administrators)
# 5. Browser extensions (Chrome/Edge) — name + id, so you can look them up
$ext = foreach ($b in @{Chrome="$env:LOCALAPPDATA\Google\Chrome\User Data"; Edge="$env:LOCALAPPDATA\Microsoft\Edge\User Data"}.GetEnumerator()) {
Get-ChildItem "$($b.Value)\*\Extensions\*\*\manifest.json" | ForEach-Object {
$m = Get-Content $_ -Raw | ConvertFrom-Json
[pscustomobject]@{Browser=$b.Key; Id=$_.Directory.Parent.Name; Name=$m.name; Version=$m.version; Perms=($m.permissions -join ',')}
}
}
SaveT browser-extensions $ext
# 6. Defender: history, exclusions, status
Save defender-status (Get-MpComputerStatus | Select-Object AMServiceEnabled, RealTimeProtectionEnabled, AntivirusSignatureLastUpdated, QuickScanEndTime, FullScanEndTime, IsTamperProtected)
Save defender-prefs (Get-MpPreference | Select-Object Exclusion*, DisableRealtimeMonitoring, DisableBehaviorMonitoring, MAPSReporting, SubmitSamplesConsent)
SaveT defender-threats (Get-MpThreatDetection | Select-Object InitialDetectionTime, ThreatID, ProcessName, Resources, ActionSuccess)
SaveT defender-events (Get-WinEvent -FilterHashtable @{LogName='Microsoft-Windows-Windows Defender/Operational'; Id=1006,1007,1008,1015,1116,1117,1118,1119,5001,5004,5007,5010,5012} -MaxEvents 200 | Select-Object TimeCreated, Id, Message)
# 7. Event logs: new services, logons, powershell, cleared logs
SaveT evt-system (Get-WinEvent -FilterHashtable @{LogName='System'; Id=7045,7034,104,1074; StartTime=$cut} -MaxEvents 300 | Select-Object TimeCreated, Id, Message)
SaveT evt-security (Get-WinEvent -FilterHashtable @{LogName='Security'; Id=4720,4728,4732,4624,4625,4648,1102; StartTime=$cut} -MaxEvents 500 |
Select-Object TimeCreated, Id, @{n='Msg';e={($_.Message -split "`n")[0]}}, @{n='Acct';e={$_.Properties[5].Value}}, @{n='Type';e={$_.Properties[8].Value}})
SaveT evt-powershell (Get-WinEvent -FilterHashtable @{LogName='Microsoft-Windows-PowerShell/Operational'; Id=4104; StartTime=$cut} -MaxEvents 300 | Select-Object TimeCreated, @{n='Script';e={$_.Message.Substring(0,[Math]::Min(500,$_.Message.Length))}})
# 8. Hashes of everything currently running + non-Microsoft autostart binaries -> paste into VirusTotal
$paths = @($procs.Path) + @((Get-CimInstance Win32_Service).PathName -replace '^"?([^"]+?\.exe).*','$1') | Where-Object { $_ -and (Test-Path $_) } | Sort-Object -Unique
SaveT hashes ($paths | ForEach-Object { $h = Get-FileHash $_ -Algorithm SHA256; [pscustomobject]@{SHA256=$h.Hash; Path=$_; Sig=(Get-AuthenticodeSignature $_).Status} } | Sort-Object Sig)
Compress-Archive -Path $out -DestinationPath "$out.zip" -Force
Write-Host "Done -> $out.zip"
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment