PowerShell Script Block Logging
PowerShell Script Block Logging
One-liner: A Windows logging feature (Event ID 4104) that records the full content of PowerShell scripts and commands as they execute, even if obfuscated or encoded.
🎯 What Is It?
PowerShell Script Block Logging is a security auditing feature that captures the actual code executed by PowerShell, regardless of how it was invoked. This is critical for threat hunting because attackers frequently use PowerShell for:
- Downloading and executing malware
- Lateral Movement
- Credential Dumping
- Command and Control (C2) communication
Key Benefit: Even heavily obfuscated or Base64-encoded scripts are logged in their deobfuscated form after PowerShell interprets them.
🔬 How It Works
What Gets Logged
Event ID: 4104
Channel: Microsoft-Windows-PowerShell/Operational
| Field | Description |
|---|---|
ScriptBlockText |
The actual PowerShell code executed |
ScriptBlockId |
Unique identifier for the script block |
Path |
Script file path (if from file) |
MessageNumber |
Part number if script spans multiple events |
MessageTotal |
Total parts for large scripts |
Example Log Entry
<Event>
<System>
<EventID>4104</EventID>
<Channel>Microsoft-Windows-PowerShell/Operational</Channel>
</System>
<EventData>
<Data Name="ScriptBlockText">
Invoke-Mimikatz -DumpCreds
</Data>
<Data Name="Path">C:\Users\attacker\evil.ps1</Data>
</EventData>
</Event>
Why It's Powerful
Attacker runs:
powershell -enc SQBuAHYAbwBrAGUALQBNAGkAbQBpAGsAYQB0AHoA...
Script Block Logging captures:
Invoke-Mimikatz -DumpCreds
The decoded command is logged, not the encoded blob!
⚙️ Enabling Script Block Logging
Via Group Policy
Computer Configuration
→ Administrative Templates
→ Windows Components
→ Windows PowerShell
→ Turn on PowerShell Script Block Logging
Via Registry
# Enable Script Block Logging
New-Item -Path "HKLM:\SOFTWARE\Policies\Microsoft\Windows\PowerShell\ScriptBlockLogging" -Force
Set-ItemProperty -Path "HKLM:\SOFTWARE\Policies\Microsoft\Windows\PowerShell\ScriptBlockLogging" -Name "EnableScriptBlockLogging" -Value 1
PowerShell v5+ Automatic Logging
PowerShell 5.0+ automatically logs "suspicious" script blocks even without explicit configuration when:
- Script contains known malicious patterns
- Script is heavily obfuscated
🕵️ Detection & Hunting
Suspicious Strings to Hunt
From the THM Threat Hunting Foothold room:
| String | Indicates |
|---|---|
Invoke-Expression / IEX |
Dynamic code execution |
-enc / -EncodedCommand |
Base64 encoded commands |
WebRequest / DownloadString |
Downloading remote payloads |
Invoke-Mimikatz |
Credential theft |
Invoke-Empire |
Empire C2 framework |
bypass |
Execution policy bypass |
-nop / -noprofile |
Stealth execution |
FromBase64String |
Decoding payloads |
KQL Query Example
# Hunt unusual PowerShell execution
host.name: WKSTN-* AND winlog.event_id: 4104
Filtering Noise
# Exclude common benign patterns
host.name: WKSTN-* AND winlog.event_id: 4104
AND NOT powershell.file.script_block_text: "Set-StrictMode"
Key Fields to Add as Columns
winlog.computer_namewinlog.user.namepowershell.file.script_block_text
📊 Related PowerShell Logging Types
| Log Type | Event ID | What It Captures |
|---|---|---|
| Script Block Logging | 4104 | Actual script content (deobfuscated) |
| Module Logging | 4103 | Pipeline execution details |
| Transcription | N/A | Full session transcript to file |
| Command History | N/A | ConsoleHost_history.txt file |
🎤 Interview Angles
Common Questions
- "How do you detect malicious PowerShell activity?"
- "What's the advantage of Script Block Logging over command-line logging?"
- "How would you hunt for encoded PowerShell commands?"
STAR Story
Situation: Alerts were triggering on encoded PowerShell commands but we couldn't determine their actual intent.
Task: Improve visibility into PowerShell execution for threat hunting.
Action: Enabled Script Block Logging via GPO across all endpoints. Created detection rules for known malicious patterns (Invoke-Mimikatz, Empire signatures). Built a Kibana dashboard filtering Event ID 4104 for suspicious keywords.
Result: Detected Empire C2 agent execution within 24 hours of deployment. The deobfuscated logs showedInvoke-Empireclearly despite the encoded command line.
✅ Best Practices
- Enable Script Block Logging on all endpoints via GPO
- Forward logs to SIEM for centralized analysis
- Create baseline of normal PowerShell usage to reduce false positives
- Monitor for log clearing attempts (Event ID 1102)
- Combine with Sysmon for full visibility
❌ Common Misconceptions
- "Command-line logging is enough" — Only captures the initial command, not the deobfuscated content
- "Attackers can bypass it" — While possible, it's difficult and leaves other traces
- "It generates too much noise" — Proper filtering makes it manageable
🔗 Related Concepts
- Windows Event Logs
- Sysmon
- Threat Hunting
- Command and Control (C2)
- Living off the Land (LOLBAS)
- Defense Evasion
📚 References
- Microsoft: About Logging Windows PowerShell
- SANS: PowerShell Logging Cheat Sheet
- FireEye: Greater Visibility Through PowerShell Logging