Private/ConvertTo-PsObject.ps1

<#
.SYNOPSIS
Recursively convert dictionaries to PSCustomObjects, merging keys that differ only in casing.

.DESCRIPTION
Walks the input recursively: dictionaries become PSCustomObjects, arrays are converted element-wise, scalars pass through unchanged. Keys differing only in casing (as produced by a case-sensitive JSON parser on JSON with duplicate-cased keys) collapse into a single property; the last value wins.

.PARAMETER InputObject
The value to convert. Accepts pipeline input.

.EXAMPLE
PS> $Json | ConvertFrom-Json -AsHashtable | ConvertTo-PsObject
Parses JSON that ConvertFrom-Json rejects for duplicate-cased keys, then restores the usual PSCustomObject shape.
#>

function ConvertTo-PsObject {
    [CmdletBinding()]
    param (
        [Parameter(ValueFromPipeline)]
        [object]$InputObject
    )
    process {
        if ($InputObject -is [System.Collections.IDictionary]) {
            # [ordered] is case-insensitive, so duplicate-cased keys collapse; the last value wins.
            $Merged = [ordered]@{}
            foreach ($Key in $InputObject.Keys) {
                $Merged[[string]$Key] = ConvertTo-PsObject -InputObject $InputObject[$Key]
            }
            [pscustomobject]$Merged
        }
        elseif ($InputObject -is [System.Collections.IList]) {
            , @($InputObject | ForEach-Object { ConvertTo-PsObject -InputObject $_ })
        }
        else {
            $InputObject
        }
    }
}