Private/Resolve-AccessPackageAssignmentIds.ps1

function Resolve-AccessPackageAssignmentIds {
    <#
    .SYNOPSIS
        Resolves each user in $UserList to their existing accessPackageAssignment
        id for the given access package, by fetching all current assignments once
        (paginated, expanding target) instead of one GET per user.
    .NOTES
        Needed only for adminRemove. Unlike adminAdd, which identifies the target
        via target.objectId/accessPackageId/assignmentPolicyId, Graph's adminRemove
        identifies the assignment to remove purely by the assignment's own id -
        there is no other way to reference it, so this lookup isn't an optional
        pre-check the way an add-side duplicate check would be.
    .OUTPUTS
        PSCustomObject with Resolved (array of {User; AssignmentId}) and
        NotFound (users with no existing assignment - nothing to remove).
        Writes an error and returns $null if the lookup itself fails.
    #>


    [CmdletBinding()]
    param(
        [Parameter(Mandatory = $true)]
        [string]$AccessPackageId,

        [Parameter(Mandatory = $true)]
        [array]$UserList
    )

    # state eq 'Delivered' matters here: without it, Graph's list includes
    # expired assignments alongside current ones, and an expired assignment's
    # id is not something adminRemove should be pointed at.
    $uri = "https://graph.microsoft.com/v1.0/identityGovernance/entitlementManagement/assignments?`$filter=accessPackage/id eq '$AccessPackageId' and state eq 'Delivered'&`$expand=target&`$select=id,target&`$count=true"

    try {
        $assignments = @(Get-GraphPagedResult -Uri $uri -Eventual)
    }
    catch {
        Write-Error -Message "Could not look up the existing assignments to remove. $($_.Exception.Message)" -Category ReadError -TargetObject $AccessPackageId
        return $null
    }

    # Build a lookup of target user id -> assignment id from every current
    # assignment on this access package, one query instead of one per user.
    $lookup = @{}
    foreach ($a in $assignments) {
        $targetId = $null
        if ($a.target) {
            if ($a.target.id) { $targetId = $a.target.id }
            elseif ($a.target.objectId) { $targetId = $a.target.objectId }
        }
        if ($targetId) { $lookup[$targetId] = $a.id }
    }

    $resolved = [System.Collections.Generic.List[object]]::new()
    $notFound = [System.Collections.Generic.List[object]]::new()
    foreach ($user in $UserList) {
        if ($lookup.ContainsKey($user.id)) {
            $resolved.Add([PSCustomObject]@{ User = $user; AssignmentId = $lookup[$user.id] })
        }
        else {
            $notFound.Add($user)
        }
    }

    return [PSCustomObject]@{ Resolved = @($resolved); NotFound = @($notFound) }
}