Public/Get-PdqLicense.ps1

<#
.SYNOPSIS
Retrieves and decodes your PDQ license(s).
 
.INPUTS
None.
 
.OUTPUTS
System.Object[]
System.Xml.XmlElement
System.String
 
.EXAMPLE
Get-PdqLicense
Retrieves and decodes the Deploy and Inventory licenses from the registry.
 
.EXAMPLE
Get-PdqLicense -Product 'Deploy' -Format 'Raw'
Retrieves your Deploy license from the registry without decoding it.
 
.EXAMPLE
Get-PdqLicense -License (Get-Clipboard)
Retrieves a PDQ license from your clipboard and decodes it.
#>


function Get-PdqLicense {

    [CmdletBinding(DefaultParameterSetName = 'Product')]
    param (
        [ValidateSet('Deploy', 'Inventory')]
        [Parameter(ParameterSetName = 'Product')]
        # The PDQ application whose license you would like to retrieve.
        [String[]]$Product = ('Deploy', 'Inventory'),

        [Parameter(ParameterSetName = 'Product')]
        # If a license can't be found in the registry, output the Free Mode license instead.
        [Switch]$AllowFreeMode,

        # The license(s) you would like to decode, if you don't want to retrieve them from the registry.
        [Parameter(ParameterSetName = 'License')]
        [String[]]$License,

        [ValidateSet('Object', 'Raw', 'RawMiddle', 'URL', 'Wrapped', 'XML')]
        <#
        How you would like the license(s) to be formatted.
 
        Object - XmlElement - Contains the fully decoded license.
        Raw - String - Contains the license without any processing.
        RawMiddle - String - The same as Raw, but with the Start and End blocks stripped off.
        URL - String - Contains the license formatted for use with PDQ web APIs.
        Wrapped - String - The same as Raw, but split into lines up to 40 characters long.
        XML - String - Contains the XML text that was decoded from base64.
        #>

        [String]$Format = 'Object' 
    )

    function Exit-AfterFormatting {

        [CmdletBinding()]
        param (
            $Format,
            $FormatToTest,
            $DesiredOutput
        )

        if ( $Format -eq $FormatToTest ) {

            $DesiredOutput
            continue

        }

    }

    $Licenses = @()

    if ( $License ) {

        # Flatten multi-line licenses, such as those from emails.
        if ( $License[0] -eq '--- START LICENSE ---' ) {

            $TempLicenses = @()

            foreach ( $Line in $License ) {
                
                if ( $Line -eq '--- START LICENSE ---' ) {

                    $TempLicense = $Line

                } else {

                    $TempLicense += $Line

                }

                if ( $Line -eq '--- END LICENSE ---' ) {

                    $TempLicenses += $TempLicense

                }

            }

            $License = $TempLicenses

        }

        foreach ( $SuspiciousLicense in $License ) {

            if ( -not $SuspiciousLicense.StartsWith('--- START LICENSE ---') ) {

                throw 'Licenses must start with: --- START LICENSE ---'

            }

            if ( -not $SuspiciousLicense.EndsWith('--- END LICENSE ---') ) {

                throw 'Licenses must end with: --- END LICENSE ---'

            }

            $Licenses += $SuspiciousLicense

        }

    } else {

        foreach ( $ProductName in $Product ) {

            try {

                $Licenses += Get-ItemPropertyValue -Path "HKLM:\SOFTWARE\Admin Arsenal\PDQ $ProductName" -Name 'License' -ErrorAction 'Stop'
                $Count ++

            } catch {

                if ( $AllowFreeMode ) {
                
                    Write-Verbose "Unable to find the $ProductName license in the registry, assuming Free Mode."
                    $Licenses += '--- START LICENSE ---PExpY2Vuc2U+DQogIDxOYW1lPjwvTmFtZT4NCiAgPENvZGU+PC9Db2RlPg0KICA8Q291bnQ+MDwvQ291bnQ+DQogIDxUeXBlPjA8L1R5cGU+DQogIDxJRD4wMDAwMDAwMC0wMDAwLTAwMDAtMDAwMC0wMDAwMDAwMDAwMDA8L0lEPg0KICA8RS1NYWlsPjwvRS1NYWlsPg0KICA8RXhwaXJlcz4tNzMzNzcyPC9FeHBpcmVzPg0KICA8U2lnbmF0dXJlPjwvU2lnbmF0dXJlPg0KPC9MaWNlbnNlPg==--- END LICENSE ---'
                    $Count ++

                } else {

                    Write-Warning "Unable to find the $ProductName license in the registry."

                }

            }

        }

        if ( -not $Count ) {

            throw 'Unable to find any licenses in the registry.'
    
        }

    } 

    foreach ( $LicenseRaw in $Licenses ) {

        Exit-AfterFormatting $Format 'Raw' $LicenseRaw



        # Get the main part of the license.
        $LicenseMiddle = ($LicenseRaw -split "---")[2]

        Exit-AfterFormatting $Format 'RawMiddle' $LicenseMiddle



        # Split the license into lines that are up to 40 characters long.
        $LicenseWrappedLines = @('--- START LICENSE ---')
        For ( $Count = 0; $Count -lt ($LicenseMiddle.Length / 40); $Count ++ ) {

            $Index = $Count * 40
            $RemainingCharacters = $LicenseMiddle.Length - $Index
    
            # The last line usually isn't 40 characters long.
            if ( $RemainingCharacters -lt 40 ) {

                $Length = $RemainingCharacters

            } else {

                $Length = 40

            }
    
            # Split the middle section (the actual license) into pieces up to 40 characters long.
            $LicenseWrappedLines += $LicenseMiddle.Substring($Index, $Length)

        }

        $LicenseWrappedLines += '--- END LICENSE ---'
        $LicenseWrapped = $LicenseWrappedLines -join "`r`n"

        Exit-AfterFormatting $Format 'Wrapped' $LicenseWrapped



        # Format the license how the PDQ web APIs expect it.
        $LicenseUrlEncoded = [System.Net.WebUtility]::UrlEncode($LicenseWrapped) -replace '\+', '%20'

        Exit-AfterFormatting $Format 'URL' $LicenseUrlEncoded



        # Decode base64.
        # https://stackoverflow.com/a/15415708
        $LicenseDecoded = [System.Text.Encoding]::UTF8.GetString([System.Convert]::FromBase64String($LicenseMiddle))

        Exit-AfterFormatting $Format 'XML' $LicenseDecoded



        # Convert the XML string into a PowerShell object, and output it.
        ([XML]$LicenseDecoded).License

    }

}