© Adam Bertram 2020
A. BertramBuilding Better PowerShell Codehttps://doi.org/10.1007/978-1-4842-6388-4_7

7. Log Script Activity

Adam Bertram1  
(1)
Evansville, IN, USA
 

If you don’t know what your code is doing, how are you supposed to troubleshoot it? How are you supposed to optimize it? To show what it changed in an environment? Log everything!

Especially on long-running scripts or scripts executed in production, you must bake logging routines into your code. It’s not only helpful to monitor activity when things go well, it’s especially helpful when problems arise that need investigation.

In this chapter, you’ll learn some tips on how to best implement logging in your PowerShell scripts.

Use a Logging Function

Logging to a text file is an extremely common need. Great scripts log everything and do it a lot. This seems like a good opportunity to build a little tool to do that for us!

You should have or be building up an arsenal of small helper functions. A Write-Log function needs to be in that arsenal somewhere. By creating a function with a few parameters like Message, Severity, etc., which then records information to a structured text file, is a must-have.

For example, let’s say you find yourself constantly copying/pasting the same line of code over and over again in your scripts like the following. You want to record the status of your scripts using Add-Content.
Add-Content -Path 'C:activity.log' -Value "Doing something here"

This method gets the job done but has a few of problems. For starters, you’re repeating yourself. Don’t do that. Second, what happens if you suddenly want to change up how you’re logging information? Maybe you want to include a timestamp in the output or even create a structure allowing you to define messages by severity, category, and other criteria.

Logging information is a great opportunity to create a Write-Log function. The choice is yours how you’d like your Write-Log function to behave, but in the following you’ll find a good example.

Rather than calling Add-Content over and over, instead, you can load the following function into your session and run Write-Log. This function is a good example of a simple yet handy logging function. It:
  • Creates and appends lines to a CSV-formatted file called activity.log. By creating a CSV file, you can then easily parse it with Import-Csv and other utilities.

  • Adds a Severity parameter. By passing different values to the Severity parameter, you can differentiate message importance and filter on severity when reading the log later.

  • Adds a Source property. This is an advanced technique which shows you the name of the script or module the function was invoked from as well as the line number.

  • Adds a Time property. Timestamps are critical in log files. Now you will always get a timestamp written to the log file.

function Write-Log {
    [CmdletBinding()]
    <#
        .SYNOPSIS This function creates or appends a line to a log file
        .DESCRIPTION This function writes a line to a log file
            .PARAMETER Message
            The message parameter is the log message you'd like to record to the log
            file
        .PARAMETER LogLevel
            The logging level is the severity rating for the message you're recording.
            You have 3 severity levels available; 1, 2 and 3 from informational messages
            for FYI to critical messages. This defaults to 1.
        .EXAMPLE
            PS C:> Write-Log -Message 'Valuell -LogLevel "Value2'
            This example shows how to call the Write-Log function with named parameters.
    #>
    param (
        [Parameter(Mandatory)]
        [ValidateNotNullOrEmpty()]
        [string]$Message,
        [Parameter()]
        [ValidateNotNullOrEmpty()]
        [string]$FilePath = "$PSScriptRootactivity.log",
        [Parameter()]
        [ValidateSet(1, 2, 3)]
        [int]$LogLevel = 1
    )
    [pscustomobject]@{
        'Time'     = (Get-Date -Format 'MM-dd-yy HH:mm:sstt')
        'Message'  = $Message
        'Source'   = "$($MyInvocation.ScriptName | Split-Path -Leaf):$($MyInvocation.ScriptLineNumber)"
        'Severity' = $LogLevel
    } | Export-Csv -Path $FilePath -Append -NoTypeInformation
}

Further Learning

Clean Up Verbose Messages

Think of a PowerShell script as a piece of software. Software has three rough stages of creation: development, testing, and production. It’s a shame so many scripts out there are “in production” but still have development code throughout.

One example of “development code” in a script is all of those Write-Verbose lines. Developers use Write-Verbose to troubleshoot and debug code while it’s being developed. That code isn’t necessary when the code is solid. You don’t need to return minute, granular details you required when debugging in the final product. Remember to clean all of those debugging messages up before signing off.

Let’s say you’ve been working on a script for a few days and needed to return some variable values to track what a variable’s value is at a specific point in time. Take the following script, for example. Perhaps you call this script in a larger automation workflow.
[CmdletBinding()]
param(
    [Parameter()]
    [string]$ComputerName,
    [Parameter()]
    [string]$FilePath
)
Get-Content -Path "\$ComputerName$FilePath"
You’ve been noticing that this script returns an error sometimes trying to access a bogus file. You need to know what values are being passed to the FilePath parameter so you decide to add a Write-Verbose reference.
## read-file.ps1
[CmdletBinding()]
param(
    [Parameter()]
    [string]$ComputerName,
    [Parameter()]
    [string]$FilePath
)
Write-Verbose -Message "Attempting to read file at [\$ComputerName$FilePath]..."
Get-Content -Path "\$ComputerName$FilePath"
You then call this function using the Verbose parameter.
./read-file.ps1 -ComputerName FOO -FilePath 'bar.txt' -Verbose

You will then see the familiar verbose line as shown here:

../images/501963_1_En_7_Chapter/501963_1_En_7_Figa_HTML.jpg

Verbose messaging isn’t necessarily a bad thing. After all, you can control when and when not to show this stream using the Verbose parameter or the VerbosePreference automatic variable. However, this behavior can become a problem when you have random lines throughout your scripts that make no sense to anyone other than your current self.

Ensure verbose message is clear, concise, and you don’t overdo it.

Tip Source: https://twitter.com/JimMoyle

Further Learning

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
18.118.144.69