Expert Solution for 2011 Scripting Games Beginner Event 9:Use a PowerShell Function to Simplify Script Logging

Expert Solution for 2011 Scripting Games Beginner Event 9:Use a PowerShell Function to Simplify Script Logging

  • Comments 3
  • Likes

Summary: Microsoft PowerShell MVP, Jonathan Medd, shows beginners how to create a function to simplify script logging in Event 9 of the 2011 Scripting Games.

Microsoft Scripting Guy, Ed Wilson, here. Today we have Jonathan Medd to provide his solution for Beginner Event 9.

Photo of Jonathan Medd

Jonathan Medd has been working with IT infrastructure products since 1997. A few years ago, he discovered Windows PowerShell, and he now cohosts the Get-Scripting PowerShell podcast. In April 2010, he was awarded status as a Microsoft MVP.

Jonathan's contact information:
Blog: Jonathan Medd's Blog
Twitter: jonathanmedd

Worked solution

This event requires adding the ability to create a log file to one your scripts. The best way to achieve this, I thought, would be to create a function. Windows PowerShell 2.0 added a number of features to enable the scripter to produce advanced functions, and we will use some of these in the Write-LogFile function.

In this solution, we need to think about the main criteria of the event, which is the ability to write data to a log file as part of a script and name that file with the current date. By adding additional parameters to the function, I was able to meet the flexibility objectives: a chosen path, a file extension, and how to handle an existing file of the same name. I decided that although the event requirement was to prompt for a new file name if an existing log file of the same name already existed, it would be better to offer an option to overwrite or append to an existing log file. However, I will show you at the end how you could instead prompt for a response.

First of all, take a look at the Write-LogFile function, and then I shall cover the main learning points.

function Write-LogFile {

 

<#

      .SYNOPSIS

            Output data into a log file.

 

      .DESCRIPTION

            Output data into a log file. Options for path, extension and overwrite.

 

      .PARAMETER  LogData

            Data to be logged.

 

      .PARAMETER  FolderPath

            Path of the folder to store the log file in.

     

      .PARAMETER  Extension

            Use a different file extension other than .log .

           

      .PARAMETER  Overwrite

            Specify to overwrite existing log file.

 

      .EXAMPLE

            PS C:\> Write-LogFile -LogData $string -FolderPath 'C:\Logs' -Overwrite

 

      .EXAMPLE

            PS C:\> $string | Write-LogFile -FolderPath 'C:\Logs' -Extension 'txt'

 

#>

 

      [CmdletBinding()]

      param(

            [Parameter(Position=0, Mandatory=$true, ValueFromPipeline=$true, HelpMessage="Data to be logged")]

            [ValidateNotNullOrEmpty()]

            [String]

            $LogData,

            [Parameter(Position=1, Mandatory=$true, HelpMessage="Path of the folder to store the log file in")]

            [ValidateNotNullOrEmpty()]

            [String]

            $FolderPath,

            [Parameter(Position=2)]

            [String]

            $Extension = 'log',

            [Parameter(Position=3)]

            [Switch]

            $Overwrite

      )

     

      process {

     

            try

            {    

                  $Filename = [string](Get-Date -format yyyyMMdd) + '.' + $Extension

                 

                  if ($Overwrite){ 

                  $LogData | Out-File $FolderPath\$Filename

                  }

                  else {

                  $LogData | Out-File $FolderPath\$Filename -Append

                  }    

            }

           

            catch [System.IO.DirectoryNotFoundException]

            {

            Write-Host -ForegroundColor Red "The FolderPath $FolderPath does not exist. Please use a valid folder to store the log file in."

            }

      }

}

The first section encapsulated by the <# and #> is a Windows PowerShell 2.0 feature that allows you to include your own Help information in a function or script. The user is then able to get a similar Help experience as that of a full-fledged Windows PowerShell cmdlet. You can see in the following image how this could be used with the Write-Logfile function.

Get-Help Write-LogFile -Examples

Image of command output

Within the parameter section of the function, I specify four parameters: $LogData, $FolderPath, $Extension, and $OverWrite. With the Windows PowerShell 2.0 advanced functions, I can specify options for each of these parameters so that they behave in a way that I require.

Tip: To find out more about advanced functions, type Get-Help about_functions_advanced.

$LogData and $FolderPath are both marked as Mandatory, and they have a HelpMessage. Executing the function without either of these parameters will result in the user being prompted for values. The HelpMessage can be viewed by entering !?.

Image of command output

$LogData and $FolderPath also use the option [ValidateNotNullOrEmpty()] to ensure at least something tangible has been supplied to them. The following image shows what happens if this is not the case.

Image of command output

I set the $Extension parameter to ‘log’ by default, but users can change it if they wish when executing the function. Finally, the $Overwrite parameter allows us to specify if we wish to overwrite the existing log file if it already exists. By specifying that the parameter is a switch parameter, the Overwrite option is either on or off (by default in this case).

The actual code for the actions is now very straightforward. I create the file name by using Get-Date and the supplied extension.

Tip: to get the format of the date to match the requirement of the event, use the Format parameter with the options we need. For a great expansion of this topic, see Formatting Dates and Times in Windows PowerShell Tips on TechNet.

The data to output is then written to the log file, either appending or overwriting dependent on whether the $Overwrite parameter has been set. So to output the string ‘This is a test’ to the folder C:\Logs with an extension of txt and to overwrite an existing file, we would use:

Write-LogFile 'This is a test' -FolderPath C:\Logs -Extension 'txt' -Overwrite

Because I set the $LogData parameter to accept pipeline input, we can also use the Write-Logfile function in a pipeline:

'This is a test'  | Write-LogFile -FolderPath C:\Logs -Extension 'txt' -Overwrite

Image of command output

I have also built in some basic error checking through a Try…Catch block, so if the folder path that is supplied does not exist, a custom error will be displayed.

Write-LogFile 'This is a test' -FolderPath C:\BadPath -Extension 'txt' -Overwrite

Image of command output

Tip: Hey! Scripting Guy wrote a blog with a great introduction to how you can use Try…Catch...Finally blocks in your scripts.

At the beginning of this blog, I mentioned how I chose to offer an Overwrite parameter rather than prompting for input if the logfile already existed. To meet the exact objective of the event in that respect, you could use something like the following in the script instead. Note that Read-Host doesn’t have a ForegroundColor parameter like Write-Host does; however, you can achieve a similar effect by using [console]::ForeGroundColor before Read-Host and then resetting it afterwards.

If (Test-Path $Folderpath\$Filename){

[console]::ForegroundColor="Yellow"

$NewFilename = Read-Host "$Folderpath\$Filename already exists. Please enter a new file name"

$LogData | Out-File $FolderPath\$NewFilename

[console]::ResetColor()

}          

Else {    

$LogData | Out-File $FolderPath\$Filename        

}

 

The entire script can be found in the Script Repository.

Thank you for your solution, Jonathan.

I invite you to follow me on Twitter and Facebook. If you have any questions, send email to me at scripter@microsoft.com, or post your questions on the Official Scripting Guys Forum. See you tomorrow. Until then, peace.

Ed Wilson, Microsoft Scripting Guy

Your comment has been posted.   Close
Thank you, your comment requires moderation so it may take a while to appear.   Close
Leave a Comment
  • Hello Jonathan,

    as I know that you are a soccer fan: congrats fto the 0:2 against Schalke!

    The second part of the match should not be more difficult, I suppose ...

    An excellent solution! And I used the same format parameter "trick", too!

    Everything is Ok but again, as always, even if you did provide some error handling

               catch [System.IO.DirectoryNotFoundException]

    we may certainly encounter the problem, that others error should have been caught!

    If I want to write to $FolderPath\$Filename it may be impossible because I have no

    rights to write to this location!

    kind regards, Klaus

  • Put something similar up on PoshCode, check it out: http://poshcode.org/2575

    On a side note, we shouldn't have to do this! What I would of really liked to of seen is a -File parameter for the Write-Warning, Write-Error, Write-Verbose cmdlets.

  • thank you