Public/Get-EntraVacAccessPackageDrift.ps1

function Get-EntraVacAccessPackageDrift {
    <#
    .SYNOPSIS
        Returns users who should be assigned to an access package but are not, and vice versa.

    .DESCRIPTION
        Compares the expected membership (derived from the auto-assignment policy filter) against
        actual delivered assignments and returns a drift report without making any changes.

    .PARAMETER AccessPackageId
        The object ID of the access package to inspect.

    .EXAMPLE
        Get-EntraVacAccessPackageDrift -AccessPackageId "ad524555-24ef-412a-8d20-e070c088a42d"
    #>

    [CmdletBinding()]
    param (
        [Parameter(Mandatory)]
        [string] $AccessPackageId
    )

    $policies = Invoke-MgGraphRequest -Method GET `
        -Uri "https://graph.microsoft.com/v1.0/identityGovernance/entitlementManagement/assignmentPolicies?`$filter=accessPackage/id eq '$AccessPackageId'" |
        Select-Object -ExpandProperty value

    $autoPolicy = $policies | Where-Object { $null -ne $_.automaticRequestSettings } | Select-Object -First 1

    if (-not $autoPolicy) {
        Write-Warning "No auto-assignment policy found for access package $AccessPackageId"
        return
    }

    $assignments = Invoke-MgGraphRequest -Method GET `
        -Uri "https://graph.microsoft.com/v1.0/identityGovernance/entitlementManagement/assignments?`$filter=accessPackage/id eq '$AccessPackageId' and state eq 'Delivered'&`$expand=target" |
        Select-Object -ExpandProperty value

    $assignedUserIds = $assignments | ForEach-Object { $_.target.objectId }

    $graphFilter  = Convert-PolicyFilterToGraphFilter -PolicyFilter $autoPolicy.automaticRequestSettings.requestorFilter
    $targetUsers  = Invoke-MgGraphRequest -Method GET `
        -Uri "https://graph.microsoft.com/v1.0/users?`$filter=$graphFilter&`$select=id,displayName,userPrincipalName" |
        Select-Object -ExpandProperty value

    $targetUserIds = $targetUsers | ForEach-Object { $_.id }

    [PSCustomObject]@{
        AccessPackageId = $AccessPackageId
        ShouldAdd       = $targetUsers | Where-Object { $_.id -notin $assignedUserIds }
        ShouldRemove    = $assignments | Where-Object { $_.target.objectId -notin $targetUserIds } | ForEach-Object { $_.target }
    }
}