The Shell You Triage With
Is Also The Shell You Collect With.
Using PowerShell as an evidence-collection tool: core IR cmdlets, remote collection across a fleet, and script block logging setup. See Suspicious PowerShell for triaging a PowerShell-based alert, which is a different question than the one this guide answers.
Core IR Cmdlets
The commands that come up in almost every collection run, regardless of what the investigation is actually about.
Events, Processes, Connections, Persistence
Get-WinEvent -FilterHashtable @{LogName='Security'; Id=4624,4625; StartTime=(Get-Date).AddHours(-24)} ├── Far faster than the deprecated Get-EventLog — FilterHashtable filters at the provider level, not after loading every event into memory └── -ComputerName targets a remote host directly, given WinRM access and the right permissions Get-Process | Select-Object Name, Id, Path, StartTime Get-CimInstance Win32_Process | Select-Object Name, ProcessId, ParentProcessId, CommandLine ├── Get-CimInstance shows the full command line and parent PID; Get-Process alone does not └── The parent-child relationship is often the fastest way to spot a LOLBIN abuse chain by hand Get-NetTCPConnection | Where-Object State -eq 'Established' ├── The modern replacement for netstat, returns structured objects instead of text to parse └── Pipe to a process lookup (OwningProcess maps to a PID) to tie a connection back to its process Get-ScheduledTask | Where-Object State -ne 'Disabled' Get-Service | Where-Object Status -eq 'Running' // both are common persistence checks, same rationale as the manual-host-triage playbook's persistence sections
Remote Collection
The same cmdlets, run against a fleet instead of one host.
CMDLET
Invoke-Command
One script block, many hosts, in parallel
Invoke-Command -ComputerName $hosts -ScriptBlock { ... } runs a script block against one or many remote hosts at once. This is the core mechanism for a fleet-wide IR sweep.CMDLET
New-PSSession / Enter-PSSession
For an extended interactive investigation on one host
A persistent remote session, useful when the work on a single host is going to take more than one command, rather than a one-shot collection.
PREREQUISITE
WinRM Access
Fails as a timeout, not a clear permissions error
The target needs WinRM enabled, and the investigator's account needs local Administrators membership or an explicit WinRM permission on that host. Misconfiguration shows up as a connection timeout, not an obvious access-denied message.
Script Block Logging Setup
This has to be turned on before the incident, not during it.
GPO
Script Block Logging
What actually populates Event ID 4104
Computer Configuration > Administrative Templates > Windows Components > Windows PowerShell > Turn on PowerShell Script Block Logging. This is what puts decoded script content into Event ID 4104.
GPO
Module Logging
A separate setting, useful alongside 4104
Module logging records pipeline execution details as Event ID 4103. It's a separate GPO setting from script block logging, and worth enabling alongside it, not instead of it.
SCOPE
Transcription
Valuable, but scope it deliberately
Turn on PowerShell Transcription writes a full session transcript to a specified directory. It generates significant log volume, so enable it deliberately with a retention plan, not fleet-wide by default.
Common Pitfalls
Mistakes made under time pressure during an active collection run.
PITFALL
Running Broad Collection Without Confirming Impact
A large recursive scan at the wrong moment
A broad
Get-ChildItem -Recurse across a large file share during an active incident can affect host performance at exactly the moment it can least afford to.PITFALL
PowerShell Version Differences
5.1 and 7+ don't share every cmdlet
Windows PowerShell 5.1 and PowerShell 7+ have different default cmdlet availability and module paths. A script that runs cleanly in one may not run at all in the other.
PITFALL
Execution Policy Blocking Collection
A one-time bypass, not a permanent policy change
Restricted or AllSigned execution policy blocks an ad hoc IR script outright.
-ExecutionPolicy Bypass on the invocation itself is usually the right call for a one-time collection run, not editing the host's policy permanently.PITFALL
An Empty Result Isn't Proof Of Nothing
Same caveat as the ransomware and manual-triage playbooks
Get-WinEvent needs the Security log's audit policy actually configured to return anything. An empty result on a default-audit-policy host is a coverage gap, not evidence that nothing happened.