PowerShell offers a rich set of logging options, which can be accessed through the PowerShell profile. These logs can then be used to help diagnose issues with your scripts and determine what has happened during runtime. This is useful for auditing purposes or just keeping track of your history in case you need it later on. In this blog post we will show how to create scripts that record these logs automatically, as well as an example script that uses them.,
PowerShell is a command-line tool that allows users to record and audit all the things. The “powershell script logging output to file” is an option that allows users to do just this.
IT professionals of all skill levels are using PowerShell daily to perform a wide variety of tasks. Everything from automation of systems & database administration to help desk troubleshooting, PowerShell logging and auditing has a role to play. All this activity generates security concerns for an organization. You may find yourself asking:
- What commands are executed during sessions?
- Is it possible that unauthorised scripts are being run from unsecure local or network sources?
- What modules are being utilized that could be harmful?
In this post, you’ll learn about the PowerShell logging and auditing settings. By the Conclusion of this tutorial, you’ll have enough expertise to start recording and auditing all PowerShell activities that take place on the network. Continue reading if this has piqued your curiosity.
This post will be a step-by-step guide. If you want to follow along, you’ll need the following items:
- A basic understanding of Powershell is required.
- Understand how to update registry entries and get access to them.
- Basic understanding of Group Policies
This article does not address non-Windows PowerShell logging, but you can learn more about it here.
PowerShell 5.1, Windows Server 2016, and Windows Server 2019 are used in all cases.
Using Transcripts for Logging
On the internet, there are several accusations that PowerShell is vulnerable. This could hardly be more untrue. PowerShell has tools for auditing and logging PowerShell activities for both SysOps and SecOps.
Transcripts are one of the most basic PowerShell logging options. Transcripts are an excellent method to keep track of a live host session. This feature has been in PowerShell since version 1.0, when it was released by Microsoft. PowerShell. Module for hosting.
You receive all of the instructions and output created during a host session with transcripts. When you exit the host session, the transcript will come to a halt.
How to Use the Registry to Enable Transcripts
While Group Policy may allow transcripts, you can also do it by modifying the Windows Registry. On Windows Server 2016, for example, the registry entry is stored at HKLM:SOFTWAREWOW6432NodePoliciesMicrosoftWindowsPowerShellTranscription and may have values like those shown below:
Transcription logging and auditing registry values examples
If you’d prefer not open regedit and manually edit the registry, a PowerShell function is provided below that will perform all of the heavy lifting for you. This function will automatically set all of the necessary registry settings.
param([Parameter(Mandatory)]) function Enable-PSTranscriptionLogging [string] $OutputDirectory))))))))))))))) # Create the key if it doesn’t exist if(-not (Test-Path $basePath)) $basePath = ‘HKLM:SOFTWAREWOW6432NodePoliciesMicrosoftWindowsPowerShellTranscription’ $null = New-Item $basePath -Force; $null = New-Item $basePath -Force; $null = New-Item # Make the necessary properties. $base $base $base $base $base $base $base $base $base $base $base $base $base $ -PropertyType Dword New-ItemProperty $base Path -Name “EnableInvocationHeader” -PropertyType Dword -Name “EnableTranscripting” $basePath -Name “OutputDirectory” -PropertyType String -New-ItemProperty $basePath -Name “OutputDirectory” # By adjusting the value, they may be activated (1) or disabled (0). $base is a property set by Set-ItemProperty. -Value “1” -Name “EnableInvocationHeader” Set-ItemProperty $basePath -Name “EnableTranscripting” -Value “1” Set-ItemProperty $basePath -Name “EnableTranscripting” -Value “1” -Value $OutputDirectory Path -Name “OutputDirectory”
Transcripts Begining and Ending
The Start-Transcript and Stop-Transcript cmdlets are the simplest method to get started with transcripts. The simplest approach to start and stop recording PowerShell console activity is to use these two simple commands.
Type the following code into the terminal and press Enter to begin a transcript or record of commands used during a host session:
# PowerShell 1.0 to 5.1 and PowerShell 7 Start-Transcript are supported.
Now type a generic command into the session to provide some verbose output. To retrieve the current date and time, use the code below:
You should get something similar to the screenshot below:
At this point, the result of the command has been saved to the text file you specified in the registry. Close the host session or use the Stop-Transcript cmdlet to terminate the transcript.
The Stop-Transcript cmdlet demonstrates purpose. Simply closing the PowerShell console will “halt” a transcript.
The Get-Date cmdlet and its output, including the Stop-Transcript cmdlet, were recorded in the background to a plain-text file.
Transcripts are saved by default in the Documents folder of the percent userprofile percent userprofile percent userprofile percent userprofile percent userprofile percent userprofile percent userprofile percent userprofile percent userprofile percent userprofile percent userprofile percent userprofile percent userprofile percent userprofile percent userprofile [hostname]. [random characters]. [timestamp].txt is a text file. When transcripts are saved centrally, this naming scheme is important since it eliminates unintentional overwriting and makes finding PowerShell logs simpler.
A PowerShell Transcript’s Anatomy
Every transcript follows a certain “schema,” or structure. Examine the PowerShell transcript file that was created with the default settings. You can see all of the common characteristics that the transcript will have.
The host session information, start time, username, PowerShell and OS version, and machine name will all be included in each transcript generated using default options. The commands that were executed, the output created, and the final command Stop-Transcript, which closes the transcript and puts a final timestamp to the transcript file, follow this helpful information.
PowerShell transcript example
There is no need to use the default naming convention or path when using the Start-Transcript cmdlet. Any name may be used to store a transcript to any writable place.
Try it right now. As seen in the sample below, use the -Path argument. This code snippet creates a folder at C:My PowerShell Transcripts and starts recording a transcript in the Get-Date-Transcript.txt file right away.
Start-Transcript -Path ‘C:My PowerShell TranscriptsGet-Date-Transcript.txt’ $null = New-Item -Path C:My PowerShell Transcripts -ItemType Directory -ErrorAction Ignore
Stop the transcript (Stop-Transcript) after performing certain commands, and then browse to the directory provided in the sample above. Your transcript should now appear as follows:
PowerShell transcript has been saved.
Parameters for the Start-Transcript command
You learnt how to use Start-Transcript with no arguments before, however this cmdlet also provides several useful parameters for customizing the behavior, such as:
- NoClobber – prevents overwriting by mistake.
- PowerShell may write to an existing transcript file with the append command.
- IncludeInvocationHeader – includes the exact time each command was executed.
- UseMinimalHeader — a v6.2 option that eliminates the default host session detail information.
A complete list of optional arguments may be found in the manuals.
Transcripts are useful, but you can’t always see what’s going on in a script from beginning to finish. Let’s have a look at Get-Date.ps1, a sample script.
Get-Date.ps1 is a program that allows you to get a date.
- The Get-Date cmdlet returns the current date and time.
- The Test-NetConnection cmdlet prints network connection test results to the console.
- Defines a number array.
- Loops over the array, running a command that doesn’t create any output and starting a new PowerShell session for each number.
# Create a date to host a session by using Get-Date as a script. # Test the network with some output to the host session using Get-Date. #uh-oh $numbers = 1..10 # Test-NetConnection localhost What exactly is this? $number in $numbers) foreach # Performing an action that does not result in a console output [System.Console]::Beep (6000,500) Start-Process pwsh.exe # This is performed in the host session, but no output is produced # and it is not recorded in the transcript!
The Get-Date does not appear in the transcript that was just prepared. Apart from Get-Date and Test-NetConnection, the ps1 script accomplished the following:
PowerShell transcript example
This PowerShell logging approach has the drawback of only working for the current user’s host session. There is no track of what activities a script did if it does not generate any output to the host session. While transcripts provide some PowerShell logging, they were never intended to include all PowerShell script activity.
This problem is solved by using PowerShell Logging of Script Blocks, which is the subject of the following section.
Logging of Script Blocks
When enabled, Logging of Script Blocks will record everything that PowerShell does. Logging of Script Blocks is implemented using Group Policy or by editing the Windows Registry directly. Windows 10 adds new functionality called Protected Event Logging, giving you the ability not to log sensitive information such as Personally Identifiable Information (PII) or other sensitive data such as credentials. Protected Event Logging is out of scope for this article, but you can read more about it here.
Editing the registry directly is a good solution for standalone systems or workgroup settings. If you can use Group Policy, configure Logging of Script Blocks and Protected Event Logging there.
Enable Logging of Script Blocks Using Windows Registry
To enable Logging of Script Blocks using the Windows Registry, Copy the function below into your PowerShell session and press Enter:
# Create the key if it doesn’t exist if(-not (Test-Path $basePath)) function Enable-PSScriptBlockLogging # Registry key $basePath = ‘HKLM:SoftwarePoliciesMicrosoftWindowsPowerShellScriptBlockLogging’ $null = New-Item $basePath -Force; $null = New-Item $basePath -Force; $null = New-Item # Make the necessary properties. # These may be enabled (1) or disabled (0) by adjusting the value of New-ItemProperty $basePath -Name “EnableScriptBlockLogging” -PropertyType Dword $basePath -Name “EnableScriptBlockLogging” -Value “1” Set-ItemProperty $basePath -Name “EnableScriptBlockLogging” -Value “1”
Now execute the function as if it were a regular cmdlet, by typing the function name and pressing Enter:
Logging of Script Blocks is enabled. Now let’s test it out. Try running some cmdlets or a few of your scripts. Once you’ve done that, use the following code to inspect the Logging of Script Blocks events:
# Only seeing the message that contains scripts and cmdlets. Get-WinEvent Where-Object Id -eq 4104 | Select-Object -ExpandProperty Message Microsoft-Windows-PowerShell/Operational -MaxEvents 4
An example of what your output may look like is shown below. Depending on the commands or scripts you used, you may see a lot more information. You can see a script I ran using the aforementioned command to inspect the log entries in this screenshot:
Recent Logging of Script Blocks entries
You can still view and audit this information using the traditional Windows Event Viewer and navigating to Applications and Services Logs > Microsoft > PowerShell > Operational. Here’s an example of how the log appears in Windows Event Viewer:
The significance of ScriptBlock logging has been established.
The sample above is from a system modification that resulted in a faulty set of registry entries, which resulted in unanticipated outcomes. Fortunately, ScriptBlock logging had been enabled beforehand. The problem was tracked down to a name error in part of the code that was executed.
If this data will be utilized for auditing, it’s a good idea to have a centralized log collecting point or SIEM in place.
Now that you have insight into what PowerShell is doing on your system, go on to the following step to audit and record which modules PowerShell is utilizing when processing commands and scripts.
Logging of Modules
When you need to audit specific PowerShell modules being used on a host, Logging of Modules is the answer. You enable Logging of Modules in much the same way as you allow Logging of Script Blocks.
Logging of Modules will generate a lot more events than ScriptBlock logging does. You will want to consider the implications and develop a strategy for its use.
Enable Logging of Modules Using Windows Registry
A Group Policy is not accessible in every setting. So, what do you do if you need to audit and track PowerShell module use in these environments? You’re making use of the Windows Registry!
To enable Logging of Modules using the Windows Registry, use the following PowerShell function:
# If the right registry path does not exist, this method establishes it and then enables it. function # Create the key if it doesn’t exist if(-not (Test-Path $basePath)) Enable-PSModuleLogging # Registry path $basePath = ‘HKLM:SOFTWAREWOW6432NodePoliciesMicrosoftWindowsPowerShellModuleLogging’ $null = New-Item $basePath -Force; $null = New-Item $basePath -Force; $null = New-Item # Make the necessary properties. $basePath -Name “EnableModuleLogging” -PropertyType Dword -New-ItemProperty $basePath # By adjusting the value, they may be activated (1) or disabled (0). $basePath -Name “EnableModuleLogging” -Value “1” Set-ItemProperty $basePath -Name “EnableModuleLogging” -Value “1”
Then, execute the following PowerShell function:
When Logging of Modules is enabled, modules are not automatically monitored. You have to specify which modules to log. There are a couple of ways to do this. The adhoc way is to use the Pipeline Execution Details property and the Windows Registry or Group Policy for more permanent scenarios.
This may be done for individual modules or for all modules. It’s not a good idea to keep track of merely a few modules.
To audit module use in a single PowerShell session, you must first import the module you want to audit. Then update the value of the member variable LogPipelineExecutionDetails to $True. For all modules, this variable is set to $False by default.
Let’s imagine you wish to log the VMware.PowerCLI module, for example. You’d do it by pressing Enter after typing the following code:
# Assume you’ve already installed a module (Get-Module -Name VMware.PowerCLI). $true LogPipelineExecutionDetails
Each time you execute the VMware.PowerCLI module in PowerShell after performing the aforementioned command, a log entry is produced. This approach is, however, only valid for the current session. The logging ends when you close PowerShell and does not resume until you restart it.
The specifics of the pipeline execution are recorded in the Windows PowerShell event log as Event ID 800.
When you look at the log using the Windows Event Viewer, it looks like this:
Viewer of Window Events
You’d execute the following code in PowerShell to see these log entries:
Get-EventLog ‘Windows PowerShell’ -EntryType Information -InstanceId 800 Get-EventLog ‘Windows PowerShell’ -EntryType Information -InstanceId 800
There will be a large number of entries if you record all PowerShell modules. You may narrow them according to your preferences. That, however, is outside the scope of this paper.
If you prefer to log all the modules, for all the users, all the time, then you need to edit the Windows Registry once more to add a new key value to the Logging of Modules key that you created earlier in this section.
Use the PowerShell function below to create a new registry key value for ModuleNames:
# This function generates a new key value in order to enable logging for all modules. Enable-AllModuleLogging is a function that enables all modules to log data. # Create the key if it doesn’t exist if(-not (Test-Path $basePath)) $basePath = ‘HKLM:SOFTWAREWOW6432NodePoliciesMicrosoftWindowsPowerShellModuleLoggingModuleNames’ $null = New-Item $basePath -Force $null = New-Item $basePath -Force $null = New-Item $basePath # To log all modules, change the key value. $basePath -Name “*” -Value “*” Set-ItemProperty $basePath -Name “*” -Value “*”
You execute the function the same way you did before in this section after pressing Enter:
Once again, press Enter, and all PowerShell modules will now be recorded each time they are used.
Enable Logging & Transcripts Using Group Policy
If you don’t want to, you can leave the Windows Registry alone. If you have access to a Group Policy environment, using the following policy objects to create logging and auditing may be simpler.
Create a new Group Policy Object in the Group Policy Management console first (GPO). Then make the following changes to the policy:
- Navigate to Computer Configuration > Administrative Templates > Windows Components > Windows PowerShell. You should see the same settings as shown in the below example:
a list of the GPO settings that are currently available
2. Change the status of any of the following settings to enable them:
Logging of Modules GPO Settings
Use an asterisk (*) for the value to ensure that all modules are logged. You might also make a list of individual modules based on their names.
Contents of Module Names
GPO Settings for Transcripts
3. Assign the new GPO to the OU that holds the machine accounts you wish to monitor or audit.
Remember to restart any machines where this policy is in effect.
That’s all there is to it when it comes to utilizing Group Policy to audit and record your PowerShell environment.
You’ve just improved your PowerShell administration security game with this new information. Because of PowerShell’s logging and auditing features, it’s a terrible option for evil actors that want to do nasty things. The techniques described in this article will help you learn the art of PowerShell logging and auditing, allowing you to become a more effective SecOps or SysOps expert. You’ve learned how to use the Windows Registry, Group Policy, and PowerShell to produce transcripts, log script block execution, and module data. If you want to learn more about PowerShell logging and auditing, check out the supplementary resources listed below. Now go out and strengthen your PowerShell environments by logging and capturing everything that happens in PowerShell!
Enabling Logging of Script Blocks
about Group Policy Settings-PowerShell
Creating Policy Objects for Groups
Reference from Group Policy to Registry
Threat Research – PowerShell Logging Provides More Visibility (FireEye)
PowerShell is a command-line tool that allows users to manage the Windows operating system. The “turn on powershell script block logging” is an option that records and auditing all the things for your scripts.
Frequently Asked Questions
How do I log everything in PowerShell?
A: There is a cmdlet called Get-EventLog that can be used to retrieve the logs from any event log. If this does not return all of your desired information, you can use Select-String to filter for certain entries and find what you want.
How do you log activity in PowerShell?
A: The best way to log activity in PowerShell is by using the Get-EventLog cmdlet and piping it into a text file on your local drive.
How do I view PowerShell logs?
A: PowerShell logs are displayed in the Windows Event Viewer.
- powershell module logging
- powershell script block logging
- powershell logging to event viewer
- sysmon powershell logging
- splunk powershell logging