PowerShell script block logs live in Applications and Services Logs → Microsoft → Windows → PowerShell → Operational, as event 4104. They’re only complete if script block logging is turned on. To export them:
wevtutil epl "Microsoft-Windows-PowerShell/Operational" C:\logs\powershell.evtx
PowerShell 7 is a separate product with a separate channel, PowerShellCore/Operational, and its own policy setting.
If an attacker touched a Windows box, odds are PowerShell was involved. Script block logging records the code that actually ran, often after the obfuscation layers have been peeled off. Prime Core has 663 detection rules for PowerShell logs, mapped to 417 MITRE ATT&CK techniques. They cover malicious PowerShell use (T1059.001), obfuscation (T1027) and download cradles that pull in tools (T1105).
Before you start
Is script block logging on?
reg query "HKLM\SOFTWARE\Policies\Microsoft\Windows\PowerShell\ScriptBlockLogging"
EnableScriptBlockLogging set to 0x1 means yes. If the key doesn’t exist, it’s off. Even then, Windows PowerShell 5.1 still logs script blocks it considers suspicious, as 4104 events at Warning level. So you may find some events. Just don’t mistake them for the full picture.
Turning it on helps from now on, not for what already happened. Use the Group Policy setting Administrative Templates → Windows Components → Windows PowerShell → Turn on PowerShell Script Block Logging, or set the registry value directly:
reg add "HKLM\SOFTWARE\Policies\Microsoft\Windows\PowerShell\ScriptBlockLogging" /v EnableScriptBlockLogging /t REG_DWORD /d 1 /f
PowerShell 7 reads its own policy key under HKLM\SOFTWARE\Policies\Microsoft\PowerShellCore. If it was installed from a zip rather than the MSI, its event channel may not be registered until you run RegisterManifest.ps1 from $PSHOME.
Expect volume. Every script and module that runs ends up in the log. Raise the channel’s maximum size, or you’ll keep only a few hours.
Expect secrets. Admin scripts sometimes carry passwords and API keys in plain text, and script block logging records them faithfully. Keep that in mind before this file goes anywhere, and read the LogTotal section below.
Export the logs
In Event Viewer, right-click Operational under PowerShell and choose Save All Events As… From the command line:
:: script blocks only
wevtutil epl "Microsoft-Windows-PowerShell/Operational" C:\logs\ps_4104.evtx /q:"*[System[(EventID=4104)]]"
:: PowerShell 7
wevtutil epl "PowerShellCore/Operational" C:\logs\pwsh.evtx
:: the classic "Windows PowerShell" log: engine start events with the host command line
wevtutil epl "Windows PowerShell" C:\logs\windows_powershell.evtx
That last one is easy to forget, and it’s worth grabbing. Event 400 records each engine start, including the engine version. An EngineVersion of 2.0 on a modern system usually means someone deliberately downgraded to dodge script block logging.
Upload and review in LogTotal
LogTotal reads EVTX natively. One thing to know first: LogTotal doesn’t sanitize EVTX files yet. [PROOF: confirm which formats the sanitize step covers today.] With PowerShell logs, that matters more than usual, because of the secrets mentioned above. Use EVTX uploads freely for test machines. For production hosts, get a yes from whoever owns data handling first.
- Upload. Open logtotal.com and drop in the file. [PROOF: upload screen, size limit]
- Review. [PROOF: what the results screen shows for PowerShell data]
What this looks like on real data. We used [PROOF: sample source, e.g. a test VM with script block logging on, after running an encoded download cradle and a harmless AMSI-tampering test string]. LogTotal flagged [PROOF: actual findings]. [PROOF: link to the sample file]
When it goes wrong
| Symptom | Likely cause | Fix |
|---|---|---|
| No 4104 events at all | Script block logging is off, and nothing looked suspicious | Enable it for the future; check the Windows PowerShell log for what you can still get |
| Only a handful of 4104 events, all Warning | Logging is off; you’re seeing automatic suspicious-block logging | Same as above |
| PowerShellCore/Operational not found | PowerShell 7 isn’t installed, or its manifest isn’t registered | Run RegisterManifest.ps1 from $PSHOME |
| 4104 text is unreadable ciphertext | Protected Event Logging is on | You need the decryption certificate |
| Log covers only a few hours | Default size, high volume | Raise the channel’s maximum size |
FAQ
Does script block logging catch obfuscated code?
Largely, yes. It records script blocks as they’re compiled. When obfuscated code builds and runs the next stage, that stage gets logged as its own block, often in readable form.
What’s the difference from transcription?
Transcription writes text files of session input and output to a folder. Script block logging records the code itself in the event log. They complement each other, and both are worth having.