PowerShell Protected Event Logging: Encrypting Script Block and Transcript Evidence at the Source
Script block logging and transcription leak secrets to anyone who reads the event log. Protected Event Logging encrypts that forensic trail at write time so only your IR team can open it.
Turning on PowerShell logging is one of the highest-value hardening steps on Windows. Script block logging (event ID 4104 in the Microsoft-Windows-PowerShell/Operational log) and transcription capture exactly what attackers ran, even when they obfuscate or run in-memory. But there is a quiet problem most teams never think about: the logs themselves become a secrets database. Every credential that gets passed on a command line, every connection string, every API token embedded in a one-liner, every decoded payload — it all lands in plaintext in a log that, by default, local administrators and anyone with Event Log Readers rights can read.
Protected Event Logging (introduced in Windows 10 / PowerShell 5.0) fixes this. It encrypts log content to a certificate's public key the moment it is written, so the on-disk forensic trail is opaque to everyone except the holder of the matching private key — typically your incident response team on an offline workstation.
The threat: your audit trail is an exfiltration target
Think through what an attacker who already has local admin — the exact scenario your logging is supposed to help you investigate — can do with unencrypted logs:
- Harvest cleartext credentials that scripts passed as arguments or wrote to transcripts.
- Read decoded contents of their own earlier
-EncodedCommandpayloads to reconstruct what the blue team can see. - Scrape secrets that legitimate admin automation logged — scheduled jobs, deployment scripts, and installers routinely pass passwords inline.
In other words, the better your PowerShell logging, the juicier the log becomes. Protected Event Logging closes that gap by making the written events useless to anyone without the decryption key — including the attacker standing on the box.
How it works
Protected Event Logging uses the Cryptographic Message Syntax (CMS / PKCS#7). You supply an encryption certificate (document-encryption EKU, OID 1.3.6.1.4.1.311.80.1) via Group Policy. Windows encrypts eligible event content to that certificate's public key before it hits disk. Only a host that possesses the corresponding private key can decrypt it, using Unprotect-CmsMessage. The private key never needs to live on the monitored endpoints at all.
1. Create a document encryption certificate
On an isolated analyst workstation, generate the keypair and export only the public certificate for distribution:
$cert = New-SelfSignedCertificate `
-Subject "CN=PEL-IR-2026" `
-KeyUsage KeyEncipherment,DataEncipherment `
-Type DocumentEncryptionCert `
-CertStoreLocation Cert:\CurrentUser\My
# Export PUBLIC cert for deployment to endpoints (no private key).
Export-Certificate -Cert $cert -FilePath C:\keys\pel-public.cer
In production, issue this from your enterprise CA with a document-encryption template so you get rotation and revocation for free. Keep the private key off the fleet — on a hardware token or an offline, well-controlled IR host.
2. Turn it on via Group Policy
Enable Computer Configuration → Administrative Templates → Windows Components → Administrative Templates → Event Logging → Enable Protected Event Logging and paste the public certificate content (or point it at a store thumbprint). The registry equivalent for scripted rollout:
$base = "HKLM:\SOFTWARE\Policies\Microsoft\Windows\EventLog\ProtectedEventLogging"
New-Item -Path $base -Force | Out-Null
Set-ItemProperty -Path $base -Name EnableProtectedEventLogging -Value 1 -Type DWord
# EncryptionCertificate expects the full base64 cert content.
Set-ItemProperty -Path $base -Name EncryptionCertificate `
-Value (Get-Content C:\keys\pel-public.cer -Raw)
Pair this with the two settings that actually generate the sensitive content — script block logging and transcription — under Windows Components → Windows PowerShell. Protected Event Logging has nothing to encrypt if those are off.
3. Decrypt, on your terms
On the endpoint, 4104 events now carry a CMS blob instead of readable script text. On the analyst host that holds the private key:
Get-WinEvent -LogName 'Microsoft-Windows-PowerShell/Operational' |
Where-Object Id -eq 4104 |
ForEach-Object { $_.Message | Unprotect-CmsMessage }
What it protects — and what it doesn't
Protected Event Logging is confidentiality for the audit trail. It is not tamper-proofing and not a substitute for shipping logs off the box.
An attacker with local admin can still delete or stop writing logs; encryption stops them reading content, not destroying it. So Protected Event Logging is one layer in a stack:
- Forward events off-host (Windows Event Forwarding) so deletion on the endpoint doesn't erase the evidence — the forwarded copy stays encrypted in transit and at rest.
- Restrict log access so day-to-day admins can't trivially read raw events even before encryption.
- Protect the private key like a crown jewel. If it leaks, every encrypted log the attacker scraped becomes readable retroactively.
Where WinSentinel fits
This is exactly the kind of setting that is easy to enable once and impossible to remember to verify. WinSentinel audits your PowerShell logging posture as part of its standard scan — whether script block logging and transcription are on, whether Protected Event Logging is configured, and whether the referenced certificate is actually present and valid rather than a dangling thumbprint from a decommissioned cert.
On a single machine, that full audit runs free with no limits — all of WinSentinel's modules are available on one endpoint without a license. For teams running many machines, the Pro fleet capabilities let a central node roll this check across every endpoint, flag the hosts where logging silently regressed, and surface drift — for example, a golden image that shipped with Protected Event Logging on but a subset of machines where a later GPO change turned it back off. That rollup turns "we enabled it in 2024" into "every node is still enforcing it this morning."
Encrypting your PowerShell forensic trail costs almost nothing and removes an entire class of secret leakage from the one place defenders assumed was safe. Turn on the logging, encrypt what it captures, forward it off the box, and verify the posture holds over time.