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.
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 PowerShell log 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 PowerShell log 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 PowerShell Log 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
}