Private/ConvertTo-EscRegistryDump.ps1

function Read-EscRegKey {
    <#
    .SYNOPSIS
        Recursively reads a RegistryKey into an ordered hashtable (read-only helper).
    .DESCRIPTION
        Internal helper for ConvertTo-EscRegistryDump. Captures each value's name,
        kind, and data (binary rendered as hex; env strings left un-expanded) plus
        every sub-key, bounded by MaxDepth. Never writes.
    #>

    [CmdletBinding()]
    param(
        [Parameter(Mandatory = $true)]
        [object] $Key,

        [Parameter(Mandatory = $false)]
        [int] $Depth = 0,

        [Parameter(Mandatory = $false)]
        [int] $MaxDepth = 20
    )

    $node = [ordered]@{ '(values)' = [ordered]@{} }

    foreach ($vn in $Key.GetValueNames()) {
        $kind = $Key.GetValueKind($vn)
        $val = $Key.GetValue($vn, $null, [Microsoft.Win32.RegistryValueOptions]::DoNotExpandEnvironmentNames)
        if ($val -is [byte[]]) { $val = ([System.BitConverter]::ToString([byte[]]$val)) -replace '-', '' }
        $name = $vn
        if ([string]::IsNullOrEmpty($name)) { $name = '(default)' }
        $node['(values)'][$name] = [ordered]@{ Type = [string]$kind; Data = $val }
    }

    if ($Depth -lt $MaxDepth) {
        foreach ($sn in $Key.GetSubKeyNames()) {
            $sub = $null
            try { $sub = $Key.OpenSubKey($sn) } catch { $sub = $null }
            if ($null -ne $sub) {
                $node[$sn] = Read-EscRegKey -Key $sub -Depth ($Depth + 1) -MaxDepth $MaxDepth
                try { $sub.Close() } catch { }
            }
        }
    }

    return $node
}

function ConvertTo-EscRegistryDump {
    <#
    .SYNOPSIS
        Reads a remote HKLM sub-tree into a nested object (read-only, live).
    .DESCRIPTION
        Opens the remote machine's HKEY_LOCAL_MACHINE hive over the read-only
        remote-registry API and returns the requested sub-key as a nested ordered
        hashtable (values + sub-keys). Used to export a CA's CertSvc\Configuration
        sub-tree when the tool runs off-box. Requires the Remote Registry service
        and appropriate read rights; never modifies the registry.
    .PARAMETER ComputerName
        Target host holding the CA.
    .PARAMETER SubKey
        HKLM sub-key path (e.g. SYSTEM\CurrentControlSet\Services\CertSvc\Configuration).
    .PARAMETER MaxDepth
        Recursion bound (default 20).
    .OUTPUTS
        [System.Collections.Specialized.OrderedDictionary]
    #>

    [CmdletBinding()]
    param(
        [Parameter(Mandatory = $true)]
        [string] $ComputerName,

        [Parameter(Mandatory = $true)]
        [string] $SubKey,

        [Parameter(Mandatory = $false)]
        [int] $MaxDepth = 20
    )

    $base = $null
    try {
        $base = [Microsoft.Win32.RegistryKey]::OpenRemoteBaseKey([Microsoft.Win32.RegistryHive]::LocalMachine, $ComputerName)
        $root = $base.OpenSubKey($SubKey)
        if ($null -eq $root) { throw ("Sub-key not found: {0}" -f $SubKey) }
        $result = Read-EscRegKey -Key $root -Depth 0 -MaxDepth $MaxDepth
        try { $root.Close() } catch { }
        return $result
    }
    finally {
        if ($null -ne $base) { try { $base.Close() } catch { } }
    }
}