POWERSHELL LOGGING
How to enable and read PowerShell logging for detection and forensics. Three independent features: Module Logging, Script Block Logging, and Transcription. All configured via Group Policy or registry; events land in the "Microsoft-Windows-PowerShell/Operational" and "Windows PowerShell" logs.
KEY EVENT IDS#
Log: Microsoft-Windows-PowerShell/Operational
4103 Module logging - pipeline execution details (command invocation)
4104 Script block logging - the actual code that was run (deobfuscated)
Level "Warning" (vs Verbose) marks blocks the engine flagged as
suspicious. 4104 is the single most useful PowerShell event.
4105 Script block execution started
4106 Script block execution stopped
Log: Windows PowerShell (classic)
400 Engine state changed to Available (a session/host started)
HostName field shows the host (powershell.exe, ISE, custom host).
403 Engine state changed to Stopped (session ended)
500/501 Command started / stopped (older)
600 Provider lifecycle (e.g. "Provider Registry started")
WHERE EACH IS CONFIGURED (GPO)#
Computer/User Configuration >
Administrative Templates > Windows Components > Windows PowerShell
"Turn on Module Logging" -> Event 4103
Specify module names (use * for all).
"Turn on PowerShell Script Block Logging" -> Event 4104
Optional: "Log script block invocation start/stop" -> 4105/4106.
"Turn on PowerShell Transcription" -> writes .txt transcripts
Set output directory (central share recommended) and
"Include invocation headers".
REGISTRY EQUIVALENTS (read to verify config)#
Script Block Logging:
HKLM\SOFTWARE\Policies\Microsoft\Windows\PowerShell\ScriptBlockLogging
EnableScriptBlockLogging = 1
EnableScriptBlockInvocationLogging = 1 (optional, 4105/4106)
Module Logging:
HKLM\SOFTWARE\Policies\Microsoft\Windows\PowerShell\ModuleLogging
EnableModuleLogging = 1
...\ModuleLogging\ModuleNames (value "*" = all modules)
Transcription:
HKLM\SOFTWARE\Policies\Microsoft\Windows\PowerShell\Transcription
EnableTranscripting = 1
OutputDirectory = \\server\share\pstranscripts
EnableInvocationHeader = 1
WHAT EACH FEATURE GIVES YOU#
Script Block Logging (4104)
- Records the full text of script blocks AS EXECUTED, after the engine
has deobfuscated/decoded them. Catches -EncodedCommand payloads,
Invoke-Expression content, and in-memory execution.
- Best single source for "what did the attacker actually run".
Module Logging (4103)
- Logs pipeline invocation and parameter binding per command. More verbose,
noisier, and does not always capture obfuscated input as cleanly as 4104.
Transcription
- Plain-text input/output transcript of interactive and script sessions,
one file per session, with timestamps and host info. Good for human
review and for capturing command OUTPUT (which 4104 does not).
Note: PowerShell v2 lacks these features. "powershell -version 2" is a known
downgrade/evasion attempt -- alert on it and consider removing the v2 engine
(Windows optional feature "Windows PowerShell 2.0").
READING THE LOGS (read-only)#
# All script blocks in the last day
Get-WinEvent -FilterHashtable @{
LogName='Microsoft-Windows-PowerShell/Operational'; Id=4104;
StartTime=(Get-Date).AddDays(-1) } |
Select-Object TimeCreated, @{n='Script';e={$_.Message}}
# Only blocks flagged suspicious (Warning level)
Get-WinEvent -FilterHashtable @{
LogName='Microsoft-Windows-PowerShell/Operational'; Id=4104; Level=3 }
# Classic engine starts with host name
Get-WinEvent -FilterHashtable @{LogName='Windows PowerShell'; Id=400} |
Select-Object TimeCreated, Message
DETECTION IDEAS (strings to hunt in 4104/transcripts)#
-enc / -EncodedCommand / -e (base64 command) FromBase64String (inline decode) IEX / Invoke-Expression (dynamic execution) DownloadString / DownloadData / Invoke-WebRequest / Net.WebClient -nop / -noprofile -w hidden / -ExecutionPolicy Bypass [Reflection.Assembly]::Load / System.Reflection (in-memory loading) powershell -version 2 (engine downgrade) Always tune against your admin baseline before alerting.
POWERSHELL LOGGING CHEATSHEET
=============================
How to enable and read PowerShell logging for detection and forensics.
Three independent features: Module Logging, Script Block Logging, and
Transcription. All configured via Group Policy or registry; events land in
the "Microsoft-Windows-PowerShell/Operational" and "Windows PowerShell" logs.
KEY EVENT IDS
-------------
Log: Microsoft-Windows-PowerShell/Operational
4103 Module logging - pipeline execution details (command invocation)
4104 Script block logging - the actual code that was run (deobfuscated)
Level "Warning" (vs Verbose) marks blocks the engine flagged as
suspicious. 4104 is the single most useful PowerShell event.
4105 Script block execution started
4106 Script block execution stopped
Log: Windows PowerShell (classic)
400 Engine state changed to Available (a session/host started)
HostName field shows the host (powershell.exe, ISE, custom host).
403 Engine state changed to Stopped (session ended)
500/501 Command started / stopped (older)
600 Provider lifecycle (e.g. "Provider Registry started")
WHERE EACH IS CONFIGURED (GPO)
------------------------------
Computer/User Configuration >
Administrative Templates > Windows Components > Windows PowerShell
"Turn on Module Logging" -> Event 4103
Specify module names (use * for all).
"Turn on PowerShell Script Block Logging" -> Event 4104
Optional: "Log script block invocation start/stop" -> 4105/4106.
"Turn on PowerShell Transcription" -> writes .txt transcripts
Set output directory (central share recommended) and
"Include invocation headers".
REGISTRY EQUIVALENTS (read to verify config)
--------------------------------------------
Script Block Logging:
HKLM\SOFTWARE\Policies\Microsoft\Windows\PowerShell\ScriptBlockLogging
EnableScriptBlockLogging = 1
EnableScriptBlockInvocationLogging = 1 (optional, 4105/4106)
Module Logging:
HKLM\SOFTWARE\Policies\Microsoft\Windows\PowerShell\ModuleLogging
EnableModuleLogging = 1
...\ModuleLogging\ModuleNames (value "*" = all modules)
Transcription:
HKLM\SOFTWARE\Policies\Microsoft\Windows\PowerShell\Transcription
EnableTranscripting = 1
OutputDirectory = \\server\share\pstranscripts
EnableInvocationHeader = 1
WHAT EACH FEATURE GIVES YOU
---------------------------
Script Block Logging (4104)
- Records the full text of script blocks AS EXECUTED, after the engine
has deobfuscated/decoded them. Catches -EncodedCommand payloads,
Invoke-Expression content, and in-memory execution.
- Best single source for "what did the attacker actually run".
Module Logging (4103)
- Logs pipeline invocation and parameter binding per command. More verbose,
noisier, and does not always capture obfuscated input as cleanly as 4104.
Transcription
- Plain-text input/output transcript of interactive and script sessions,
one file per session, with timestamps and host info. Good for human
review and for capturing command OUTPUT (which 4104 does not).
Note: PowerShell v2 lacks these features. "powershell -version 2" is a known
downgrade/evasion attempt -- alert on it and consider removing the v2 engine
(Windows optional feature "Windows PowerShell 2.0").
READING THE LOGS (read-only)
----------------------------
# All script blocks in the last day
Get-WinEvent -FilterHashtable @{
LogName='Microsoft-Windows-PowerShell/Operational'; Id=4104;
StartTime=(Get-Date).AddDays(-1) } |
Select-Object TimeCreated, @{n='Script';e={$_.Message}}
# Only blocks flagged suspicious (Warning level)
Get-WinEvent -FilterHashtable @{
LogName='Microsoft-Windows-PowerShell/Operational'; Id=4104; Level=3 }
# Classic engine starts with host name
Get-WinEvent -FilterHashtable @{LogName='Windows PowerShell'; Id=400} |
Select-Object TimeCreated, Message
DETECTION IDEAS (strings to hunt in 4104/transcripts)
-----------------------------------------------------
-enc / -EncodedCommand / -e (base64 command)
FromBase64String (inline decode)
IEX / Invoke-Expression (dynamic execution)
DownloadString / DownloadData / Invoke-WebRequest / Net.WebClient
-nop / -noprofile -w hidden / -ExecutionPolicy Bypass
[Reflection.Assembly]::Load / System.Reflection (in-memory loading)
powershell -version 2 (engine downgrade)
Always tune against your admin baseline before alerting.
Source: Microsoft Learn - About Logging (PowerShell).
Defensive reference on CyberRamen. Offensive / red-team sheets live on OffensiveRamen.com.