Private/Get-NSPConditionalAccessAdCoverageData.ps1

function Get-NSPConditionalAccessAdCoverageData {
    <#
    .SYNOPSIS
        Reads Active Directory for the coverage check: enabled users, and the recursive user
        members of each coverage group and of the exempt group.
    .DESCRIPTION
        The only function that reads AD for coverage, so tests can replace it. Groups are given by
        identity (SID preferred, else sAMAccountName). A group that cannot be read is reported in
        Errors, never treated as empty: an unreadable group would otherwise make all of its members
        look uncovered.
    #>

    [CmdletBinding()]
    param(
        [Parameter(Mandatory)][hashtable]$CoverageGroups,
        [string]$ExemptGroup
    )

    if (-not (Get-Module -ListAvailable -Name ActiveDirectory)) {
        throw 'The ActiveDirectory module is not available on this host (install RSAT, or run on a domain controller).'
    }
    Import-Module ActiveDirectory -ErrorAction Stop -Verbose:$false

    $errors = [System.Collections.Generic.List[string]]::new()
    $members = @{}
    foreach ($slot in $CoverageGroups.Keys) {
        $identity = $CoverageGroups[$slot]
        try {
            $group = Get-ADGroup -Identity $identity -ErrorAction Stop
            $members[$slot] = [pscustomobject]@{
                Identity = $identity
                Name = $group.SamAccountName
                Members = @(Get-ADGroupMember -Identity $group -Recursive -ErrorAction Stop | Where-Object objectClass -eq 'user' | ForEach-Object { [string]$_.ObjectGUID })
            }
        } catch {
            $errors.Add("Group for slot $slot ($identity) could not be read: $_")
        }
    }
    $exempt = @()
    if ($ExemptGroup) {
        try {
            $exempt = @(Get-ADGroupMember -Identity $ExemptGroup -Recursive -ErrorAction Stop | Where-Object objectClass -eq 'user' | ForEach-Object { [string]$_.ObjectGUID })
        } catch {
            $errors.Add("Exempt group $ExemptGroup could not be read: $_")
        }
    }
    $users = @(Get-ADUser -Filter 'Enabled -eq $true' -Properties UserPrincipalName, DisplayName -ErrorAction Stop | ForEach-Object {
            [pscustomobject]@{
                ObjectGuid = [string]$_.ObjectGUID
                SamAccountName = $_.SamAccountName
                UserPrincipalName = $_.UserPrincipalName
                DisplayName = $_.DisplayName
            }
        })

    [pscustomobject]@{ Users = $users; Groups = $members; Exempt = $exempt; Errors = @($errors) }
}