When it comes to Windows PowerShell, in most instances, I deliver pretty much complex scripts to bridge the gap between management systems that cannot communicate directly with each other. Usually these script solutions will be hooked into a Whatever Automation Suite that has control over the IT workflows. A mandatory requirement is that the script passes information back to the caller, be it an exit code, a message string, or an API call, you name it. Therefore, I’ve written a PowerShell template for a controller script that already includes the code to deal with multiple logical steps, with exceptions, and passing back corresponding information. I decided to share a simplified edition of that template with the readers of this blog (it’s on GitHub). I consider it a good starting point to build a controller script, that leverages the tools, PowerShell functions, and modules to succeed.
Plain vanilla structure
The template is structured in multiple sections, that is (1) requirements, (2) comment-based help, (3) parameters, (4) private helper functions, (5) initialization, and (6) main (implemented as a huge try-catch-finally).
In this region the script prepares for returning information as follows:
- Assuming that the script will fail an
IsSuccessful variable will be set to
Result hashtable with a nested hashtable for each possible result, that is success, unknown failure, and all well-known failure results.
ScriptResult variable will be initialized as an empty hashtable. At the end it will hold the relevant information for the caller.
ScritResultOnError variable will be set initially to
$Result.Unknown. In course of script processing that variable will be updated continuously with corresponding failure information.
Furthermore, in order to catch exceptions, the
ErrorActionPreferece variable will be set to
Stop which enables termination instead continuation in case of exceptions.
Basically, the main region is a huge try-catch-finally statement meaning that once a command within the try-ScriptBlock throws an exception, PowerShell will run the catch-ScriptBlock. In any case the finally-ScriptBlock will be run. This is plain vanilla as well.
The try-ScriptBlock, however, is divided into regions. Each logical step in completing the script task is represented by a region. Each region begins with an update for the
ScriptResultOnError variable so that it holds corresponding script results just in case of downstream failure or rather exception. The actual commands for the region in question follow afterwards and yet other commands might be necessary to validate outcome. If the outcome doesn’t meet the requirements for the script to succeed, the region exits processing of the try-ScriptBlock with
Break statement will directly lead to the finally-ScriptBlock. (I distinguish between ‘hard’ errors that is exceptions and ‘soft’ errors that is unfulfilled interim results. Hard errors lead to the catch-ScriptBlock. Soft errors don’t.) The final region inside the try-ScriptBlock is in charge to set the above mentioned
IsSuccessful variable to
$true, if applicable.
The catch-ScriptBlock will be used to log the exception message and the like.
The finally-ScriptBlock, finally, returns the script result to the script caller. In order to pass back correct information, it first sets the
ScriptResult variable depending on
IsSuccessful‘s value. If it is
$true it will hold
$Result.Success, if it is
$false it will set to
$ScriptResultOnError which holds the ‘latest’ failure results (see above). Ultimately,
$ScriptResult contains a hashtable with one or more elements to return. The script template contains sample code to terminate script execution with an exit code.
Hope this helps to make to world a better place.
PowerShell Controller Script Template