Keeping tabs on what a script is doing is critical for monitoring and debugging. If you’re writing a PowerShell script, you need a go-to PowerShell log function you can use in all of your scripts.
If a script is invoked interactively, meaning directly from the console using techniques such as Write-Verbose
, Write-Information
or Write-Host
, it is useful because each command can display messages on the console as the script runs.
But what if this script is getting invoked by a scheduled task or some other process that doesn’t involve a human staring at a screen while it runs? In this case, we’ll need to incorporate another level of monitoring. An excellent way to monitor a script that doesn’t run interactively is by writing to a log file.
Table of Contents
Define What You Need to Log
There are a few different ways to write text to a text file in PowerShell, and the approach that’s used is completely up to the developer. However, before embarking on creating your own logging function, there are a few things to keep in mind.
- All log lines need to be structured content. No loosey-goosey text messages strewed about.
- The time should be recorded for each log entry.
- A severity is recommended or other “tags” to quickly filter information in the log file later.
Related: Set-Content: The PowerShell Way to Write to a File
Build the PowerShell Log Function Scaffold
Let’s see how we can build a PowerShell function to incorporate into any of our scripts. Because this function will need to be available to several different scripts, we’re going to create a PS1 script just to store our function. The function’s name will be Write-Log
.
function Write-Log {
[CmdletBinding()]
param()
}
This logging function will write a single log line every time it’s called. Each line in the log is going to have two attributes that will change depending on what I’d like to record; message and severity, so I will add those as parameters to our function.
function Write-Log {
[CmdletBinding()]
param(
[Parameter()]
[ValidateNotNullOrEmpty()]
[string]$Message,
[Parameter()]
[ValidateNotNullOrEmpty()]
[ValidateSet('Information','Warning','Error')]
[string]$Severity = 'Information'
)
}
Notice that I’ve chosen to limit the value of the Severity
parameter to three choices. By limiting the options, it ensures that I can rely on this field to always be one of three different severities. Once I’ve got the parameters built out, I’ll use CSV to create a structured log file. This will ensure that I can quickly pull up the log file in a spreadsheet program and look through the data, if necessary.
Adding Output to the Function
Notice below that I’ve also added the time to the PowerShell log function. This isn’t a parameter because this will always be the time the function was executed.
function Write-Log {
[CmdletBinding()]
param(
[Parameter()]
[ValidateNotNullOrEmpty()]
[string]$Message,
[Parameter()]
[ValidateNotNullOrEmpty()]
[ValidateSet('Information','Warning','Error')]
[string]$Severity = 'Information'
)
[pscustomobject]@{
Time = (Get-Date -f g)
Message = $Message
Severity = $Severity
} | Export-Csv -Path "$env:Temp\LogFile.csv" -Append -NoTypeInformation
}
That’s all there is to our Write-Log
function. We can now add this to any script we like as long as we dot-source it in first. If the Write-Log.ps1 script was in the same folder as the script we’re calling it from; we could dot-source it like $PSScriptRoot\Write-Log.ps1
.
Once the script knows about the function, it can then be called as many times as necessary in a script.
$foo = $false
if ($foo) {
Write-Log -Message 'Foo was $true' -Severity Information
} else {
Write-Log -Message 'Foo was $false' -Severity Error
}
The information would then get recorded to the log file which would look like this:
$foo = $false
if ($foo) {
Write-Log -Message 'Foo was $true' -Severity Information
} else {
Write-Log -Message 'Foo was $false' -Severity Error
}