Archive | October, 2014

Pseudo Singleton Pattern in PowerShell

1 Oct

I have had a few modules that I have developed where I desired to use the Singleton pattern as I didn’t want multiple instances of a particular object running about across scripts. Building full fledge objects in PowerShell is a bit verbose and not the most straightforward process. I’m also not certain you can properly build an honest Singleton class natively in PowerShell. An alternative to building objects natively in PowerShell is to use C# in line and compile the class with Add-Type. Although that is an acceptable solution and benefits from full enforcement of restricting object creation to calling the Instance method, I wanted to stay native to PowerShell. I’ve adopted the following pattern to accomplish this:

function Get-ObjectInstance{
    param()

    if(Get-Variable -Scope Global -Name 'tmpObject' -EA SilentlyContinue){ 
        return (Get-Variable -Scope Global -Name 'tmpObject').Value 
    }

    $Global:tmpObject = New-Object PSObject
    

   return $tmpObject
}

Using a global variable is required if you want the object available across scripts which is helpful if you want to do things like logging. This concept was initially prompted by an issue I was having with a Logging module I had written. I was invoking a Global logging object in each script which was causing problems on multiple runs. I would call:

# Instatiate Log #
if($GLOBAL:Log -eq $null){
    $GLOBAL:Log = New-LogObject "Log Description"
}

On subsequent runs I would get errors of “Can’t add-member… “ something or other and the logging would error. It required me closing the object properly which was difficult to do cleanly and consistently when creating the Global object in each script as the name could change from script to script if you weren’t careful. Instead of making the variable global in each script, I moved that into a module using the “singleton” pattern as described above in the function Get-ObjectInstance . I initially moved to this method to make it easier to close out the global variable so I wouldn’t run into issues on subsequent runs. The side benefit of this change was that I no longer needed to maintain consistency from script to script for the variable name. Using the pseudo singleton pattern, I could now call:

# Instatiate Log #
$Log = Get-LogInstance "Log Description"

This remove the need for checking if the variable had been created in each script, and I could call scripts in any order knowing I would get a valid and the correct instance of the object I wanted.