Public/Invoke-MgkTenantSweep.ps1

function Invoke-MgkTenantSweep {
    <#
    .SYNOPSIS
        Runs a scriptblock against every tenant in a fleet, fault-isolated.
    .DESCRIPTION
        For each tenant: connect to Graph (certificate app-only), invoke the
        scriptblock (which receives the tenant config object), disconnect.
        Guarantees:
          - one tenant's failure never stops the sweep (it becomes a result
            row with Success=$false and the error message)
          - throttling (429) and transient 5xx are retried with backoff
          - Disconnect-MgGraph always runs, even on failure
    .PARAMETER Tenant
        Tenant config objects (from Get-MgkTenantConfig), by pipeline or parameter.
    .PARAMETER ScriptBlock
        Work to run per tenant. Receives the tenant object as its argument.
        Whatever it returns lands in the result's Data property.
    .OUTPUTS
        One MspGraphKit.SweepResult per tenant: TenantName, Success, Data,
        Error, DurationMs.
    .EXAMPLE
        $r = Get-MgkTenantConfig -Path tenants.json | Invoke-MgkTenantSweep -ScriptBlock {
            param($t)
            (Invoke-MgGraphRequest -Uri 'https://graph.microsoft.com/v1.0/organization').value.displayName
        }
    .EXAMPLE
        Invoke-MgkTenantSweep -Tenant $tenants -ScriptBlock $work -Verbose
    #>

    [CmdletBinding()]
    [OutputType('MspGraphKit.SweepResult')]
    param(
        [Parameter(Mandatory, ValueFromPipeline)]
        [PSTypeName('MspGraphKit.TenantConfig')]
        [object[]]$Tenant,

        [Parameter(Mandatory)]
        [scriptblock]$ScriptBlock
    )

    process {
        foreach ($t in $Tenant) {
            Write-Verbose "Sweeping $($t.TenantName)"
            $sw = [System.Diagnostics.Stopwatch]::StartNew()
            $result = [ordered]@{
                PSTypeName = 'MspGraphKit.SweepResult'
                TenantName = $t.TenantName
                Success    = $false
                Data       = $null
                Error      = $null
                DurationMs = 0
            }

            try {
                Connect-MgGraph -TenantId $t.TenantId -ClientId $t.ClientId `
                    -CertificateThumbprint $t.CertificateThumbprint -NoWelcome -ErrorAction Stop

                $result.Data = Invoke-MgkWithRetry -ScriptBlock $ScriptBlock -ArgumentList @($t)
                $result.Success = $true
            }
            catch {
                $result.Error = "$_"
                Write-Warning "$($t.TenantName): $_"
            }
            finally {
                $result.DurationMs = $sw.ElapsedMilliseconds
                Disconnect-MgGraph -ErrorAction SilentlyContinue | Out-Null
            }

            [pscustomobject]$result
        }
    }
}