Public/Import-NSPEntraPairingQueue.ps1

function Import-NSPEntraPairingQueue {
    <#
    .SYNOPSIS
        Loads a saved queue for the expected tenant and forest. Offline.
    .DESCRIPTION
        A queue from another tenant or forest is refused, so a review can't be replayed in the wrong
        environment. Loading proves nothing about the directory: run Sync-NSPEntraPairingQueue
        against a fresh inventory before relying on any decision. Until then needsRevalidation is
        set, and no selection or review can start.
    .EXAMPLE
        $queue = Import-NSPEntraPairingQueue -Path $path -ExpectedTenantId $tenantId -ExpectedForest 'contoso.example'
    #>

    [CmdletBinding()]
    [OutputType('NSP.M365.UserPairing.Queue')]
    param(
        [Parameter(Mandatory)][string]$Path,
        [Parameter(Mandatory)][guid]$ExpectedTenantId,
        [Parameter(Mandatory)][ValidateNotNullOrEmpty()][string]$ExpectedForest
    )

    $queue = [IO.File]::ReadAllText($Path) | ConvertFrom-Json
    if ($queue.schemaVersion -ne 1) { throw "Unsupported queue schema version '$($queue.schemaVersion)'." }
    foreach ($field in 'tenantId', 'forest', 'sourceAnchor', 'pairs') {
        if ($null -eq $queue.PSObject.Properties[$field]) { throw "The queue has no $field." }
    }
    if ([string]$queue.tenantId -ne [string]$ExpectedTenantId) {
        throw "This queue belongs to tenant $($queue.tenantId), not $ExpectedTenantId. It was not loaded."
    }
    if ([string]$queue.forest -ne $ExpectedForest) {
        throw "This queue belongs to forest $($queue.forest), not $ExpectedForest. It was not loaded."
    }

    $allowed = @('undecided', 'selected', 'skipped', 'flagged', 'deferred', 'needs-review')
    $states = @('pending', 'writing', 'applied', 'unconfirmed', 'different', 'unknown', 'failed', 'linked')
    $seen = @{}
    foreach ($pair in @($queue.pairs)) {
        if ([string]$pair.decision -notin $allowed) { throw "Pair $($pair.cloudObjectId) has an unknown decision '$($pair.decision)'." }
        if ([string]$pair.executionState -notin $states) { throw "Pair $($pair.cloudObjectId) has an unknown execution state '$($pair.executionState)'." }
        if ($seen.ContainsKey([string]$pair.cloudObjectId)) { throw "Cloud object $($pair.cloudObjectId) appears twice in the queue." }
        $seen[[string]$pair.cloudObjectId] = $true
        # JSON gives back a null or scalar where a list held nothing or one item.
        foreach ($list in 'candidates', 'matchEvidence', 'history') { $pair.$list = @($pair.$list | Where-Object { $null -ne $_ }) }
    }
    $queue.pairs = @($queue.pairs)
    $queue.domains = @($queue.domains)
    $queue.linkedAdObjectGuids = @($queue.linkedAdObjectGuids | Where-Object { $_ })
    $queue.revalidatedAtUtc = $null
    $queue | Add-Member -NotePropertyName needsRevalidation -NotePropertyValue $true -Force
    $queue.PSObject.TypeNames.Insert(0, 'NSP.M365.UserPairing.Queue')
    $queue
}