How to create a log file for your PowerShell scripts

I am a great fan of the KISS method, while KISS stands for Keep It Simple Stupid.
Fortunately, there are two built-in cmdlets in PowerShell to make it easy to create log files: Start-Transcript and Stop-Transcript.

However, keep in mind that you must use a maximum of your script content with the Verbose parameter. Furthermore, you can also use the Write-Output cmdlet to write your personal messages to the log file. Otherwise, your log file will just be empty, or only contain error messages…

Also note that the Write-Host cmdlet doesn’t write to the log file, neither to any other output other than the console. That’s why, as I said above, you should use the Write-Output cmdlet.

You must also think about where you want to store your log file(s) and how many of them you want to keep.

Here are three use cases

Unique log file

You want only one log file which is overwritten each time the script is executed.

In the case of one log file, my preference is to keep it in the same folder as the script. Thus you immediately see the script and the log together

I use an automatic variable named MyInvocation to find the path to my running script and replace the .ps1 extension with the .log extension via the Replace method and a regular expression to build the path to the log file.

$Logfile = $MyInvocation.MyCommand.Path -replace '\.ps1$', '.log'
Start-Transcript -Path $Logfile

#Doing some stuff with the Verbose parameter
Get-ChildItem -Verbose
Get-Service -Verbose
Get-Process -Verbose

Write-Output 'Writing some text to the log file'

Stop-Transcript

Two log files

You want two log files: the last run and the run before.

In the case of two log files, my preference is to keep them in the same folder as the script. If you have a folder with several scripts and two log files for each script, it is still readable and clear.

First I remove the old log file, then I rename the current one to .log and finally, I can create a new one.

$OldLogfile = $MyInvocation.MyCommand.Path -replace '\.ps1$', '.log.old'
$NewLogfile = $MyInvocation.MyCommand.Path -replace '\.ps1$', '.log'
#Removing the .log.old file
If(Test-Path -Path $OldLogfile) {Remove-Item -Path $OldLogfile}
#Renaming the .log to .log.old
If(Test-Path -Path $NewLogfile) {Rename-Item -Path $NewLogfile -NewName $OldLogfile}

#Starting with a fresh .log file
Start-Transcript -Path $NewLogfile

#Doing some stuff with the Verbose parameter
Get-ChildItem -Verbose
Get-Service -Verbose
Get-Process -Verbose

Write-Output 'Writing some text to the log file'

Stop-Transcript

Multiple log files

You want a longer history than only the last run and the former one.

In this case, my preference is to keep them in a subfolder named Logs or whatever you want.

However, you must also keep in mind that you will have plenty of logs and that you must think to a way removing unnecessary history.

And in this case, the beginning of the script will be a bit more complicated…

Without explaining every detail, here is what it does

  • Every log file has a time stamp to make it unique in the folder
  • Every time the script runs it keeps only the latest log files and removes the older ones
  • $CurrentPath = Split-Path -Path $MyInvocation.MyCommand.Path -Parent
    $LogPath = Join-Path -Path $CurrentPath -ChildPath 'Logs'
    $LogRootName = (Split-Path -Path $MyInvocation.MyCommand.Path -Leaf) -replace '\.ps1$', ''
    $TimeStamp = Get-Date -Format yyyyMMdd_HHmmss
    $LogFileName = '{0}_{1}.log' -f $LogRootName, $TimeStamp
    $LogFile = Join-Path -Path $LogPath -ChildPath $LogFileName
    #Change this value to how many log files you want to keep
    $NumberOfLogsToKeep = 10
    
    If(Test-Path -Path $LogPath)
    {
        #Make some cleanup and keep only the most recent ones
        $Filter = '{0}_????????_??????.log' -f (Join-Path -Path $LogPath -ChildPath $LogRootName)
    
        Get-ChildItem -Path $Filter |
            Sort-Object -Property LastWriteTime -Descending |
            Select-Object -Skip $NumberOfLogsToKeep |
            Remove-Item -Verbose
    }
    Else
    {
        #No logs to clean but create the Logs folder
        New-Item -Path $LogPath -ItemType Directory -Verbose
    }
    
    Start-Transcript -Path $Logfile
    
    #Doing some stuff with the Verbose parameter
    Get-ChildItem -Verbose
    Get-Service -Verbose
    Get-Process -Verbose
    
    Write-Output 'Writing some text to the log file'
    
    Stop-Transcript
    

    More about

    About Automatic variables (Microsoft Docs)

    Start-Transcript (Microsoft Docs)

    Leave a Reply

    Please log in using one of these methods to post your comment:

    WordPress.com Logo

    You are commenting using your WordPress.com account. Log Out /  Change )

    Google+ photo

    You are commenting using your Google+ account. Log Out /  Change )

    Twitter picture

    You are commenting using your Twitter account. Log Out /  Change )

    Facebook photo

    You are commenting using your Facebook account. Log Out /  Change )

    Connecting to %s