Public/Convert-UUIDSquished.ps1

function Convert-UUIDSquished {
    <#
    .SYNOPSIS
    Converts a GUID to the format stored by Windows Installer, e.g. in the Products registry key.
 
    .DESCRIPTION
    The cmdlet is idempotent -- this means you can give it a regular MSI GUID, or a GUID in the "Squished" format, and it will convert in either direction automatically.
 
    .PARAMETER GUID
    A GUID in a supported format. Curly braces and hyphens optional.
 
    .PARAMETER Format
    The GUID output format. Default is "b".
    Supported options are:
    b - Default format with hyphens and curly braces (the typical format)
    d - Default format with hyphens
    n - Default format without hyphens (use this for Product registry keys)
    p - Default format with parentheses and hyphens
    x - Hexadecimal format
 
    .EXAMPLE
    PS C:\> Convert-UUIDSquished "01020304-0506-0708-090a-0b0c0d0e0f10"
 
    Output:
    {04030201-0605-0807-090a-0b0c0d0e0f10}
    .EXAMPLE
    PS C:\> Convert-UUIDSquished "01020304-0506-0708-090a-0b0c0d0e0f10" -Format n
 
    Output:
    0403020106050807090a0b0c0d0e0f10
    .OUTPUTS
    [Guid] if Format is not specified.
    [String] if Format specified.
    .NOTES
    A "squished GUID" (SQUID) is a compressed format of a standard Windows Installer GUID, used to save space in the registry.
    It removes hyphens and curly braces from the GUID and rearranges the hexadecimal digits, and is used internally by the installer to identify products and their updates.
    You can find them used in: HKLM\Software\Microsoft\Windows\CurrentVersion\Installer\UserData\S-1-5-18\Products
    .COMPONENT
    Windows Installer
    .LINK
    About SQUIDs
    https://lordjeb.com/2013/10/01/windows-installer-squids/
    .LINK
    Converting a Regular GUID to a Compressed GUID
    https://community.revenera.com/s/article/converting-a-regular-guid-to-a-compressed-guid
    #>

    [OutputType([guid])]
    [OutputType([string],ParameterSetName='Formatted')]
    [Alias('Convert-SQUID', 'Convert-GUIDSquished', 'cvgs')]
    [CmdletBinding()]
    Param(
        [Parameter(
            Mandatory,
            Position = 0,
            ValueFromPipeline
        )]
        [guid]
        $GUID,

        [Parameter(
            Position = 1,
            ValueFromPipelineByPropertyName,
            ParameterSetName = 'Formatted'
        )]
        [ValidateSet(IgnoreCase,'d','n','p','b','x')]
        [string]
        $Format
    )

    Begin {
        $FunctionName = $MyInvocation.MyCommand.Name
        if(-not (Get-Variable 'LITTLE_ENDIAN' -Scope Global -ea SilentlyContinue)) {
            Set-Variable -Name 'LITTLE_ENDIAN' -Value [BitConverter]::IsLittleEndian -Scope Script
        }
        $ConvertedBytes = [byte[]]::new(16)
    }

    Process {
        try {
            $Bytes = $GUID.ToByteArray()
            if ($LITTLE_ENDIAN) {
                # Reverse the byte order for little-endian systems
                [Array]::Reverse($Bytes, 0, 4)
                [Array]::Reverse($Bytes, 4, 2)
                [Array]::Reverse($Bytes, 6, 2)
            }
            Write-Verbose "${FunctionName}: Processed $($Bytes.Count) bytes for $GUID"
        }
        catch {
            $Err = $_
            throw "Exception $($Err.Exception.HResult) converting GUID to Byte[] > $($Err.Exception.Message)"
        }

        # apparently this is a nibble swap
        <# for($i = 0; $i -lt 16; $i++) {
            $ByteHI = [byte]($Bytes[$i] -shl 4 -band 0xF0)
            $ByteLO = [byte]($Bytes[$i] -shr 4 -band 0x0F)
            $ConvertedBytes[$i] = $ByteHI -bor $ByteLO
        } #>

        try {
            $ConvertedBytes = Switch-ByteNibble -Bytes $Bytes
            Write-Verbose "${FunctionName}: Swapped $($ConvertedBytes.Count) $($ConvertedBytes.GetType().Name)"
        }
        catch {
            $Err = $_
            throw "Exception $($Err.Exception.HResult) performing nibble swap on GUID bytes > $($Err.Exception.Message)"
        }

        try {
            $ConvertedGUID = [guid]::new($ConvertedBytes -as [byte[]])
        }
        catch {
            $Err = $_
            throw "Exception $($Err.Exception.HResult) parsing converted GUID bytes > $($Err.Exception.Message)"
        }

        if ($Format) {
            Return $ConvertedGUID.ToString($Format).ToUpperInvariant()
        }
        else {
            $ConvertedGUID
        }
    }
}