top of page
Search

PowerShell Logging: Making the Invisible Visible

  • Oct 24
  • 6 min read
ree

If you’ve worked in cybersecurity for a while, you know one truth: PowerShell is both a friend and a foe. Administrators love it because it makes automation simple. Attackers love it because it makes exploitation simple.


From credential theft to data exfiltration, lateral movement, and even memory-only malware — PowerShell can do it all.

So, the real question is not whether PowerShell is being used, but how and by whom.

That’s where PowerShell logging comes into play — your digital microscope into what’s really happening behind that blue window.


----------------------------------------------------------------------------------------------------------

The Problem — Power Without Visibility

Older versions of PowerShell were like stealth bombers — powerful and almost invisible. Before version 5, investigators had very little to work with; attackers could run entire malicious frameworks without leaving much of a trace.


Then came PowerShell v5, and finally, we got some serious logging features. Now we can see what’s being executed, which modules are being loaded, and even the contents of the script itself.

But here’s the catch: most of this logging is not enabled by default, and attackers know it.

That’s why it’s your job to understand it, enable it, and use it wisely.


The Key Event IDs You Must Know

Think of these as your “eyes and ears” inside PowerShell:

Event ID

Log Type

What It Shows

Why It Matters

4103

Module Logging

Captures module and pipeline output

Great for spotting command sequences and variables

4104

Script Block Logging

Captures the full script content

Lets you see exactly what was executed (with deobfuscation!)

400 & 800

Legacy PowerShell Logs

Session start and stop events

Still useful for older systems or downgrade attacks

WinRM/Operational

Remoting Logs

Tracks inbound/outbound PS remoting

Crucial for identifying remote PowerShell abuse

Logs to remember:
  • Microsoft-Windows-PowerShell/Operational.evtx → for PowerShell v5

  • Microsoft-Windows-PowerShellCore/Operational.evtx → for PowerShell Core (v6, v7)


----------------------------------------------------------------------------------------------------------

The Power of Script Block Logging (EID 4104)

Event ID 4104 is where the magic happens. It records the entire script block that was executed — whether typed in manually, run from a file, or even built dynamically in memory.

What’s even better?

Windows automatically flags potentially malicious script blocks as “Warning” events under EID 4104 — even if script block logging isn’t fully enabled.

That’s right — Microsoft built in a safety net. If a suspicious command like Invoke-Expression, DownloadString, or FromBase64String runs, it gets logged automatically.

So, even in unprepared environments, you might still get lucky.


----------------------------------------------------------------------------------------------------------

Why Attackers Still Get Away — The Downgrade Trick

Attackers know PowerShell v5+ logs everything, so they often downgrade their sessions to PowerShell v2 — which has no useful logging at all.


You can spot this behavior in the legacy logs:
  • Look in Windows PowerShell.evtx for Event ID 400 with EngineVersion=2.0 or HostVersion=2.0

  • Also, watch for command-line indicators like:

    powershell -Version 2

Best defense?

Disable or uninstall PowerShell v2 entirely. It’s outdated, insecure, and only helps attackers stay invisible.


----------------------------------------------------------------------------------------------------------

Decoding the Attacker’s Syntax

Attackers rarely use PowerShell the normal way. They love stealthy parameters that hide windows, bypass policies, and run scripts directly from memory.


Common flags and their purpose:

Parameter

What It Does

Why It’s Dangerous

-WindowStyle hidden

Hides PowerShell window

Runs silently in background

-NoProfile

Skips user profile scripts

Avoids detection via profile hooks

-NonInteractive

Disables prompts

Prevents blocking

-ExecutionPolicy Bypass

Disables script execution restrictions

Runs unsigned or malicious scripts

-EncodedCommand

Runs Base64-encoded script

Obfuscates real command

Invoke-Expression (IEX)

Executes arbitrary code

Common in download cradles


----------------------------------------------------------------------------------------------------------

Quick Wins for Analysts

When triaging PowerShell activity, start with these “low-hanging fruit” checks:

  • Search for suspicious keywords:download, Invoke-Expression, FromBase64String, WebClient, rundll32, Start-BitsTransfer, Invoke-WmiMethod

  • Filter by Event ID:

    • 4103 → See what modules and variables were used

    • 4104 → See the full script, including deobfuscated code

  • Look for “Warning” in 4104 — these are Microsoft’s auto-flagged malicious patterns.

  • Check for Remoting (WinRM):

    • Event ID 6 — Destination host, IP, and logged-on user

    • Event ID 91 — Session creation

    • Event ID 168 — Authenticating user

Remember — even legitimate scripts can look suspicious. Don’t just hunt for what was executed — understand why it was executed.

----------------------------------------------------------------------------------------------------------

PowerShell Core (v6 & v7) — The Next Chapter

PowerShell Core is cross-platform now (Windows, Linux, macOS) — built on .NET Core. It doesn’t replace PowerShell v5, it coexists with it.


That means:

  • Separate installation

  • Separate Group Policies

  • Separate logs


If both versions exist on a system, you must enable logging on both. Attackers already know this — they may run scripts through PowerShell 7 to bypass your v5 monitoring.

----------------------------------------------------------------------------------------------------------

Practical Tip: Centralize, Don’t Silo

The biggest mistake I see? Logs stay on endpoints until it’s too late.

Forward PowerShell logs, Security logs (4688), and Defender logs (1116–1119) to a central SIEM or log collector. Once an attacker wipes or disables logging locally, your central copy will be the only evidence left.



----------------------------------------------------------------------------------------------------------

The Art of Obfuscation

Attackers now rely heavily on obfuscation — the practice of making a script unreadable to humans and confusing to machines. If you’ve ever seen something like ${#/~) or $a+$b+$c forming into a download cradle, that’s obfuscation at work.


One of the most famous tools behind this is Invoke-Obfuscation, created by Daniel Bohannon.

It showed the world just how easily PowerShell scripts could be twisted into unrecognizable forms while still running perfectly. Since then, threat actors and cybercrime groups have taken this concept to a new level, turning PowerShell into a weapon that can blend right into legitimate system activity.

The scary part?

A heavily obfuscated script can look like complete gibberish but still download malware or run a tool like Mimikatz in the background.


The good news is that defenders have caught up. Windows 10 introduced AMSI (Antimalware Scanning Interface), which allows security tools to inspect scripts as they’re executed — even if they’re obfuscated. This means we can now catch malicious activity closer to the source.


----------------------------------------------------------------------------------------------------------

Understanding PowerShell Logging

PowerShell isn’t just powerful for attackers — it’s also a goldmine for forensic analysts. The tool leaves behind several kinds of logs, and each tells a different part of the story.


PowerShell Transcript Logs

Transcript logs are like a screen recorder for the PowerShell terminal. They capture exactly what was typed and what the system replied with. That includes both the commands (inputs) and their results (outputs).


These logs are incredibly useful because they give you the complete picture — especially in scenarios where an attacker runs tools like Mimikatz to dump credentials.

Script Block Logging might tell you what script was executed, but Transcript Logging shows what actually happened, including whether the attack succeeded.

Transcript logs are saved as text files, usually under:

C:\Users\<username>\Documents\

But storing logs in user folders is risky — attackers can easily delete or modify them. That’s why redirect them to a write-only network share or a secure folder with limited permissions.


You can enable transcription via Group Policy under:

Computer Configuration >Administrative Templates >Windows Components >
Windows PowerShell >Turn on PowerShell Transcription

It’s lightweight, easy to enable, and provides incredible visibility with minimal storage cost.



Script Block Logging

Script Block Logging focuses on the code itself — the PowerShell commands and functions that get executed, even if they’re hidden or dynamically generated.

In combination with transcript logs, Script Block Logging helps you catch both the “what” and the “how” of PowerShell activity.



PSReadLine History

Starting with PowerShell v5, Microsoft introduced something even simpler — a local history file called ConsoleHost_history.txt.

If you’ve used Linux before, this is similar to .bash_history. It records the last 4,096 commands typed into the PowerShell console (but not the output). The file is stored here:

%UserProfile%\AppData\Roaming\Microsoft\Windows\PowerShell\PSReadline\

This is often the first artifact investigators check when trying to reconstruct what an attacker was doing manually.

However, there are two caveats:
  • Attackers can easily delete or modify it.

  • It only records interactive console sessions, not background or remote executions.

Even so, it’s incredibly handy — especially because it’s enabled by default.


----------------------------------------------------------------------------------------------------------

Why This Matters for Defenders

Every PowerShell log type provides a different piece of the puzzle:

Log Type

Captures

Typical Use Case

Script Block Logging

Code that was executed

Detect obfuscated or malicious scripts

Transcript Logging

Commands + Output

Reconstruct what happened in a session

PSReadLine History

Last 4,096 typed commands

Identify manual actions or testing


When combined, they can help analysts piece together how an attacker moved through a system, what tools they executed, and what data they may have accessed.


----------------------------------------------------------------------------------------------------------


Wrapping Up

PowerShell is not the enemy — blindness is and PowerShell logging isn’t just a feature — it’s a window into the attacker’s mind/

When properly logged, PowerShell becomes one of your most valuable forensic resources. You can see who ran what, when they ran it, and what exactly executed in memory.


----------------------------------------------Dean---------------------------------------------------

 
 
 

Comments


bottom of page