Scripts/Convert-FIDOKeyToStandardFormat.ps1

function Convert-FIDOKeyToStandardFormat {
    <#
    .SYNOPSIS
        Converts FIDO key data to a standardized format.

    .DESCRIPTION
        This function takes a FIDO key object and converts it to a standardized format,
        ensuring all properties are in the expected order and properly formatted.

    .PARAMETER FIDOKey
        The FIDO key object to be converted.

    .EXAMPLE
        $standardizedKey = Convert-FIDOKeyToStandardFormat -FIDOKey $originalKey
        
    .NOTES
        This function preserves all the data from the original object but ensures
        it follows a consistent structure for better readability and processing.
    #>

    
    [CmdletBinding()]
    param (
        [Parameter(Mandatory = $true, ValueFromPipeline = $true)]
        [PSCustomObject]$FIDOKey
    )
    
    process {
        # Create an ordered hashtable to ensure properties are in the desired order
        $standardizedKey = [ordered]@{
            Vendor = if ($null -ne $FIDOKey.Vendor) { $FIDOKey.Vendor } elseif ($null -ne $FIDOKey.vendor) { $FIDOKey.vendor } else { "" }
            Description = if ($null -ne $FIDOKey.Description) { $FIDOKey.Description } elseif ($null -ne $FIDOKey.description) { $FIDOKey.description } else { "" }
            AAGUID = if ($null -ne $FIDOKey.AAGUID) { $FIDOKey.AAGUID } elseif ($null -ne $FIDOKey.aaguid) { $FIDOKey.aaguid } else { "" }
            Bio = if ($null -ne $FIDOKey.Bio) { $FIDOKey.Bio } elseif ($null -ne $FIDOKey.bio) { $FIDOKey.bio } else { $false }
            USB = if ($null -ne $FIDOKey.USB) { $FIDOKey.USB } elseif ($null -ne $FIDOKey.usb) { $FIDOKey.usb } else { $false }
            NFC = if ($null -ne $FIDOKey.NFC) { $FIDOKey.NFC } elseif ($null -ne $FIDOKey.nfc) { $FIDOKey.nfc } else { $false }
            BLE = if ($null -ne $FIDOKey.BLE) { $FIDOKey.BLE } elseif ($null -ne $FIDOKey.ble) { $FIDOKey.ble } else { $false }
            Version = if ($null -ne $FIDOKey.Version) { $FIDOKey.Version } elseif ($null -ne $FIDOKey.version) { $FIDOKey.version } else { "" }
            ValidVendor = if ($null -ne $FIDOKey.ValidVendor) { $FIDOKey.ValidVendor } elseif ($null -ne $FIDOKey.validVendor) { $FIDOKey.validVendor } else { $true }
        }
        
        # Add metadataStatement if it exists
        if ($FIDOKey.metadataStatement) {
            $metadataStatement = [ordered]@{
                legalHeader = $FIDOKey.metadataStatement.legalHeader
                aaguid = $FIDOKey.metadataStatement.aaguid
                description = $FIDOKey.metadataStatement.description
                authenticatorVersion = $FIDOKey.metadataStatement.authenticatorVersion
                protocolFamily = $FIDOKey.metadataStatement.protocolFamily
                schema = $FIDOKey.metadataStatement.schema
            }
            
            # Add optional properties if they exist
            foreach ($property in @('upv', 'authenticationAlgorithms', 'publicKeyAlgAndEncodings', 
                                   'attestationTypes', 'userVerificationDetails', 'keyProtection', 
                                   'matcherProtection', 'cryptoStrength', 'attachmentHint', 
                                   'tcDisplay', 'attestationRootCertificates', 
                                   'icon', 'supportedExtensions', 'authenticatorGetInfo')) {
                if ($FIDOKey.metadataStatement.$property) {
                    $metadataStatement[$property] = $FIDOKey.metadataStatement.$property
                }
            }
            
            $standardizedKey['metadataStatement'] = [PSCustomObject]$metadataStatement
        }
        
        # Add statusReports if they exist
        if ($FIDOKey.statusReports) {
            $standardizedKey['statusReports'] = $FIDOKey.statusReports
        }
        
        # Add timeOfLastStatusChange if it exists
        if ($FIDOKey.timeOfLastStatusChange) {
            $standardizedKey['timeOfLastStatusChange'] = $FIDOKey.timeOfLastStatusChange
        }
        
        # Convert to PSCustomObject and return
        return [PSCustomObject]$standardizedKey
    }
}

function Test-FIDOKeyStandardFormat {
    <#
    .SYNOPSIS
        Tests if a FIDO key is already in the standard format.

    .DESCRIPTION
        This function determines whether a FIDO key object is already in the standardized format.

    .PARAMETER FIDOKey
        The FIDO key object to be tested.

    .EXAMPLE
        $isStandardFormat = Test-FIDOKeyStandardFormat -FIDOKey $keyObject
    #>

    
    [CmdletBinding()]
    [OutputType([bool])]
    param (
        [Parameter(Mandatory = $true)]
        [PSCustomObject]$FIDOKey
    )
    
    # Check for required properties in the expected order
    $requiredProperties = @('Vendor', 'Description', 'AAGUID', 'Bio', 'USB', 'NFC', 'BLE', 'Version', 'ValidVendor')
    
    foreach ($prop in $requiredProperties) {
        if (-not $FIDOKey.PSObject.Properties.Name.Contains($prop)) {
            return $false
        }
    }
    
    # If all required properties exist, consider it standardized
    return $true
}

function Import-FIDOKeysFromJson {
    <#
    .SYNOPSIS
        Imports FIDO keys from a JSON file, standardizing the format as needed.

    .DESCRIPTION
        This function reads a JSON file containing FIDO key information, standardizes the format
        of keys that need it, and returns the full collection of keys.

    .PARAMETER FilePath
        The path to the JSON file containing FIDO keys.

    .EXAMPLE
        $fidoKeys = Import-FIDOKeysFromJson -FilePath "path/to/FidoKeys.json"
        
    .NOTES
        This function preserves the metadata section of the original JSON file.
    #>

    
    [CmdletBinding()]
    param (
        [Parameter(Mandatory = $true)]
        [string]$FilePath
    )
    
    try {
        # Read and convert the JSON file
        $fidoKeysData = Get-Content -Raw -Path $FilePath -ErrorAction Stop | ConvertFrom-Json
        
        # Determine the structure of the JSON data
        $keysCollection = $null
        
        # Check if it's an array directly
        if ($fidoKeysData -is [Array]) {
            Write-Verbose "JSON contains a direct array of keys"
            $keysCollection = $fidoKeysData
            $metadata = $null
        }
        # Check if it has a 'keys' property that is an array
        elseif ($fidoKeysData.PSObject.Properties.Name.Contains('keys') -and $fidoKeysData.keys -is [Array]) {
            Write-Verbose "JSON contains keys array property"
            $keysCollection = $fidoKeysData.keys
            $metadata = if ($fidoKeysData.PSObject.Properties.Name.Contains('metadata')) { $fidoKeysData.metadata } else { $null }
        }
        # Check if it's a single object with key-like properties
        elseif ($fidoKeysData.PSObject.Properties.Name -contains 'Vendor' -or 
                $fidoKeysData.PSObject.Properties.Name -contains 'vendor' -or
                $fidoKeysData.PSObject.Properties.Name -contains 'Description' -or
                $fidoKeysData.PSObject.Properties.Name -contains 'description') {
            Write-Verbose "JSON contains a single key object"
            $keysCollection = @($fidoKeysData) # Wrap in array for consistency
            $metadata = $null
        }
        else {
            # Try to find any array property that might contain keys
            $arrayProps = $fidoKeysData.PSObject.Properties | Where-Object { $_.Value -is [Array] } | Select-Object -First 1
            if ($arrayProps) {
                Write-Verbose "Using array property '$($arrayProps.Name)' as keys collection"
                $keysCollection = $fidoKeysData.$($arrayProps.Name)
                $metadata = $null
            }
            else {
                throw "Could not determine the structure of the JSON data. Expected an array of keys or an object with a 'keys' property."
            }
        }
        
        Write-Verbose "Found $(($keysCollection | Measure-Object).Count) keys to process"
        
        # Process each key
        $standardizedKeys = $keysCollection | ForEach-Object {
            $currentKey = $_
            
            # Only standardize if needed
            if (-not (Test-FIDOKeyStandardFormat -FIDOKey $currentKey)) {
                Write-Verbose "Standardizing key: $($currentKey.Description)"
                Convert-FIDOKeyToStandardFormat -FIDOKey $currentKey
            }
            else {
                Write-Verbose "Key already in standard format: $($currentKey.Description)"
                $currentKey
            }
        }
        
        # Create the result object
        if ($metadata) {
            $result = @{
                keys = $standardizedKeys
                metadata = $metadata
            }
        }
        else {
            $result = @{
                keys = $standardizedKeys
            }
        }
        
        return $result
    }
    catch {
        Write-Error "Error importing FIDO keys from JSON: $_"
        throw
    }
}

# Example usage:
# $fidoKeys = Import-FIDOKeysFromJson -FilePath "path/to/FidoKeys.json" -Verbose
# $fidoKeys | ConvertTo-Json -Depth 10 | Set-Content -Path "path/to/standardized-FidoKeys.json"