Beginning with PowerShell 5, the PowerShell engine starts to log executed commands and scripts. By default, only commands considered potentially harmful are logged. When you enable verbose logging, though, all executed code from all users on a given machine are logged.

This is the first part of a mini series introducing you to script block logging. Today, we just want to get to the logged script code in the most basic way. One line is sufficient:

$logInfo = @{ ProviderName="Microsoft-Windows-PowerShell"; Id = 4104 }

Get-WinEvent -FilterHashtable $logInfo |
  Select-Object -ExpandProperty Message

This reads all events with ID 4104 from the log “Microsoft-Windows-PowerShell” which contains logged code. Note that PowerShell Core also logs commands but uses a different log file.

You should now get back chunks of data like this:

Creating Scriptblock text (1 of 1):
Set-ExecutionPolicy -Scope CurrentUser -ExecutionPolicy Bypass

ScriptBlock ID: aeb85bcb-98be-42d0-b695-fbbb975ec5d2

If "Path" is empty, then the command was issued interactively. Else, you find the script path here.

If you don’t get back any information, consider these points:

  • Are you using Windows PowerShell? If you are using PowerShell Core, you’d need to adjust the log file name
  • By default, script block logging logs only code that is security relevant. If you haven’t issued any such code, you will not receive anything.

When you execute the line below which is considered security relevant, you should be able to read this code from the log afterwards:

PS> Set-ExecutionPolicy -Scope Process -ExecutionPolicy Bypass -Force

Twitter This Tip! ReTweet this Tip!