Dynamic .Net Type Loading in Powershell

When crafting powershell scripts it's convenient to enter a hard-coded path to the .net DLL.  This is a huge annoyance when trying to execute the script on another workstation.  If that workstation was deployed such that the HPE Content Manager installation files are located in an alternate path the script will fail.

In many of my previous posts I would use this command to import the .Net DLL:

Add-Type -Path "D:\Program Files\Hewlett Packard Enterprise\Content Manager\HP.HPTRIM.SDK.dll"

It worked because I installed HPE Content Manager into the "D:\Program Files\Hewlett Packard Enterprise\Content Manager" directory on that workstation.  When I run this on a server with a different installation path, errors abound.  I could search for the DLL across the mounted volumes, but it seems cleanest to check the registry.

The one liner import of the SDK now becomes these 12 lines:

try { 
    $RootPath = [System.IO.Path]::GetDirectoryName((Get-ItemProperty "Registry::HKEY_LOCAL_MACHINE\Software\Hewlett-Packard\HP TRIM\MSISettings" -ErrorAction Stop).'INSTALLDIR')
    if ( [System.IO.Directory]::Exists($RootPath) -eq $true ) {
        $SDKPath = [System.IO.Path]::Combine($RootPath, "HP.HPTRIM.SDK.dll")
        if ( [System.IO.File]::Exists($SDKPath) ) {
            Add-Type -Path $SDKPath
            Write-Debug "Loaded SDK from $($SDKPath)"
        }
    }
} catch {
    Write-Error "$($_)"
}

I would say it's not easily readable and decide to wrap it within a function.  Then I call the function and wrap them both with a region.    A simple comment for the region then seems to suffice for readability.

#region Load CM SDK
<#
 # Fetch installation path from HKCLM\Software..., validates
 # there is a DLL on disk and then loads the SDK from path
#>
function LoadSDK {
    try { 
        $RootPath = [System.IO.Path]::GetDirectoryName((Get-ItemProperty "Registry::HKEY_LOCAL_MACHINE\Software\Hewlett-Packard\HP TRIM\MSISettings" -ErrorAction Stop).'INSTALLDIR')
        if ( [System.IO.Directory]::Exists($RootPath) -eq $true ) {
            $SDKPath = [System.IO.Path]::Combine($RootPath, "HP.HPTRIM.SDK.dll")
            if ( [System.IO.File]::Exists($SDKPath) ) {
                Add-Type -Path $SDKPath
                Write-Debug "Loaded SDK from $($SDKPath)"
            }
        }
    } catch {
        Write-Error "$($_)"
    }
}
LoadSDK
#endregion

Executing this yields the following results in the debug log...

2018-01-24_19-04-34.png

If I add this as an ISE snippet I can start every new script with this (instead of having to copy and paste it).

2018-01-24_19-08-39.png

Including the region allows me to collapse it and then focus on the script itself.  Distributing small scripts, which aren't meant to be maintained, with reliable snippets works best for my needs.  This could also be reliably implemented in a powershell module.

2018-01-25_17-12-50.png

To create this snippet in your own environment you can run this command:

$code = @'
#region Load CM SDK
<#
 # Fetch installation path from HKCLM\Software..., validates
 # there is a DLL on disk and then loads the SDK from path
#>
function LoadSDK {
    try { 
        $RootPath = [System.IO.Path]::GetDirectoryName((Get-ItemProperty "Registry::HKEY_LOCAL_MACHINE\Software\Hewlett-Packard\HP TRIM\MSISettings" -ErrorAction Stop).'INSTALLDIR')
        if ( [System.IO.Directory]::Exists($RootPath) -eq $true ) {
            $SDKPath = [System.IO.Path]::Combine($RootPath, "HP.HPTRIM.SDK.dll")
            if ( [System.IO.File]::Exists($SDKPath) ) {
                Add-Type -Path $SDKPath
                Write-Debug "Loaded SDK from $($SDKPath)"
            }
        }
    } catch {
        Write-Error "$($_)"
    }
}
LoadSDK
#endregion
 
'@
 
New-IseSnippet -Title "CMRamble-LoadSDK" -Description "Dynamically load the Content Manager SDK" -Text $code