Private/Resolve-AACScope.ps1

function Resolve-AACScope {
    <#
    .SYNOPSIS
        Finds the subscriptions a command covers: every one the account can
        see, those in -SubscriptionId, or those under -ManagementGroupId (at
        any depth) - from one Azure Resource Graph query.
    .DESCRIPTION
        A subscription asked for that the account can't see is left out with
        a warning; when none is left, it stops with what to do.
 
        Returns @{
          Subscriptions the Resource Graph rows (subscriptionId, name,
                         state, chain - its management groups)
          Ids their IDs
          GraphScope the IDs to pass Invoke-AACGraphBatch -SubscriptionId:
                         none when unscoped (every query then covers
                         everything the account can see)
          Names ID (lower case) -> name
          Label 'all subscriptions', '2 subscription(s)', 'management
                         group mg-corp'
        }
    #>

    [CmdletBinding()]
    [OutputType([hashtable])]
    param(
        [string[]] $SubscriptionId = @(),

        [string[]] $ManagementGroupId = @()
    )

    $wantedSubscriptions = @($SubscriptionId | Where-Object { $_ } | ForEach-Object { $_.ToLowerInvariant() })
    $wantedGroups = @($ManagementGroupId | Where-Object { $_ } | ForEach-Object { $_.ToLowerInvariant() })
    $read = Invoke-AACGraphBatch -Query ([ordered]@{ subscriptions = "resourcecontainers | where type =~ 'microsoft.resources/subscriptions' | project id, subscriptionId, name, state = tostring(properties.state), chain = properties.managementGroupAncestorsChain" })
    $all = @($read.Rows['subscriptions'] | Where-Object { $null -ne $_ })
    $subscriptions = $all
    if ($wantedGroups.Count) {
        $subscriptions = @($subscriptions | Where-Object {
                $names = @(@($_['chain']) | Where-Object { $_ -is [System.Collections.IDictionary] } | ForEach-Object { ([string]$_['name']).ToLowerInvariant() })
                @($wantedGroups | Where-Object { $names -contains $_ }).Count
            })
        if (-not $subscriptions.Count) {
            $problem = [System.InvalidOperationException]::new("No subscription the account can see is under management group $($ManagementGroupId -join ', ').")
            $problem.Data['AACHint'] = 'Use the management group''s ID (its name), not its display name - and check the account has Reader on it.'
            throw $problem
        }
    }
    if ($wantedSubscriptions.Count) {
        foreach ($id in $wantedSubscriptions) { if (-not @($subscriptions | Where-Object { ([string]$_['subscriptionId']).ToLowerInvariant() -eq $id }).Count) { Write-Warning "Subscription $id isn't one the account can see$(if ($wantedGroups.Count) { ' under that management group' }); it's left out." } }
        $subscriptions = @($subscriptions | Where-Object { $wantedSubscriptions -contains ([string]$_['subscriptionId']).ToLowerInvariant() })
        if (-not $subscriptions.Count) { throw "None of the subscriptions $($SubscriptionId -join ', ') is one the account can see." }
    }
    if (-not $subscriptions.Count) {
        $problem = [System.InvalidOperationException]::new('The account can see no subscription.')
        $problem.Data['AACHint'] = 'Give the account Reader on the subscriptions (or a management group above them), or sign in to the right tenant with Connect-AAC -TenantId.'
        throw $problem
    }
    $names = @{}
    foreach ($row in $all) { $names[([string]$row['subscriptionId']).ToLowerInvariant()] = [string]$row['name'] }
    $ids = @($subscriptions | ForEach-Object { [string]$_['subscriptionId'] })
    $scoped = $wantedSubscriptions.Count -or $wantedGroups.Count
    @{
        Subscriptions = $subscriptions
        Ids           = $ids
        GraphScope    = $(if ($scoped) { $ids } else { @() })
        Names         = $names
        Label         = $(if ($wantedGroups.Count) { "management group $($ManagementGroupId -join ', ')" } elseif ($wantedSubscriptions.Count) { "$($ids.Count) subscription(s)" } else { "all $($ids.Count) subscription(s)" })
    }
}