How to secure passwords with PowerShell When to use the Windows command prompt vs. PowerShell
X

Set up PowerShell script block logging for added security

Learn how to set up your systems to capture abnormal PowerShell behavior as one way to shore up your defenses.

Editor's Note: Adam Bertram originally wrote this article and Brien Posey has expanded it.

PowerShell is an incredibly comprehensive and easy-to-use language. But administrators need to protect their organization from bad actors who use PowerShell for criminal purposes.

PowerShell's extensive capabilities as a native tool in Windows make it tempting for an attacker to exploit the language. Increasingly, malicious software and bad actors are using PowerShell to either glue together different attack methods or run exploits entirely through PowerShell. Often such attacks evade detection because of how the attacks leverage native operating system components.

There are many methods and best practices available for securing PowerShell. One of the most valued is PowerShell script block logging. Script blocks are a collection of statements or expressions used as a single unit. Users denote them by everything inside the curly brackets within the PowerShell language.

Starting in Windows PowerShell version 4.0 but significantly enhanced in Windows PowerShell version 5.0, script block logging produces an audit trail of executed code. Windows PowerShell version 5.0 introduced a logging engine that automatically decrypts code that was obfuscated with methods such as XOR, Base64 and ROT13. PowerShell includes the original encrypted code for comparison.

PowerShell script block logging helps with the postmortem analysis of events to give additional insights if a breach occurs. It also helps IT be more proactive with monitoring for malicious events. For example, if you set up event subscriptions in Windows, you can send events of interest to a centralized server for a closer look.

Set up a Windows system for logging

Two primary ways to configure script block logging on a Windows system are by either setting a registry value directly or by specifying the appropriate settings in a group policy object.

To configure script block logging via the registry, use the following code while logged in as an administrator.

New-Item -Path "HKLM:\SOFTWARE\Wow6432Node\Policies\Microsoft\Windows\PowerShell\ScriptBlockLogging" -Force
Set-ItemProperty -Path "HKLM:\SOFTWARE\Wow6432Node\Policies\Microsoft\Windows\PowerShell\ScriptBlockLogging" -Name "EnableScriptBlockLogging" -Value 1 -Force

You can set PowerShell logging settings within group policy, either on the local machine or through organizationwide policies.

Open the Local Group Policy Editor and navigate to Computer Configuration > Administrative Templates > Windows Components > Windows PowerShell > Turn on PowerShell Script Block Logging.

Turning on PowerShell script block logging
Set up PowerShell script block logging from the Local Group Policy Editor in Windows.

When you enable script block logging, the editor unlocks an additional option to log events via "Log script block invocation start / stop events" when a command, script block, function or script starts and stops. This helps trace when an event happened, especially for long-running background scripts. This option generates a substantial amount of additional data in your logs.

PowerShell script block logging option
PowerShell script block logging tracks executed scripts and commands run on the command line.

How to configure script block logging on non-Windows systems

PowerShell Core is the cross-platform version of PowerShell for use on Windows, Linux and macOS. To use script block logging on PowerShell Core, you define the configuration in the powershell.config.json file in the $PSHome directory, which is unique to each PowerShell installation.

From a PowerShell session, navigate to $PSHome and use the Get-ChildItem command to see if the powershell.config.json file exists. If not, you will need to create the file. The method for doing so will vary by operating system. While you can use a text editor, you can also create the required file from the command line. On a Linux machine, for example, you could use this command.

sudo touch powershell.config.json

Modify the file using a tool such as the Nano text editor and paste in the following configuration.

{
     "PowerShellPolicies": {
         "ScriptBlockLogging": {
         "EnableScriptBlockInvocationLogging": false,
         "EnableScriptBlockLogging": true
         }
     },
     "LogLevel": "verbose"
 }

Test PowerShell script block logging

Testing the configuration is easy. From the command line, run the following command.

PS /> { "log me!" }
  "log me!"

Checking the logs on Windows

How do you know what entries to watch out for? The main event ID to watch out for is 4104. This is the ScriptBlockLogging entry for information that includes user and domain, logged date and time, computer host, and the script block text.

Open Event Viewer and navigate to the following log location: Applications and Services Logs > Microsoft > Windows > PowerShell > Operational.

Click on events until you find the one from the test that is listed as Event ID 4104. Filter the log for this event to make the search quicker.

Windows Event 4104
Event 4104 in the Windows Event Viewer details PowerShell activity on a Windows machine.

On PowerShell Core on Windows, the log location is: Applications and Services Logs > PowerShellCore > Operational.

Log location on non-Windows systems

On Linux, PowerShell script block logging will log to syslog. The location will vary based on the distribution. For this tutorial, we use Ubuntu, which has syslog at /var/log/syslog.

Run the following command to show the log entry. It is worth noting that this command requires elevated permissions, so you will need to use the sudo command.

sudo cat /var/log/syslog | grep "{ log me! }"
2019-08-20T19:40:08.070328-05:00 localhost powershell[9610]: (6.2.2:9:80) [ScriptBlock_Compile_Detail:ExecuteCommand.Create.Verbose] Creating Scriptblock text (1 of 1):#012{ "log me!" }#012#012ScriptBlock ID: 4d8d3cb4-a5ef-48aa-8339-38eea05c892b#012Path:

Setting up a centralized server on Linux is different since you're using syslog by default. There are many different tools that you can use to ship your logs to a log aggregation service to track PowerShell activity from a central location. Rsyslog is a popular choice, but other options include Dynatrace, New Relic and Datadog.

Next Steps

5 PowerShell tools to help simplify admin tasks and support

How to test PowerShell code with Pester

7 PowerShell courses to help hone skills for all levels of expertise

Do-While vs. Do-Until in PowerShell: What's the difference?

How to use regex in PowerShell

Dig Deeper on Microsoft messaging and collaboration