This post introduces a class, ErrorRecordExtension, that handles PowerShell exceptions and supports the logging of said exceptions. All source code is provided at the end of the post in Appendix A. The ErrorRecordExtension class provides methods for cleaning up the formatting of the information provided when an exception is handled. The constructor for the ErrorRecordExtension class is defined at line 16 in the code snippet below:
Thursday, December 31, 2020
PowerShell: Handling/Logging Exceptions
PowerShell: Class Properties Returning Collections (ReadOnlyCollection)
When implementing a class or any code construct, it is critical to avoid side effects. One cause of side effects is when mutable data is provided as a parameter to a method, constructor or function. Additionally side effects can be caused when mutable data is assigned to a property. To demonstrate host to avoid side effects, consider the following the Friend class:
The first parameter to the constructor defined at line 8 is $name a string type. The string type is immutable. The second parameter is a string array named $tag and it should be recognized that the array type is mutable. Notice at line 10 the following code is invoked making a clone of the $tag string array:
The array created by $tag.Clone() is used to create a value of type of ReadOnlyCollection. The ReadOnlyCollection type cannot be modified hence it is immutable.
When the GetTags method is invoked (line 17) the value returned therefore cannot be modified by the caller and as the [ReadOnlyCollection[string]] is read-only. The following code demonstrates that the value return by the GetTag method of the Friend class is not subject to side effects:
Line 30 of the code above changes the array passed as a parameter to the constructor of the Friend class. The invoking of $tag.Clone at line means that any change to the array declared at line 26 does not affect $this.tag property of the Friend class. The output from lines 29 and 31 is as follows showing the Friend class instance has not been modified:
Not Invoking the Clone Method
Not using ReadOnlyCollection
Conclusion
The discussion in this post focused on the properties of classes and the parameters passed to constructors. The same issues with side effects be experienced by the parameters passed to functions or the parameters passed to class methods.
Correct Implementation
Wednesday, December 30, 2020
PowerShell: Working with UTC Date/Time Values, String Representations and Parsing
The previous post on PowerShell enumerations (see PowerShell: Enumerations) actually demonstrated PowerShell's support for UTC date/time, how to format UTC dates as text, and how to covert a string to UTC time. The sample code in the aforementioned post created a log entry class that uses UTC time versus local time (see line 25):
In the code above the Get-Date cmdlet retrieves the current/date time and the DateTime structure's ToUniversalTime method converts the local time to UTC.
When a log entry (class SimpleLogEntry) instance is written as a line of text so it can be logged, the code to perform this task is as follows (the ToString method of the SimpleLogEntry class):
The GetDateTmeText method above converts the date/time associated with log entry to text using:
The 'o' is one of .NET standard date/time formatters (see Standard date and time format strings). As the documentation from Microsoft below states, the 'o' format produces a string but can be parsed back to the original date:
The code that parses the date/time in string format in order to construct a new instance of SimpleLogEntry is as follows:
The code at line 41 first casts the string to a DateTime structure which creates a date/time object corresponding to local time:
Invoking the ToUniversalTime method converts the local time to UTC:
With that the round trip is complete from UTC date/time to string and back to UTC date/time.
PowerShell: Overriding Methods
The introduction of classes in PowerShell 5.1 gave PowerShell the ability to override methods. Every class in PowerShell is derived from the System.Object base class. The System.Object base class exposes the ToString method which is a virtual method meaning it can be overridden The previous blog post, PowerShell: Enumerations, contained an example of overriding the ToString method (see line 32):
The SimpleLogEntry class shown above is derived by default from the common base class, System.Common. C# developers will note that there is no use of explicate override keyword required in order to override ToString in the SimpleLogEntry class.
One cmdlet that takes invokes the ToString methods is Write-Host. An excerpt from the documentation for Write-Host (see Write-Host) is as follows showing that the cmdlet invokes ToString for the object passed in as a parameter (the object to be written to output in string form):
The following code (shown in the aforementioned blog post) passed an instance of type, SimpleLogEntry, to the Write-Host cmdlet (line 102):
Tuesday, December 29, 2020
PowerShell: Passing Enumeration Values as Function Parameters
In a previous post PowerShell enumerations were introduced (see PowerShell: Enumerations). One topic related to enumerations merits additional discussion, namely passing enumeration values to functions. In brief, when passing enumeration values to a function, the enumeration values must be surrounded by parentheses. In the example below line 20 (enumeration value wrapped in parentheses) succeeds when invoked while line 21 ((enumeration value not wrapped in parentheses) generates an exception:
The example of passing enumerations as function parameters in its entirety is as follows where line 20 passes an enumeration value bracketed by parentheses and line 21 passes an enumeration value sans parentheses:
Invoking line 20 (the enumeration passed with parentheses) displays the following output:
Log Level: Info (2)
Invoking line 21 (the enumeration passed without parentheses) generates an exception which is handled at line 25 (see code above). The first line of text displayed by line 27 is:
The error shown by line 28 is follows:
The correct way to pass enumeration values to functions in PowerShell should be clear: parentheses, parentheses, parentheses!
Appendix A: Code from Post
PowerShell: Enumerations
PowerShell 5.1 introduced classes (which were partially reviewed in post PowerShell: Classes Static Constructors, Static Methods, and Static Properties) and enumerations. Microsoft's documentation on enumeration describes them as (see About Enum):
An example of a too commonly defined (regardless of language) enumeration is as follows where the enumeration values are Error, Warn, and Info:
When displayed, by default, an enumeration value is displayed as text but each enumeration value is associated with a numeric value (Error = 0, Warn = 1, and Info = 2). The following script snippet demonstrates this:
The output from the above snippet is as follows:
Enumerations can be compared using standard numeric operators such as -eq, -ne, -le, -lt, -ge, and -gt. An example of comparing two enumerations is line 98 below which limits the logs displayed to being Error only or Error/Warning or Error/Warn/Info (a.k.a. the current log level):
The enumerations numeric values can also be used as array index. Consider the following enumeration also used the SimpleLogEntry class:
The code which converts a log entry to a line of text is as follows where each property of the SimpleLogEntry class is separated by a delimiter (a tab character) when converted to a string using the ToString method:
- Create an instance of SimpleLogEntry using the constructor that takes a LogLevel enumeration and a message parameter (lines 77-78)
- Get the string representation of the SimpleLogEntry using the ToString method (line line 79)
- Creates a second instance of SimpleLogEntry using the constructor that takes a string (a line of text created from ToString) as a parameter (lines 80-81)
- Get the string representation of the second SimpleLogEntry instance from ToString (line 82)
- Compare the string representation of both SimpleLogEntry instances and if they are equal the test was successful (lines 84-86)
- If the two instance of SimpleLogEntry do not match, throw an exception (line 88)
Appendix A: Script in its Entirety
Monday, December 28, 2020
PowerShell: Classes Static Constructors, Static Methods, and Static Properties
The previous two posts presented a practical implementation of a static class, PsUnit, in PowerShell (PowerShell: Unit Test Functions and Accessing the Invoking Code's Line Number and PowerShell: Unit Tests Compare Doubles for Equality). A static class does not need to be instantiated in order to invoke its properties and methods. In .NET one of the most commonly used static classes is the System.Math class that exposes fields such as (shown in their PowerShell form):
- $filenameLineNumberStart
- $filenameLineNumberEnd
- $filenameLineNumberSeparator
- $boolMismatchMessage
Sunday, December 27, 2020
PowerShell: Unit Tests Compare Doubles for Equality
Comparing double and single values (floating point numbers) can lead to rounding errors. The way to get around this is to define a tolerance meaning just how much of a difference is acceptable when comparing two floating point numbers. To demonstrate how compare floating point values using PowerShell the PsUnit class will be extended to support an AreEqual method with the following signature:
The PsUnit class was introduced in the post PowerShell: Unit Test Functions and Accessing the Invoking Code's Line Number. Recall from the aforementioned post that functions were used to wrap PsUnit methods in order to pass in the invoking code's filename and line number. The function to invoke the override of AreEqual that compares values of type double is AreEqualDouble: