PowerShell Event ID 4104: powershell script block logged
What PowerShell Event ID 4104 (powershell script block logged) means, the fields to check, what is normal and what is suspicious, with PowerShell and KQL queries to find it.
Event ID 4104 in the PowerShell Operational log records the actual script code PowerShell ran, after it was decoded. That makes it one of the best defences against obfuscated PowerShell: base64 and string tricks are undone before the code is logged.
The fields that matter
| Field | What it tells you |
|---|---|
| ScriptBlock Text | The code that ran. Long scripts are split across several events. |
| ScriptBlock ID | Joins the parts of one script. |
| Path | The script file, if it came from one. |
| Level | Warning means PowerShell itself judged the code suspicious, which it logs even when full logging is off. |
What is normal
Admin scripts, management agents and modules loading, which can be a very large volume.
When PowerShell Event ID 4104 is suspicious
- Download and run patterns:
IEX,Invoke-Expression,DownloadString,Net.WebClient. FromBase64String,-bxorand character-code tricks used to hide strings.- AMSI bypass attempts such as
AmsiUtilsoramsiInitFailed. - Credential tools and reflective loading:
Invoke-Mimikatz,[Reflection.Assembly]::Load. - Any event at Warning level.
Common false positive: Security products and deployment tools run scripts that contain many of these words. Filter by the script path or the parent process.
Find PowerShell Event ID 4104 with PowerShell
Get-WinEvent -FilterHashtable @{LogName='Microsoft-Windows-PowerShell/Operational'; Id=4104; StartTime=(Get-Date).AddDays(-7)} -MaxEvents 50 |
ForEach-Object {
$d = [ordered]@{ Time = $_.TimeCreated; Computer = $_.MachineName }
([xml]$_.ToXml()).Event.EventData.Data | ForEach-Object { $d[$_.Name] = $_.'#text' }
[pscustomobject]$d
} | Format-List
Microsoft Sentinel (KQL)
Event
| where TimeGenerated > ago(7d) and EventLog == "Microsoft-Windows-PowerShell/Operational" and EventID == 4104
| project TimeGenerated, Computer, RenderedDescription, EventData
| order by TimeGenerated desc
Related events
- Event ID 4688: New process created
- Sysmon Event ID 1: process creation
- PowerShell Event ID 4103: PowerShell module logging
FAQ
How do I turn on script block logging?
Group Policy: Administrative Templates > Windows Components > Windows PowerShell > Turn on PowerShell Script Block Logging. The events go to Microsoft-Windows-PowerShell/Operational.
Why do I see some 4104 events even without the policy?
PowerShell 5 and later log script blocks that match a list of suspicious terms at Warning level automatically.
Windows Event Triage reads a CSV, EVTX-to-JSON or XML export in your browser and flags brute force, new admins, suspicious services and log clearing.
IOC Triage, our free browser extension: right-click it for a verdict from 15 threat-intel sources, then copy a ready ticket note.