Using PowerShell and Graph to handle access package assignments

The Microsoft Graph is powerful, however it can be a bit daunting at times due to the sheer number of endpoints and parameters. Just for the access package feature of entitlement management, you have endpoints for assignments, approvals, approval stages, resource role scopes, assignment policies, assignment requests, catalogs, resources… you get the point. In this blog post we will be working with assigning existing access packages to users, just because that is a simple process that might be difficult to understand from the documentation.

Just a quick “What will not be covered”, before we move on:

  • Creating and managing access packages
  • Authentication
  • Paging of graph requests returning more than $top number of results

This is to simplify code and examples. I’ll just drop this Connect-MgGraph cmdlet, and we’ll get the examples:

Install-Module Microsoft.Graph.Identity.Governance -Scope CurrentUser
Connect-MgGraph -Scope EntitlementManagement.ReadWrite.All, User.Read.All, Group.Read.All

1 – Getting access packages and policies

In order to assign access packages, we need to know two things:

  • The id of the access package
  • The id of the access package assignment policy that we are assigning. This is required even though the access package may only have one policy.

In the user interface, the access package id can be found here:

And the policy id can be found here:

In order to locate the same information through PowerShell, we can use the Get-MgEntitlementManagementAccessPackage cmdlet, as follows:

$accessPackages = Get-MgEntitlementManagementAccessPackage -All -ExpandProperty catalog, assignmentPolicies

Or using the Graph, we can get it through the list accesspackages endpoint:

GET https://graph.microsoft.com/v1.0/identityGovernance/entitlementManagement/accessPackages?$expand=catalog,assignmentPolicies

Worth noting here, is that we are getting all access packages in the tenant. This means that we must filter client side, such as the following, which will find all access packages with name matching *Landing zone*:

$accessPackages | 
Where-Object DisplayName -like "*Landing zone*" |
ForEach-Object {
    $AccessPackage = $_
    if($_.AssignmentPolicies) {
        $_.AssignmentPolicies | ForEach-Object {
            [PSCustomObject] @{
                AccessPackage = $AccessPackage.DisplayName
                AccessPackageId = $AccessPackage.Id
                AssignmentPolicy = $_.DisplayName
                AssignmentPolicyId = $_.Id
            }
        }
    }
}

In order to speed up things, we can easily filter on the Graph side instead:

$accessPackages = Get-MgEntitlementManagementAccessPackage -All -ExpandProperty catalog, assignmentPolicies -Filter "contains(displayName,'Landing zone')"

Or through the Graph:

GET https://graph.microsoft.com/v1.0/identityGovernance/entitlementManagement/accessPackages?$expand=catalog,assignmentPolicies&$filter=contains(displayName,'Landing zone')

2 – Listing assigned users

Now that we ways of finding access package ids and the policy ids, we can go on to find assigned users. This is done through the list assignments endpoint.

Getting all assignments for an access package using Powershell

Get-MgEntitlementManagementAssignment -Filter "accessPackage/id eq '5f18f252-6cc5-4d3d-8866-27269f999997'" -ExpandProperty assignmentPolicy

Getting all assignments for an access package using Graph

GET https://graph.microsoft.com/v1.0/identityGovernance/entitlementManagement/assignments?$filter=accessPackage/id eq '5f18f252-6cc5-4d3d-8866-27269f999997'&$expand=assignmentPolicy

Getting all assignments for an access package, limited to a single assignment policy using PowerShell

Get-MgEntitlementManagementAssignment -Filter "accessPackage/id eq '5f18f252-6cc5-4d3d-8866-27269f999997' and assignmentPolicy/id eq 'b532ecbd-d34a-4603-a759-634682fcc281'"

Getting all assignments for an access package, limited to a single assignment policy using Graph

GET https://graph.microsoft.com/v1.0/identityGovernance/entitlementManagement/assignments?$filter=accessPackage/id eq '5f18f252-6cc5-4d3d-8866-27269f999997' and assignmentPolicy/id eq 'b532ecbd-d34a-4603-a759-634682fcc281'

Now that we are able to check existing assignments for access packages, let’s look into assigning access packages.

3 – Assigning access packages

In entitlement management, all assignments are done through access package assignment requests, creating through the post assignment requests endpoint. The examples in the Microsoft documentation is very good, but I’ll have them here anyway, as there are simply way too many different other things you can do with assignment requests. The thing is that all modifications to access package assignments are also made through creating requests. So let’s say you want to extend the life time of an assignment, you create a request to do this. However, in this blogpost we are focusing on the simple “assign access package” operation.

Assigning an access package using PowerShell

New-MgEntitlementManagementAssignmentRequest -Assignment @{
    targetId = "ce3d945f-fc56-4b19-9891-665ca05a998d" # User object id
    assignmentPolicyId = "b532ecbd-d34a-4603-a759-634682fcc281"
    accessPackageId = "5f18f252-6cc5-4d3d-8866-27269f999997"
} -RequestType "adminAdd"

Assigning an access package using Graph

POST https://graph.microsoft.com/v1.0/identityGovernance/entitlementManagement/assignmentRequests

{
    "assignment": {
        "targetId": "ce3d945f-fc56-4b19-9891-665ca05a998d",
        "assignmentPolicyId": "b532ecbd-d34a-4603-a759-634682fcc281",
        "accessPackageId": "5f18f252-6cc5-4d3d-8866-27269f999997"
    },
    "requestType": "adminAdd"
} 

The targetId is the objectid of the user.

4 – Making sure a list of users are assigned an access package

For our last process, we will make something simple that can take a list of user objects as input, making sure they are all assigned to an access package:

function Add-Assignment {
    [CmdletBinding(SupportsShouldProcess = $true)]

    Param(
        [Parameter(Mandatory = $true, ValueFromPipeline = $true)]
        $User,

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

        [Parameter(Mandatory = $true)]
        [string] $AssignmentPolicyId
    )

    Begin {
        # Get existing assignments and create a map for quick lookup
        $existingAssignmentsMap = @{}
        Get-MgEntitlementManagementAssignment -Filter "accessPackage/id eq '$AccessPackageId' and assignmentPolicy/id eq '$AssignmentPolicyId'" -ExpandProperty target |
        Where-Object State -in "delivered" |
        ForEach-Object {
            $existingAssignmentsMap[$_.target.id] = $_
        }
        
    }

    Process {
        if($existingAssignmentsMap.ContainsKey($User.id)) {
            Write-Verbose "Assignment already exists for $($User.id)"
            return
        }

        # Support both User object and User object id
        $userid = $User.id ?? $User

        Write-Verbose "Adding assignment for $($userid)"
        New-MgEntitlementManagementAssignmentRequest -Assignment @{
            targetId           = $userid
            assignmentPolicyId = $AssignmentPolicyId
            accessPackageId    = $AccessPackageId
        } -RequestType "adminAdd"
    }
}


# Pick 10 random users and assign them to the access package
$users = Get-MgUser 
$users | Get-Random -Count 10 | Add-Assignment -AssignmentPolicyId "b532ecbd-d34a-4603-a759-634682fcc281" -AccessPackageId "5f18f252-6cc5-4d3d-8866-27269f999997" -Verbose

Now this is where we need to look at approvals. These two assignments were sent to approval:

In the user interface, you have a feature for bypassing approval:

This does not exist in the Microsoft Graph! In fact, this feature is being deprecated… You can see this under the opt-in preview features, where the “Enforce policy approval setting for admin direct assignments” is not yet enabled (even though it was supposed to be enabled in August)

In order to assign access packages and skipping approvals, you need to have a policy with the following setting:

Hope this helps someone 😊

Leave a comment