Public/Common/ConvertFrom-JsonCustom.ps1

function ConvertFrom-JsonCustom {

    <#
        .SYNOPSIS
            Converts the given JSON string to object or hashtable.
            This is a wrapper around ConvertFrom-Json that adds the -AsHashTable parameter because:
            - PowerShell 5 does not support the -AsHashTable parameter

        .PARAMETER Value
            Object to JSON object or hashtable.

        .PARAMETER AsHashTable
            If set, the JSON string will be deserialized as a hashtable.
    #>


    [CmdletBinding()]
    param(
        [Parameter(ValueFromPipeline)]
        [AllowEmptyCollection()]
        [AllowNull()]
        [AllowEmptyString()]
        $Value,

        [switch] $AsHashTable
    )

    begin {

        # Only use System.Web.Extensions on Windows PowerShell 5.x
        # On non-Windows platforms, this assembly is not available
        if ((Get-PSVersion) -lt 6 -and (Get-OSVersion).Platform -like 'Win*') {

            # Assembly name for System.Web.Extensions
            $assemblyName = 'System.Web.Extensions, Version=4.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35'

            # Type name for JavaScriptSerializer
            $typeName = 'System.Web.Script.Serialization.JavaScriptSerializer'

            try {
                # Use this class to perform the deserialization:
                # https://msdn.microsoft.com/en-us/library/system.web.script.serialization.javascriptserializer(v=vs.110).aspx
                Add-Type `
                    -AssemblyName $assemblyName `
                    -ErrorAction Stop
                
                # Create a new instance of the JavaScriptSerializer class
                $jsSerializer = New-Object -TypeName $typeName

                # ...Why the simple way does not work?
                # $jsSerializer = [System.Web.Script.Serialization.JavaScriptSerializer]::new()

                # Alternative way:
                # $type = [Type]::GetType("$typeName, $assemblyName")
                # $jsSerializer = [Activator]::CreateInstance($type)
            } catch {
                # If we can't load the assembly, fall back to basic ConvertFrom-Json
                Write-Warning "Unable to locate the System.Web.Extensions namespace from System.Web.Extensions.dll. Falling back to basic ConvertFrom-Json."
                $jsSerializer = $null
            }
        } else {
            $jsSerializer = $null
        }
    }

    process {

        $Value | ForEach-Object {

            # Cast to string first
            $current = [string] $_

            # Skip if null or empty
            if (!$current) {
                return
            }

            # Remove UTF-8 BOM, if present
            if ($current.Length -gt 0) {
                # UTF-8 BOM = 0xEF 0xBB 0xBF = 65279
                if ($current[0] -eq ([char] 65279)) {
                    $current = $current.Substring(1)
                }
            }

            # Return if null or empty
            if ([string]::IsNullOrEmpty($current)) {
                return
            }

            # Powershell 6 supports -AsHashTable
            if ((Get-PSVersion) -ge 6) {
                $result = $current | ConvertFrom-Json -AsHashtable:$AsHashTable
                return $result
            }

            # PowerShell 5 does not support -AsHashTable
            # when $AsHashTable not specified or $false, use default
            if (-not ($AsHashTable.IsPresent -and ($true -eq $AsHashTable))) {
                $result = $current | ConvertFrom-Json
                return $result
            }

            # If JavaScriptSerializer is available, use it for hashtable conversion
            if ($null -ne $jsSerializer) {
                $result = $jsSerializer.Deserialize($current, 'Hashtable')
                return $result
            }

            # Fallback: use regular ConvertFrom-Json (won't be a hashtable but will work)
            Write-Warning "AsHashTable requested but System.Web.Extensions not available. Returning PSCustomObject instead of Hashtable."
            $result = $current | ConvertFrom-Json
            return $result
        }
    }

    end {
        $jsSerializer = $null
    }
}