Practical PowerShell Security: Enable Auditing and Logging with DSC

Windows_Insiders_Ninjacat-100PowerShell Security

Almost two years ago Lee Holmes released his famous PowerShell ♥ the Blue Team whitepaper. This is required reading for anyone who works with PowerShell at all in their job or who is concerned about the security of PowerShell in their environment. I outlined a number of PowerShell security-related resources in this previous post:

I am not going to rehash all of the topics in the white paper, but I do want to make it easy for people to implement PowerShell auditing and logging. What better way than putting Lee’s recommendation and code samples into a Desired State Configuration (DSC)? If you would like to see Lee demonstrate these improvements you can watch the third module of this video series:

Practical DSC

Sometimes customers ask me what should go into their baseline configurations for servers. Now that is a fun conversation. Let’s just say PowerShell auditing is an easy one to overlook. PowerShell security is not on the radar in many IT shops. With this DSC configuration sample below it can become routine.

Security Features

As Lee outlined in the whitepaper, WMF 5.x includes a number of enhancements in the area of security:

  • Script block logging
  • System-wide transcription
  • Protected event logging (used together with Windows Event Forwarding)
  • and more…

Lee even provided sample code to set the Group Policy registry values to enable these enhancements. In DSC it is really easy to set registry values, so let’s get to it.


We are assuming that the target system already has WMF 5.x installed or upgraded. Each of these enhancement will require the following settings:

  • Script block logging
    • HKLM:\Software\Policies\Microsoft\Windows\PowerShell\ScriptBlockLogging
      • EnableScriptBlockLogging, 1
      • EnableScriptBlockInvocationLogging, 1
    • It may also be a good idea to increase the log size. The Microsoft-Windows-PowerShell/Operational log is 15MB by default.
  • System-wide transcription
    • Create a directory to hold transcripts
      • Set permissions on the directory to prevent tampering. (I chose SDDL for the shortest code here.)
      • Trim the transcript directory contents on an interval to avoid filling the drive (if local).
      • We are going to use a local directory for now. Lee recommends pointing it to a share off-box.
    • HKLM:\Software\Policies\Microsoft\Windows\PowerShell\Transcription
      • EnableTranscripting, 1
      • IncludeInvocationHeader,1
      • OutputDirectory, [Path]
  • Protected event logging (can be used together with Windows Event Forwarding)
    • Requires Windows 10 or Windows Server 2016
    • Requires a document encryption certificate
    • HKLM:\Software\Policies\Microsoft\Windows\EventLog\ProtectedEventLogging
      • EnableProtectedEventLogging, 1
      • EncryptionCertificate, [Certificate]

Note that the logging and transcription enhancements include an option for invocation logging. This is optional and will increasing the logging volume. It basically adds start/stop header information for each command that is executed. You can omit this setting if you prefer a lower logging leverl.

Desired State Configuration

Now that we have an outline of the settings required, we can move those into a DSC configuration. You can view the code on my GitHub account here.

  • Script Block Logging
    • Two registry resources set the values.
    • Then for good measure we use a script resource to increase the size of the PowerShell event log.
  • Transcription
    • Three registry resources set the values.
    • We need a file resource to create the directory to hold the transcript files.
    • Then two script resources set the permissions on the directory and remove any old files. We probably could have used an external resource to set the directory permissions, but I want to keep this using in-box resources for simplicity. Keeping the transcript directory clean requires that you set the DSC Local Configuration Manager (LCM) to ApplyAndAutocorrect.
    • NOTE: Remove the file and script resources if you send the transcripts to a remote UNC share path.
    • NOTE: If you use a local path, have fun trying to read the transcript files. Also, the trim files script resource will likely generate warnings trying to clear old files.
  • Protected Event Logging
    • I’m going to skip this one due to a couple reasons:
    • Right now we do not have a way to request a certificate in a configuration, and then pass that data to another resource in the same configuration. Writing a custom resource for that wouldn’t be practical, because I’m trying to keep this to in-box DSC resources for now.
    • Most customers already have an event collection tool (SIEM). If not, then explore the xWindowsEventForwarding resource module.
  • Fit and Finish
    • Notice that the configuration has the following parameters:
    • TranscriptPath – Directory where you want to put the transcript files. Can be local or UNC path.
    • TranscriptDays – How many days of transcripts do you wish to retain?
    • EventLogSizeInMB – Size to set for the PowerShell log to hold the additional content generated.
    • For completeness I threw in a configuration to disable the transcription and logging.
    • I also threw in a couple lines to query the event logs for your new events.

Ideally you would take this sample code and create two configurations: one for the nodes being audited and one to set up the server with the UNC share receiving the transcripts and Windows Event Forwarding.

The code on my GitHub account is purely sample for you to copy/paste into your own configurations. This makes a great finish for a baseline server security config.


The PowerShell console and ISE will cache group policy settings when they are launched. In order to see the effects of the logging and transcription you will need to open a new session.

If you have DSC set to scan the node for compliance (as most of us do), note that this will generate a significant amount of logging via each of these methods.

So if you decide to put the transcript folder on the local box, then the DSC configuration is going to error out when it goes to check the folder for old files to purge. You will see orange warning text when this happens.

Audit Thy Servers

Now you have a cool whitepaper on PowerShell security to read and some free DSC code to play with. Use the comments area below to discuss any questions or ideas.


Comments (2)

  1. David Loder says:

    Just be careful with testing the impact of the transcription change. I’ve been involved with cases where transcription being on caused the Active Directory Administrative Center GUI to stop functioning.

  2. Robin CM says:

    Transcription to a share – which is the secure & sensible way to do it – seems to also require something like resource-based constrained delegation to be configured, as otherwise the share is not accessible due to being a kerberos double-hop. Unless you run your PowerShell from the console of the server/machine you’re administering, which you shouldn’t.

    Worse, if the transcript file can’t be created, the entire PowerShell session fails – which is normally good, but not if you don’t realise this, and then find that you can’t do ANY remote PowerShell stuff after enabling what you thought was going to be a beneficial security feature.

    None of the blogs or docs I’ve seen about transcription mention this, which is less than helpful.

Skip to main content