Public/Get-MgkTenantConfig.ps1

function Get-MgkTenantConfig {
    <#
    .SYNOPSIS
        Loads and validates a tenant fleet configuration file.
    .DESCRIPTION
        Reads a JSON array of tenant entries and validates each one before
        anything tries to authenticate with it: required fields present,
        tenantId/clientId are well-formed GUIDs, certificateThumbprint is
        40 hex characters. Validation failures name the tenant and the field,
        because "Cannot bind argument" three calls deep helps nobody.
    .PARAMETER Path
        Path to the tenants JSON file.
    .OUTPUTS
        One PSCustomObject per tenant with TenantName, TenantId, ClientId,
        CertificateThumbprint (PSTypeName: MspGraphKit.TenantConfig).
    .EXAMPLE
        $tenants = Get-MgkTenantConfig -Path ./tenants.json
    .EXAMPLE
        Get-MgkTenantConfig -Path ./tenants.json | Test-MgkTenantConnection
    #>

    [CmdletBinding()]
    [OutputType('MspGraphKit.TenantConfig')]
    param(
        [Parameter(Mandatory)]
        [ValidateScript({ Test-Path $_ -PathType Leaf })]
        [string]$Path
    )

    $entries = Get-Content $Path -Raw | ConvertFrom-Json
    if ($entries -isnot [array]) { $entries = @($entries) }

    foreach ($entry in $entries) {
        $name = $entry.PSObject.Properties['tenantName'].Value ?? '<unnamed>'

        foreach ($field in 'tenantName', 'tenantId', 'clientId', 'certificateThumbprint') {
            if (-not $entry.PSObject.Properties[$field] -or [string]::IsNullOrWhiteSpace($entry.$field)) {
                throw "Tenant '$name': missing required field '$field' in $Path"
            }
        }
        foreach ($field in 'tenantId', 'clientId') {
            if (-not [guid]::TryParse($entry.$field, [ref][guid]::Empty)) {
                throw "Tenant '$name': '$field' is not a valid GUID ('$($entry.$field)')"
            }
        }
        if ($entry.certificateThumbprint -notmatch '^[0-9A-Fa-f]{40}$') {
            throw "Tenant '$name': certificateThumbprint must be 40 hex characters"
        }

        [pscustomobject]@{
            PSTypeName            = 'MspGraphKit.TenantConfig'
            TenantName            = $entry.tenantName
            TenantId              = $entry.tenantId
            ClientId              = $entry.clientId
            CertificateThumbprint = $entry.certificateThumbprint.ToUpper()
        }
    }
}