PowerShell script block logging (4104)
When enabled, Windows records the actual text of every PowerShell block before it runs, after deobfuscation. It is the single highest-value log on a Windows host and it is off by default.
where it lives
C:\Windows\System32\winevt\Logs\Microsoft-Windows-PowerShell%4Operational.evtxEvent 4104 carries the script text. 4103 carries pipeline execution detail.
SOFTWARE\Policies\Microsoft\Windows\PowerShell\ScriptBlockLoggingEnableScriptBlockLogging must be 1. Check this before concluding anything from an absence.
what it proves
- The literal text of what was executed, after the layers of encoding are stripped
- Base64 and compressed payloads in their decoded form, which is why obfuscation does not defeat it
- The order of execution, and which blocks came from a file rather than the console
what it does not prove
- Anything at all when the policy is off, which is the default. An empty log is a configuration finding, not an absence of activity
- That the script succeeded, only that it was compiled and run
- Activity from a downgraded session: an attacker invoking PowerShell 2.0 avoids this entirely, which is why version 2 should be removed
parsing it
EvtxECmd (Eric Zimmerman)ChainsawHayabusaGet-WinEvent
tampering and anti-forensics
Clearing this log raises 104 in the same channel. The more common evasion is never triggering it: PowerShell 2.0 downgrade, or using a .NET runspace directly rather than powershell.exe.
how long it survives
Rolls by size, 15MB by default. On an administrative workstation that can be days.
where this comes from
read next
Find obfuscated or downloading script blocks without drowning in administrative PowerShell.
The three queries, what each field in the results means, and the benign activity each one will return, are part of a Pro membership.