Reading Time: 4 minutes, 26 secs

PowerShell: How to easily create log files for your scripts

Today I thought I would share some thing that I have developed over the last year or so as I have been working more and more with PowerShell…. some standard functions that can simply be dot sourced and called at any time so that all my scripts have some awesome logs to go along with the awesome script.

Why have logging?

Well personally I feel that this is a very important part of a script or tool that is developed, particularly if it is going to be used regularly and provides some sort of valuable functionality.

Having a log that people can follow, and see what is happening while the script is executing or if the script runs into errors is very useful. Not only that, but I feel people will respect your developed scripts \ tools as they see it as a mature product, not some dodgey back-yard operation that was just copied from the web and had the crap hacked through it.

The other reason is that it makes troubleshooting a hell of a lot easier… particularly 6 – 12 months down the track when lets say you are running the script in a different environment than what it was originally developed for. Having a log and being able to write out the result of each step of your script allows you to easily pin-point where the problem lies, especially if you pipe out error messages to the log (both custom or system errors).

Another great reason is having compassion on the guy the might be having to update or troubleshoot your script \ tool in the future. Its sort of like having well commented code (which I know everyone does… lol), it makes it easier for someone to be able to track your script and know what is happening and why its happening.

Finally, the reason why I personally like logging is because the way I layout all of my scripts is a seperate function per major task that the script completes. At the end of my scripts I then have an execution section where I call all of my functions in order and pass the required variables.

Using logging with this approach to development is great because it allows you to break your log into sections… each function has its own mini log section if you like, so it makes tracking the script really really easy and plus it looks awesome.

Logging Function Library: The contents

Becuase of the reasons above, I decided to create a logging function library which is essentially just a .ps1 file with a bunch of standard log functions. In each of my scripts I just dot source the .ps1 file and then call the each of the functions as required. The functions included in logging library are:

  • Log-Start: Creates the .log file and initialises the log with date and time, etc
  • Log-Write: Writes a informational line to the log
  • Log-Error: Writes an error line to the log (formatted differently)
  • Log-Finish: Completes the log and writes stop date and time
  • Log-Email: Emails the content of the log

Logging Function Library: Log Formatting

All of my scripts use this logging library and therefore all the logs look kinda the same. This is actually a good thing because it allows your user base to get used to a particular log format and so its just another incentive for them to use and enjoy your script that you worked so hard on.

Here is a screenshot of one of my logs that has been written using this logging function library

PowerShell Log Example 520x307 PowerShell: How to easily create log files for your scripts

Logging Function Library: The Code

Ok guys, enough rampling… here it is in all of its raw beauty:

Logging Function Library: Installation Instructions

Here are the instructions to start using this logging function library in your scripts:

  1. Copy the code above and save it in a new .ps1 file called “Logging_Functions.ps1″. Alternatively you can download the file from here: PowerShell Logging Function Library
  2. Copy the file and store it in a central location that everyone has access to (Note: This is very important otherwise your script will fail for people who don’t have access to the function library)
  3. In your script dot source the Logging_Functions.ps1 file. You should do this at the top of your PowerShell script and it should look something like this:
    		. "C:\Scripts\Functions\Logging_Functions.ps1"
    		
  4. Call the relevant functions as required (see the examples found in the meta information of each of the functions on how to do this)

PowerShell Script Template

If you are unsure on how to do step 4 above, or you would like to fill-out a standard template that have everything you need to create a new PowerShell script, then check out this post: PowerShell Script Template

If you have any problems using my PowerShell Logging Function Library then please let me know in the comments below or send me an email and I will try my hardest to get you all fixed up. Also, if you have any cool ideas or have some thoughts on how to improve the library then I am always intersted in hearing what others are doing and how I can improve myself.

Thanks guys and happy scripting icon smile PowerShell: How to easily create log files for your scripts

Luca

11 Likes
36 Comments.
  1. Kosta

    Hello, i am trying to use it in other script so i state:
    . “D:\scripts\Functions\Logging_Functions.ps1″
    Log-Start -logPath “D:\scripts\log” -LogName “service_check.log”

    but immediately when the script starts i get this error message:

    New-Item : Access to the path ‘D:\scripts\log’ is denied.
    At D:\scripts\Functions\Logging_Functions.ps1:53 char:17
    + New-Item <<<< -Path $LogPath -Value $LogName -ItemType File
    + CategoryInfo : PermissionDenied: (D:\scripts\log:String) [New-Item], UnauthorizedAccessException
    + FullyQualifiedErrorId : NewItemUnauthorizedAccessError,Microsoft.PowerShell.Commands.NewItemCommand

    I wonder why it has no access as it already written the log header.

    Thank you,
    Kosta

    • Luca Sturlese

      Hi Kosta,

      Thanks for the comment and I am glad that you are using the logging script.

      I had a look and line 53 is this “New-Item -Path $LogPath -Value $LogName –ItemType File”, which is the line that will create the log file, so in your case it is trying to create service_check.log file in D:\Scripts\Logs directory. Can you confirm that the context in which the script is running has at least modify permissions to this directory? Also can you have a look in the directory and see if the script actually creates the log file?

      The other thing I would try is create a test script using my PowerShell Script Template and see if you get the same error again.

      Hope this helps. If you still can’t figure it out, let me know the answers to the above questions and we can go from there.

      Thanks
      Luca

      • Andy

        The problem is with the line below and the -Value parameter
        New-Item -Path $LogPath -Value $LogName –ItemType File

        it should be -Name as below.
        New-Item -Path $LogPath -Name $LogName –ItemType File

        Other than that. Great re-usable scripts

        • Luca Sturlese

          Hi Andy,
          You are correct it should be -Name and now -Value. Strangely enough I am pretty sure that the Value parameter did work for me in the past but that might have been on a previous version of PowerShell (such as version 2).
          In any case, thanks very much for picking that up, I have now updated the code in the article.
          Thanks again
          Luca

  2. Caleb

    Hi Andy,

    Love the script. i’m using in most of mine scripts, Thanks
    Would it be possible to make it so that each time the script that calls the log function it adds to a previous log file and does not overwrite it?

    • Luca Sturlese

      Hi Caleb,

      Sorry about the late reply. Yes this is possible. In the Logging Function Library file just remove the following lines from the Log-Start function:


      #Check if file exists and delete if it does
      If((Test-Path -Path $sFullPath)){
      Remove-Item -Path $sFullPath -Force
      }

      Hope this helps

      Luca

  3. Matthew

    Thanks for the template and library. Is there a way with this to output into the log a stream? I”m trying to backup GPO’s and want it to actually output the results of the command using your template:

    Backup-GPO -All -Path $sPath

    Thanks. (I’m new to Powershell so still learning the ropes).

    • Luca Sturlese

      Hi Matthew,

      I am not 100% sure what you are asking but if you would like to print the log items out to screen as opposed to a text file you can use the cmdlet Write-Debug.

      As an example you can try this >>> Write-Debug "Hellow World". This should print this to the screen.

      Let me know if this is what you are after.

      Thanks
      Luca

  4. Caleb

    Hi Luca,

    And i’m sorry about my last message, Accidentally attention-ed it to the wrong person.
    Thank you for that, i am using this in every one of my scripts now!!!

    Regards
    Caleb

    • Luca Sturlese

      Hi Caleb,

      Thanks very much for the positive feedback and glad that you are using it… that is awesome!

      Regards
      Luca

  5. Albert

    Hi, that’s a wonderful, but i’m not pretty sure how to implement this script in my function in order to output the possible errors that could appear while executing the function. Could you help me??

    For example, If I want to include your function in a for each, how I have to call to your function??

    Thanks,

    • Luca Sturlese

      Hi Albert,

      Thanks for commenting. Take a look at my PowerShell Script Template because this gives you a template to build your scripts on using the PowerShell Logging Function Library. So for example if you want to write an information line into your log you would use the following Log-Write -LogPath $sLogFile -LineValue "...".

      If you would like to write an error to the log then use this Log-Error -LogPath $sLogFile -ErrorDesc "Error description goes here" -ExitGracefully $True. The best way to use the error logging function would be with using one of the error handling options available in PowerShell. The one that I find most useful and that I use (and is documented in the PowerShell Script Template) is Try… Catch. Have a look at the PowerShell Script Template post and it is all documented there.

      If you still stuck, just let me know and I can help you out.

      Thanks
      Luca

  6. Casper

    Hi Luca,

    I would like to know how to use Log-Error. For Example I got line in script:

    Import-Clixml d:\something.xml and when imported file doeasnt existx i got error. I can use

    Log-Write -LogPath $LogFile -LineValue ($error[0] | out-string)

    But how to use Log-Error? All my tryes end with:

    Log-Error : Cannot bind argument to parameter ‘ErrorDesc’ because it is an empty string.
    At D:\SKRIPTS\POWERSHELL\Create_User_in_AD.ps1:19 char:40
    + Log-Error -LogPath $LogFile -ErrorDesc $_.Exception -ExitGracefully $True
    + ~~~~~~~~~~~~
    + CategoryInfo : InvalidData: (:) [Log-Error], ParameterBindingValidationException
    + FullyQualifiedErrorId : ParameterArgumentValidationErrorEmptyStringNotAllowed,Log-Error

    Thank you.

    • Luca Sturlese

      Hi Casper,

      Can you show me the exact line of code you are having trouble with?

      What I would do is try something like this:


      $sError = $Error[0] | Out-String
      Log-Error -LogPath $sLogFile -ErrorDesc $sError -ExitGracefully $True

      Give that a go and see if that works.

      Thanks
      Luca

  7. Manuel

    Hi Luca
    This is a very useful function library, thanks a lot. I will use it in all my new scripts :-)
    Manuel

  8. Mohammad Taha

    I have this error
    Log-Error : Cannot bind argument to parameter ‘ErrorDesc’ because it is an empty string.

    i tried to use $Error and $error[0] and $sError = $Error[0] | Out-String
    but no Luke could you please help

    • Luca Sturlese

      Hi Mohammad,

      Can you please send through via email or reply to this post and extract of your code so I can see what is happening?

      Thanks
      Luca

  9. sagar

    Lucas,
    Even after removing the below script, I am still not able to append the data to the log file. It fails saying the log file already exists.

    #Check if file exists and delete if it does
    If((Test-Path -Path $sFullPath)){
    Remove-Item -Path $sFullPath -Force
    }
    Also I am trying to capture the error and using the function log-error, but i cannot capture the error…
    try{
    Invoke-Sqlcmd -query “select top 10 * from sales”
    Log-Write -LogPath $sLogFile -LineValue “step 2-altered the table : $tblname”
    }
    catch
    {
    write-output(“starting catch block”)
    Log-Error -LogPath $sLogFile -ErrorDesc $sError -ExitGracefully $True
    Break
    }
    If that table doesn’t exist i want to capture that error. But it’s displaying on the ps screen without capturing it.

  10. Don

    Also note on line 53 the dash (–ItemType File) isn’t correct, I believe it is the em dash and will cause a “missing the terminator” parse error at the end of the script. In the above script notice the highlight of the dash. Also with the downloaded version. Other than a few other minor errors noted, a great script, thanks for sharing Luca!

    • Luca Sturlese

      Thanks Don for pointing that out. Not sure how that happened. Must of converted when I moved all of my scripts to GitHub. I have fixed that and should all be ok now. Thanks again.

  11. Thanh-Nu

    Hi Luca,
    Thanks for sharing your Logging_Functions. what are the pro/ and cons of using this as a ps1 file, and “dot source” it like you show in your template, rather than include your functions in a module (Logging_Functions.psm1), then import-module in your profile? Which way you would recommand?

    Thanks again for this useful library.

    • Luca Sturlese

      Hi Thanh,

      Either way works, but there are two reasons why I don’t import the and my other functions as modules:

      1. If I am just using PowerShell to do small things, I generally don’t want to output to a log file – the results on screen are good enough.

      2. Usually when I am writing a script that requires logging I will be sharing it to be run by a number of people on different machines (e.g. IT admins). For this reason if I store my functions in a central accessible location (like a file share), then it is available to everyone running the script without them having to do anything fancy.

      Let me know your thoughts and how you would use the logging functions.

      Thanks
      Luca

  12. Ricco

    New-Item : En del af stien ‘C:\Temp\’ blev ikke fundet.
    At C:\Users\Ricco\Desktop\Logfile.ps1:56 char:13
    + New-Item <<<< -Path $LogPath -Value $LogName –ItemType File
    + CategoryInfo : WriteError: (C:\Temp\:String) [New-Item], DirectoryNotFoundException
    + FullyQualifiedErrorId : NewItemIOError,Microsoft.PowerShell.Commands.NewItemCommand

    The library is created c:\temp and It creates the file, but nothing else.

    • Luca Sturlese

      Hi Ricco,

      Can you please try download another version of the PowerShell Logging Function? I just made a change to line 53 (courtesy of the comment by Don) which will resolve that issue.

      Thanks
      Luca

  13. Paul

    @sagar
    Just change the logic slightly

    If((Test-Path -Path $sFullPath) -eq $false){
    #Create file and start logging
    New-Item -Path $LogPath -Name $LogName -ItemType File

    }

  14. Leroy

    Luca
    Great Template + Logging! I will be using these going forward.
    What I’d like to do is log all verbose output in my functions to the log file that your template is using. Do you know of a way to redirect verbose output to this log? For example, on a command if I add the common parameter -Verbose it displays the output in the shell, but I’d like that information logged into the .log file that your template is using. It doesn’t appear that your Log-Write cmdlet accepts pipeline input.

    • Luca Sturlese

      Hi Leroy,

      What you can do is something like this .... | Log-Write -LogPath "C:\Windows\Temp\Test_Script.log" -LineValue $_

      $_ is a special variable in PowerShell and is the variable that is passed via pipeline.

      Give that a go… hope that solves the problem.

      Thanks
      Luca

  15. Andreas

    Hello,
    I’m new to powershell and I was looking for “how to log in powershell” and found your script and your script template.
    But I think it doesn’t work completly how I’m using it.
    The logfile is created and the starting event and the closing event are in the logfile. But I didn’t get any output on the screen and the log entries from my functions are also not in the file (the write-host is printed).
    Here is one of my functions
    Function Import_Suppliers{

    [CmdletBinding()]

    Param ([Parameter(Mandatory=$true)][string] $fFile, [Parameter(Mandatory=$true)][string] $fDelimiter)

    Begin{
    Log-Write -LogPath $sLogFile -LineValue “Oeffnen der Datei” + $fFile
    }
    Process{
    Try{
    $Dataset = Import-Csv -path $fFile -Delimiter $fDelimiter
    return ,$Dataset
    }
    Catch{
    Log-Error -LogPath $sLogFile -ErrorDesc $_.Exception -ExitGracefully $True
    Break
    }
    }
    End{
    If($?){
    Log-Write -LogPath $sLogFile -LineValue “Oeffnen der Datei ” + $fFile + ” Erfolgreich beendet.”
    Log-Write -LogPath $sLogFile -LineValue ” ”
    }
    }
    }

    And this is the content of the log
    ***************************************************************************************************
    Started processing at [09/06/2014 13:14:51].
    ***************************************************************************************************

    Running script version [1.0].

    ***************************************************************************************************

    ***************************************************************************************************
    Finished processing at [09/06/2014 13:14:52].
    ***************************************************************************************************

    Kind regars from germany
    Andreas

    • Luca Sturlese

      Hi Andreas,

      The reason why it isn’t writing any lines to your log file is because you cannot do string concatenation in the -LineValue attribute. To resolve this can you do either of the following:

      1. Create a variable with the line value you want to write to the log and then use that variable for the -LineValue attribute. See example below:

      $Line = “Oeffnen der Datei” + $fFile
      Log-Write -LogPath $sLogFile -LineValue $Line
      

      2. Move the variable directly into the “” quotes. When PowerShell executes it will insert the variable data in as opposed to the variable name. This is a standard PowerShell feature and works in all double quotes “” (Note: This does not work with singles quotes – ”). See example below:

      Log-Write -LogPath $sLogFile -LineValue “Oeffnen der Datei $fFile”
      

      Hope this helps.
      Luca

  16. Andreas

    Hi Luca,
    I have implemented solution 2 and it works.
    But I have another question I execute a .exe in “batchmode”. When I execute the command directly in the shell it generates output in the shell. Livelog would discribe it, I think.
    The command is called via “cmd /c …”.
    I tried to redirect the output via cmd /c …. | Log-Write -LogPath $sLogFile -LineValue $_
    But I get the following error:
    “Error: An error has occurred [System.Management.Automation.ParameterBindingValidationException: Das Argument kann nicht an den
    Parameter “LineValue” gebunden werden, da es sich um eine leere Zeichenfolge handelt.”
    In english:
    The argument can not be bind to the parameter “LineValue” because it is an empty string…”
    Would be nice if this is possible.

    Output Example:
    FlowHeater (R) Batch Modul: Version 3.3.4

    Start: 08.09.2014 08:03:44
    Set Parameter [file], Wert [Lieferanten.csv]

    Rows Read : 31
    Rows Fitter : 31
    Rows Write : 31

    End: 08.09.2014 08:03:46

    Kind regars from germany
    Andreas

  17. Leroy

    Luca
    Thanks for your reply earlier.
    I guess what I’m getting at is:
    How would you edit your script to accept pipeline input? I’ve tried adding the parameter for ValueFromPipeline=$true, but that produces errors.
    For example, i’d like the ability to do something like:
    get-service | Log-Write -LogPath $sLogFile -LineValue $_
    Thanks!

  18. skai

    Great !
    One detail : I *do* hate code duplication,
    so : is it possible in my scripts to create an ‘alias’ or a ‘wrapper function’ to replace all the calls to :

    Log-Write -LogPath $log -LineValue “blah blha”
    by :
    logw “blah”

    I’ve tried the function, but can’t set it up correctly,
    I’m new to powershell and still learning, (with heavy nix background that does not help in this case).

    • Luca Sturlese

      Hi Skai,

      Unfortunately it isn’t that easy as you can’t really create alias for PowerShell functions. You could essentially convert my function library into a PowerShell module and then import the module into your script. You could then attempt to build an alias around the function within the module, as per this article here. I haven’t ever tried it so I am not sure exactly how it would work, but give it a go.

      Another solution you could use is create another function in your script called logw and have one parameter which is the line value. Then essentially you could run logw “blah” and it would work. Below is a function that you could use:

      Function logw{
        Param ([Parameter(Mandatory=$true)][string]$Data)
      
        Log-Write -LogPath "YOUR LOG FILE PATH OR VARIABLE CONTAINING FILE PATH" -LineValue $Data
      }
      

      Hope this helps.

      Thanks
      Luca

  19. skai

    In fact I would propose a change :

    in a script or profile, define :
    function log { Log-Write -LogPath $log -LineValue $args }

    that can be called like this :
    log “blah blah”
    log “a” “b” “c”

    And in your code :

    Function Log-Write{
    [CmdletBinding()]
    Param ([Parameter(Mandatory=$true)][string]$LogPath, [Parameter(Mandatory=$true)][array]$LineValue)
    Process{

    $LineValue | ForEach-Object{
    Add-Content -Path $LogPath -Value $_.toString()
    Write-Debug $_.toString();
    }

    }
    }

    something along this line

  1. By PowerShell Script Template | 9to5IT on February 19, 2013 at 11:07 pm

    […] I recently put up an article on how to easily create log files in PowerShell. If you want to read that post, then check out this link – PowerShell: How to easily create log files for your scripts. […]

  2. […] Source code for the PowerShell script. Wrapped it into a .exe with PowerShell Studio 2012. I have only tested this on Windows 7 x64 with PowerShell 3.0 / 2.0. Log-functions are from 9to5it […]

Leave a Comment.