How to Build a Logging Function in PowerShell

Adam Bertram

Adam Bertram

Read more posts by this author.

Keeping tabs on what a script is doing is critical for monitoring and debugging. Monitoring a script can be done in many different ways, but it is usually dependent on how it’s being executed. 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.

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.

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.

Notice below that I’ve also added the time. 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
}

Subscribe to Adam the Automator

Get the latest posts delivered right to your inbox

Looks like you're offline!