The PowerShell function Write-LogEntry described in this post allows you to integrate logging in your scripts in a standardized way. This will help you and your script users to troubleshoot and understand the output.

Josh Rickard

Josh's primary focus is in Windows security and PowerShell automation. He is a GIAC Certified Windows Security Administrator (GCWN) and GIAC Certified Forensic Analyst (GCFA). You can reach Josh at MSAdministrator.com or on Twitter at @MS_dministrator.

Using Write-LogEntry ^

The function offers a few parameters that allow you to log different outputs types, such as informational, debug, and error information. Each one of these parameter options belongs to a parameter set.

In addition to being able to write errors out, we can also pass any $error[0] variables that may hit a catch block in your script. The Error and ErrorRecord parameters belong to the same parameter set. This means that you can only use the ErrorRecord parameter in combination with the Error parameter.

Here are some examples of the output that Write-LogEntry provides:

A log file created with Write LogEntry

A log file created with Write LogEntry

Explaining the Write-LogEntry function ^

Have a look at the function below first. I will explain the crucial parts in detail below.

In addition to the three parameters discussed above, we have an additional parameter you can use to specify where to create the log file (if not already created). The default value for this parameter uses the automatic variable $ExecutionContext. By traversing the available properties on $ExecutionContext, we can find the calling scopes path and create a log.log file in the folder where your script is located.

Based on the parameter set you have chosen, we have a series of output formatting defined. The decision on which format to use depends on your selection. Write-LogEntry verifies your selection and applies that formatting based on a switch statement. This switch statement uses the Keys property of the $PSBoundParameters automatic variable to identify the parameter(s) used. The $PSBoundParameters variable stores a hashtable that contains the parameters passed to the function.

Depending on which parameter you used when calling the function, a separate Add-Content call formats a prefix with the current time format (yyyyMMddThhmmss), which equates to 20170416T184532. We also add the log type called and the string passed to that parameter.

At the top of the function, we create a new System.Threading.Mutex object. The Mutex object ensures we will not receive a warning or error if we attempt to write to the log file while another thread is using the file. A Mutex object (System.Threading.Mutex) essentially ensures that only one thread at a time uses the resource, the log file in our case.

Before we open the log file to write the desired content, we block the current thread until the process signals that it's ready to write the content. After we have written to our log file using the Add-Content cmdlet, we close that Mutex thread by calling the ReleaseMutex() method.

You may have noticed the Error switch statement has a few more lines of code than the other statements (Debugging and Info). The "error" ParameterSet has two parameters available: Error and ErrorRecord.

If you choose to use the "error" ParameterSet then the Error parameter is mandatory. You can use this function by just passing a string to the Error parameter, but we also can pass an $error variable to an optional parameter called ErrorRecord.

If you have passed an $error variable to the ErrorRecord parameter, you can identify it with the following if statement. This statement uses the $PSBoundParameters ContainsKeys() method to determine whether the ErrorRecord variable has been passed into the function. If the ErrorRecord parameter was used, then this statement parses the $error variable to a more readable format. By using string formatting, we can modify the output so that it's easy to read.

Instead of having a traditional error output like the following:

We have the ability to parse out the necessary properties on the $error[0] record to a more readable format:

Conclusion ^

Like writing help text or documenting scripts, logging is not a glorious task. The Write-LogEntry function simplifies this task for you and standardizes logging in your scripts. This helps with troubleshooting and helps users of your scripts to understand the output. You can find the latest version of my Write-LogEntry tool on GitHub.

Win the monthly 4sysops member prize for IT pros

Share
1+

Related Posts

5 Comments
  1. Fox 8 months ago

    Excellent function! Great timing too, as I was just starting to add some logging functionality to my script.

    1+

  2. Brandon 8 months ago

    Fantastic logging function. I just finished writing my first one to start properly tracking errors in my scripts. Yours is much more polished and useful and I'm definitely not going to re-invent the wheel! Thanks!

    0

  3. LostAtC 6 months ago

    I believe for the date-time stamp you really want the 24 hour format ("HH"):
    (Get-Date).ToString('yyyyMMddTHHmmss')

    Personally I prefer the built in formatting which is a bit easier to read:
    Get-Date -Format 's'

    0

  4. Cédric 5 months ago

    Hello,

    It seems you are creating a new mutex everytime you call the function, instead of using the same one. As a result, I don't think you're handling concurrent accesses at all since you are locking a different mutex each time you call the function.

    0

    • Cédric 5 months ago

      I'll reply to my own question ! Apparently, when you call New-Object with the same mutex name, you're not creating a new mutex, but a new handle to the same mutex.

      0

Leave a reply

Your email address will not be published. Required fields are marked *

*

CONTACT US

Please ask IT administration questions in the forum. Any other messages are welcome.

Sending
© 4sysops 2006 - 2017

Log in with your credentials

or    

Forgot your details?

Create Account