Last active
August 21, 2026 00:40
-
-
Save dancwilliams/d374f9f0edfc7854694cae6adbce0293 to your computer and use it in GitHub Desktop.
Triage PS1
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| # 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