Create an access package in entitlement management for an application with a single role using PowerShell

In Microsoft Entra entitlement management, an access package encompasses the policies for how users can obtain assignments for one or more resource roles. The resources can include groups, applications, and SharePoint Online sites.

This article describes how to create an access package for a single application with a single role, using Microsoft Graph PowerShell. This scenario is primarily applicable to environments that are using entitlement management for automating ongoing access for a specific business or middleware application. You can build upon the guidance in this and other articles for more complex scenarios, such as access across multiple applications, or access across applications and other kinds of resources. An organization that has multiple resources or resources with multiple roles can also model their access policies with access packages:

Prerequisites

Using this feature requires Microsoft Entra ID Governance or Microsoft Entra Suite licenses. To find the right license for your requirements, see Microsoft Entra ID Governance licensing fundamentals.

Before you begin creating the access package, you must integrate the application with Microsoft Entra ID. If your application isn't already present in your Microsoft Entra ID tenant, follow the instructions in that article to create an application and service principal for the object. Also ensure that your Microsoft Entra ID tenant has met the prerequisites before configuring Microsoft Entra ID for identity governance.

To create the access package and its associated policies and assignments, you'll need to have the following information ready:

Use case Configuration setting PowerShell variable
All Name of the application in your Microsoft Entra ID tenant $servicePrincipalName
All Name of the application's role $servicePrincipalRoleName
Apps which rely upon a security group ID of the Microsoft Entra security group used by the application, if any $groupId
All Name of the catalog containing the access package $catalogName
All Name to give the access package $accessPackageName
All Description to give the access package $accessPackageDescription
Separation of duties requirement with an incompatible access package the ID of the incompatible access package $incompatibleAccessPackageId (if required)
Users who do not already have assignments and would not be automatically assigned list of users $inputpath (if required)
Users with specific attributes automatically have assignments the query expression for the users in scope $autoAssignmentPolicyFilter (if required)
Allow users who don't have an assignment to request an assignment the scope of users who can request, the approvers, and the access review period depends upon requirements
Automate the creation or removal of assignments based on join or leave workflows in lifecycle workflows the names of the workflows that give and remove access depends upon requirements

Authenticate to Microsoft Entra ID

This section shows how to interact with Microsoft Entra ID Governance by using Microsoft Graph PowerShell cmdlets.

The first time your organization uses these cmdlets for this scenario, you need to be in a Global Administrator role to allow Microsoft Graph PowerShell to be used in your tenant. Subsequent interactions can use a lower-privileged role, such as:

  1. Open PowerShell.

  2. If you don't have the Microsoft Graph PowerShell modules already installed, install the Microsoft.Graph.Identity.Governance module and others by using this command:

    Install-Module Microsoft.Graph
    

    If you already have the modules installed, ensure that you're using a recent version:

    Update-Module microsoft.graph.users,microsoft.graph.identity.governance,microsoft.graph.applications
    
  3. Connect to Microsoft Entra ID:

    $msg = Connect-MgGraph -ContextScope Process -Scopes "User.ReadWrite.All,Application.ReadWrite.All,AppRoleAssignment.ReadWrite.All,EntitlementManagement.ReadWrite.All"
    
  4. If this is the first time you have used this command, you may need to consent to allow the Microsoft Graph Command Line tools to have these permissions.

Create a catalog in Microsoft Entra entitlement management

By default, when an administrator first interacts with entitlement management, then a default catalog is automatically created. However, access packages for governed applications should be in a designated catalog.

  1. Specify the name of the catalog.

    $catalogName = "Business applications"
    
  2. If you already have a catalog for your application governance scenario, then continue at step 4 of this section.

  3. If you don't already have a catalog for your application governance scenario, create a catalog.

    $catalog = New-MgEntitlementManagementCatalog -DisplayName $catalogName
    
  4. Look up the ID of the catalog.

    $catalogFilter = "displayName eq '" + $catalogName + "'"
    $catalog = Get-MgEntitlementManagementCatalog -Filter $catalogFilter -All -expandProperty resources,accessPackages
    if ($catalog -eq $null) { throw "catalog $catalogName not found" }
    $catalogId = $catalog.Id
    

Add the application as a resource to the catalog

Once the catalog is created, add the application as a resource in that catalog.

  1. Specify the name of the application and the name of the application role. Use the name of your application as the value of servicePrincipalName.

    $servicePrincipalName = "SAP Cloud Identity Services"
    $servicePrincipalRoleName = "User"
    
  2. Look up the ID of the application service principal.

    $servicePrincipalFilter = "displayName eq '" + $applicationName + "'"
    $servicePrincipal = Get-MgServicePrincipal -Filter $servicePrincipalFilter -all
    if ($servicePrincipal -eq $null) { throw "service principal $servicePrincipalName not found" }
    $servicePrincipalId = $servicePrincipal.Id
    
  3. Check if the application is already present in the catalog as a resource. If it's already present, continue at step 6 of this section.

    $resourceId = $null
    foreach ($r in $catalog.Resources) { if ($r.OriginId -eq $servicePrincipalId) { $resourceId = $r.id; break } }
    if ($resourceId -ne $null) { write-output "resource already in catalog" } else {write-output "resource not yet in catalog"}
    
  4. Add the application's service principal as a resource to the catalog.

    $resourceAddParams = @{
      requestType = "adminAdd"
      resource = @{
        originId = $servicePrincipalId
        originSystem = "AadApplication"
      }
      catalog = @{ id = $catalogId }
    }
    
    $resourceAdd = New-MgEntitlementManagementResourceRequest -BodyParameter $resourceAddParams
    if ($resourceAdd -eq $null) { throw "resource could not be added" }
    sleep 5
    
  5. Retrieve the ID and the scope of the resource in that catalog.

    $resource = $null
    $resourceId = $null
    $resourceScope = $null
    $catalogResources = Get-MgEntitlementManagementCatalogResource -AccessPackageCatalogId $CatalogId -ExpandProperty "scopes" -all
    
    foreach ($r in $catalogResources) { if ($r.OriginId -eq $servicePrincipalId) { $resource = $r; $resourceId = $r.id; $resourceScope = $r.Scopes[0]; break } }
    if ($resourceId -eq $null) { throw "resource was not added" }
    
  6. Retrieve the roles of the application.

    $resourceRoleFilter = "(originSystem eq 'AadApplication' and resource/id eq '" + $resourceId + "')"
    $resourceRoles = @(get-mgentitlementmanagementcatalogresourcerole  -AccessPackageCatalogId $catalogId -Filter $resourceRoleFilter -All -ExpandProperty "resource")
    if ($resourceRoles -eq $null -or $resourceRoles.count -eq 0) { throw "no roles available" }
    
  7. Select the role that will be included in the access package.

    $resourceRole = $null
    foreach ($r in $resourceRoles) { if ($r.DisplayName -eq $servicePrincipalRoleName) { $resourceRole = $r; break; } }
    if ($resourceRole -eq $null) { throw "role $servicePrincipalRoleName not located" }
    

Add the group as a resource to the catalog

If the application relies upon a security group, then add that group to the catalog so it can be included as a resource. If the application doesn't rely upon a security group, then continue at the next section.

  1. Specify the ID of the group. Use the ID of your group as the value of servicePrincipalName.

    $groupId = "7c2b967b-68c2-418a-a1c6-a3c7efb895a7"
    
  2. Check if the group is already present in the catalog as a resource. If it's already present, continue at step 4 of this section.

    $groupResourceId = $null
    foreach ($r in $catalog.Resources) { if ($r.OriginId -eq $groupId) { $groupResourceId = $r.id; break } }
    if ($groupResourceId -ne $null) { write-output "resource for group already in catalog" } else {write-output "resource for group not yet in catalog"}
    
  3. Add the group as a resource to the catalog.

    $groupResourceAddParams = @{
      requestType = "adminAdd"
      resource = @{
        originId = $groupId
        originSystem = "AadGroup"
      }
      catalog = @{ id = $catalogId }
    }
    
    $groupResourceAdd = New-MgEntitlementManagementResourceRequest -BodyParameter $groupResourceAddParams
    if ($groupResourceAdd -eq $null) { throw "group resource could not be added" }
    sleep 5
    
  4. Retrieve the ID and the scope of the group resource in that catalog.

    $groupResource = $null
    $groupResourceId = $null
    $groupResourceScope = $null
    $catalogResources = Get-MgEntitlementManagementCatalogResource -AccessPackageCatalogId $CatalogId -ExpandProperty "scopes" -all
    
    foreach ($r in $catalogResources) { if ($r.OriginId -eq $groupId) { $groupResource = $r; $groupResourceId = $r.id; $groupResourceScope = $r.Scopes[0]; break } }
    if ($groupResourceId -eq $null) { throw "resource was not added" }
    
  5. Retrieve the member role of the group resource in that catalog.

    $grFilter = "(originSystem eq 'AadGroup' and resource/id eq '" + $groupResourceId + "')"
    $grrs = Get-MgEntitlementManagementCatalogResourceRole -AccessPackageCatalogId $CatalogId -Filter $grFilter -ExpandProperty "resource"
    $grMember = $grrs | where DisplayName -eq "Member"
    

Create the access package for the application

Next you'll use PowerShell to create an access package in a catalog that includes the application's role.

  1. Specify the name and description of the access package.

    $accessPackageName = "SAP Cloud Identity Services"
    $accessPackageDescription = "A user of SAP Cloud Identity Services"
    $accessPackageHidden = $true
    
  2. Check that the access package doesn't already exist.

    foreach ($a in $catalog.AccessPackages) { if ($a.DisplayName -eq $accessPackageName) { throw "access package $accessPackageName already exists" } }
    
  3. Create the access package.

    $accessPackageParams = @{
        displayName = $accessPackageName
        description = $accessPackageDescription
        isHidden = $accessPackageHidden
        catalog = @{
            id = $catalog.id
        }
    }
    $accessPackage = New-MgEntitlementManagementAccessPackage -BodyParameter $accessPackageParams
    $accessPackageId = $accessPackage.Id
    

Add the application role to the access package

Once you've created an access package, then you link the role of the resource for the application in the catalog to the access package.

$rrsParams = @{
 role = @{
     id =  $resourceRole.Id
     displayName =  $resourceRole.DisplayName
     description =  $resourceRole.Description
     originSystem =  $resourceRole.OriginSystem
     originId =  $resourceRole.OriginId
     resource = @{
         id = $resource.Id
         originId = $resource.OriginId
         originSystem = $resource.OriginSystem
     }
 }
 scope = @{
     id = $resourceScope.Id
     originId = $resourceScope.OriginId
     originSystem = $resourceScope.OriginSystem
 }
}

$roleAddRes = New-MgEntitlementManagementAccessPackageResourceRoleScope -AccessPackageId $accessPackageId -BodyParameter $rrsParams

Add the group to the access package

If the application relies upon a group, then you link the group membership of the group to the access package. If the application doesn't rely upon a group, then continue at the next section.

 $grrsParams = @{
  role = @{
      displayName =  "Member"
      description =  ""
      originSystem =  $grMember.OriginSystem
      originId =  $grMember.OriginId
      resource = @{
          id = $groupResource.Id
          originId = $groupResource.OriginId
          originSystem = $groupResource.OriginSystem
      }
  }
  scope = @{
      id = $groupResourceScope.Id
      originId = $groupResourceScope.OriginId
      originSystem = $groupResourceScope.OriginSystem
  }
 }

 $groupRrsAddRes = New-MgEntitlementManagementAccessPackageResourceRoleScope -AccessPackageId $accessPackageId -BodyParameter $grrsParams

Create access package assignment policies for direct assignment

In this section you'll create the first access package assignment policy in the access package, an access package assignment policy for direct assignment, that can be used to track the users who already have access to the application. In the example policy created in this section, only the administrators or access package assignment managers can assign access, users retain access indefinitely, and there are no approvals or access reviews.

  1. Create a policy.

    $policy1Name = "Direct assignment policy"
    $policy1Description = "policy for administrative assignment"
    
    $policy1params = @{
     displayName = $policy1Name
     description = $policy1Description
     allowedTargetScope = "notSpecified"
     specificAllowedTargets = @(
     )
     expiration = @{
         endDateTime = $null
         duration = $null
         type = "noExpiration"
     }
     requestorSettings = @{
         enableTargetsToSelfAddAccess = $true
         enableTargetsToSelfUpdateAccess = $false
         enableTargetsToSelfRemoveAccess = $true
         allowCustomAssignmentSchedule = $true
         enableOnBehalfRequestorsToAddAccess = $false
         enableOnBehalfRequestorsToUpdateAccess = $false
         enableOnBehalfRequestorsToRemoveAccess = $false
         onBehalfRequestors = @(
         )
     }
     requestApprovalSettings = @{
         isApprovalRequiredForAdd = $false
         isApprovalRequiredForUpdate = $false
         stages = @(
         )
     }
     accessPackage = @{
         id = $accessPackageId
     }
    }
    
    $policy1Res = New-MgEntitlementManagementAssignmentPolicy -BodyParameter $policy1params
    $directAssignmentPolicyId = $policy1Res.Id
    
    

Configure separation of duties constraints

Microsoft Entra entitlement management can enforce separation of duties checks to prevent a user who already has an existing assignment to another designated access package, or membership of a designated group, from requesting an access package.

If you don't have separation of duties requirements for this application, then continue at the next section.

If you have separation of duties requirements, then configure the incompatible access packages or existing groups for your access package.

For each access package that is to be marked as incompatible with another, you can use a PowerShell configure access packages as incompatible.

  1. Specify the other access package that is incompatible with this one. Change the value of incompatibleAccessPackageId to the ID of another access package in Microsoft Entra entitlement management.

    $incompatibleAccessPackageId = "67cc7175-7a3d-4cb2-860f-4d9217ba96ca"
    
  2. Create the incompatible reference on this access package.

    $incompatible1params = @{
     "@odata.id" = "https://graph.microsoft.com/v1.0/identityGovernance/entitlementManagement/accessPackages/" + $incompatibleAccessPackageId
    }
    New-MgEntitlementManagementAccessPackageIncompatibleAccessPackageByRef -AccessPackageId $accessPackageId -BodyParameter $incompatible1params
    
  3. Create the incompatible reference on the other access package.

    $incompatible2params = @{
     "@odata.id" = "https://graph.microsoft.com/v1.0/identityGovernance/entitlementManagement/accessPackages/" + $accessPackageId
    }
    New-MgEntitlementManagementAccessPackageIncompatibleAccessPackageByRef -AccessPackageId $incompatibleAccessPackageId -BodyParameter $incompatible2params
    
  4. Repeat for any other access packages.

  5. If your scenario requires the ability to override a separation of duties check, then you can also set up additional access packages for those override scenarios.

Add assignments of existing users who already have access to the application

Add assignments of existing users, who already have access to the application, to the access package and its direct assignment policy. You can directly assign each user to an access package.

  1. Retrieve the existing application role assignments.

    $existingAppRoleAssignments = @(Get-MgServicePrincipalAppRoleAssignedTo -ServicePrincipalId $servicePrincipalId -All)
    
  2. To avoid creating duplicate assignments, retrieve any existing assignments to the access package.

    $existingAssignments1filter = "accessPackage/id eq '" + $accessPackageId + "' and state eq 'Delivered'"
    $existingassignments1 = @(Get-MgEntitlementManagementAssignment -Filter $existingAssignments1filter -ExpandProperty target -All -ErrorAction Stop)
    $existingusers1 = @()
    foreach ($a in $existingassignments1) { $existingusers1 += $a.Target.ObjectId}
    
  3. Create new assignments.

    foreach ($ar in $existingAppRoleAssignments) {
     if ($ar.principalType -ne "User") {
       write-warning "non-user assigned to application role"
     }
     $arpid = $ar.principalId
     if ($existingusers1.contains($arpId)) { continue }
    
     $params = @{
       requestType = "adminAdd"
       assignment = @{
          targetId = $arpId
          assignmentPolicyId = $directAssignmentPolicyId
          accessPackageId = $accessPackageId
       }
     }
     try {
       New-MgEntitlementManagementAssignmentRequest -BodyParameter $params
     } catch {
       write-error "cannot create request for user $upn"
     }
    }
    

Add assignments for any additional users who should have access to the application

This script illustrates using the Microsoft Graph PowerShell cmdlets to add assignments for additional users so they will have access to the application. If you don't have any users that need access, and wouldn't receive it automatically, then continue in the next section.

This script assumes you have an input CSV file containing one column, UserPrincipalName, to assign those users to the access package via its direct assignment policy.

  1. Specify the name of the input file.

    $inputpath = "users.csv"
    
  2. To avoid creating duplicate assignments, retrieve any existing assignments to the access package.

    $existingAssignments2filter = "accessPackage/id eq '" + $accessPackageId + "' and state eq 'Delivered'"
    $existingassignments2 = @(Get-MgEntitlementManagementAssignment -Filter $existingAssignments2filter -ExpandProperty target -All -ErrorAction Stop)
    $existingusers2 = @()
    foreach ($a in $existingassignments2) { $existingusers2 += $a.Target.ObjectId}
    
  3. Create new assignments.

    $users = import-csv -Path $inputpath
    foreach ($userrecord in $users) {
       $upn = $userrecord.UserPrincipalName
       if ($null -eq $upn) {throw "no UserPrincipalName" }
       $u = $null
       try {
          $u = Get-MgUser -UserId $upn
       } catch {
          write-error "no user $upn"
       }
       if ($u -eq $null) { continue }
       if ($existingusers2.contains($u.Id)) { continue }
    
       $params = @{
          requestType = "adminAdd"
          assignment = @{
             targetId = $u.Id
             assignmentPolicyId = $directAssignmentPolicyId
             accessPackageId = $accessPackageId
          }
       }
       try {
          New-MgEntitlementManagementAssignmentRequest -BodyParameter $params
       } catch {
          write-error "cannot create request for user $upn"
       }
    }
    

Add a policy to the access packages for auto assignment

If your organization's policy for who can be assigned access to an application includes a rule based on user's attributes to assign and remove access automatically based on those attributes, you can represent this using an automatic assignment policy. An access package can have at most one automatic assignment policy. If you don't have a requirement for an automatic assignment, then continue at the next section.

  1. Specify the automatic assignment filter expression for users to receive an assignment. Change the value of autoAssignmentPolicyFilter to be a filter for the users in your Microsoft Entra ID that are in scope. The syntax and allowable attributes are provided in rules for dynamic membership groups in Microsoft Entra ID.

    $autoAssignmentPolicyFilter = '(user.city -eq "Redmond")'
    
  2. Use PowerShell to create an automatic assignment policy in the access package.

    $policy2Name = "Automatic assignment policy"
    $policy2Description = "policy for automatic assignment"
    
    $policy2Params = @{
     DisplayName = $policy2Name
     Description = $policy2Description
     AllowedTargetScope = "specificDirectoryUsers"
     SpecificAllowedTargets = @( @{
         "@odata.type" = "#microsoft.graph.attributeRuleMembers"
         description = $policy2Description
         membershipRule = $autoAssignmentPolicyFilter
     } )
     AutomaticRequestSettings = @{
         RequestAccessForAllowedTargets = $true
     }
     AccessPackage = @{
       Id = $accessPackageId
     }
    }
    New-MgEntitlementManagementAssignmentPolicy -BodyParameter $policy2Params
    

Create additional policies to allow users to request access

If users who don't already have access allowed to request to be assigned to the application, then you can also configure an access package assignment policy to allow users to request an access package. You can add additional policies to an access package, and in each policy specify which users can request and who must approve. If you wish to only have users assigned access automatically or by an administrator, then continue at the next section.

For more examples, see Create an assignment policy through PowerShell, accessPackageAssignmentPolicy and Create an assignmentPolicy.

  1. Specify the name, description of the policy, and the ID of a Microsoft Entra user who will be the approver.

    $policy3Name = "example policy"
    $policy3Description = "example of a policy for users to request assignment"
    $policy3ApproverSingleUserId = "1aaaaaa1-2bb2-3cc3-4dd4-5eeeeeeeeee5"
    
  2. Create the policy.

    $policy3Params = @{
     displayName = $policy3Name
     description = $policy3Description
     allowedTargetScope = "allMemberUsers"
     expiration = @{
         type = "noExpiration"
     }
     requestorSettings = @{
         enableTargetsToSelfAddAccess = "true"
         enableTargetsToSelfUpdateAccess = "true"
         enableTargetsToSelfRemoveAccess = "true"
     }
     requestApprovalSettings = @{
         isApprovalRequiredForAdd = "true"
         isApprovalRequiredForUpdate = "true"
         stages = @(
             @{
                 durationBeforeAutomaticDenial = "P7D"
                 isApproverJustificationRequired = "false"
                 isEscalationEnabled = "false"
                 fallbackPrimaryApprovers = @(
                 )
                 escalationApprovers = @(
                 )
                 fallbackEscalationApprovers = @(
                 )
                 primaryApprovers = @(
                     @{
                         "@odata.type" = "#microsoft.graph.singleUser"
                         userId = $policy3ApproverSingleUserId
                     }
                 )
             }
         )
     }
     accessPackage = @{
         id = $accessPackageId
     }
    }
    
    New-MgEntitlementManagementAssignmentPolicy -BodyParameter $policy3Params
    

Configure lifecycle workflows tasks

If you use Microsoft Entra lifecycle workflows for employee join, move leave events, then you can also add tasks to those workflows to add or remove assignments to this access package. If you don't use lifecycle workflows, then continue at the next section.

This example illustrates how to make a change to the join and leave event workflows.

  1. Retrieve the joiner category workflow and its tasks, using Get-MgIdentityGovernanceLifecycleWorkflow command.

  2. Add a task to list of tasks in that workflow.

    Task display name taskDefinitionId arguments
    Request user access package assignment c1ec1e76-f374-4375-aaa6-0bb6bd4c60be name: assignmentPolicyId
    value: The assignment policy ID, such as the value from $directAssignmentPolicyId if no approval is required, for the access package you want to assign the user.

    name: accessPackageId
    value: The access package ID, $accessPackageId, for the access package you want to assign to the user.
  3. Create a new version of the workflow, including the new task, using New-MgIdentityGovernanceLifecycleWorkflowNewVersion command.

  4. Retrieve the leaver category workflow and its tasks, using Get-MgIdentityGovernanceLifecycleWorkflow command.

  5. Add a task to list of tasks in that workflow.

    Task display name taskDefinitionId arguments
    Remove access package assignment for user 4a0b64f2-c7ec-46ba-b117-18f262946c50 name: accessPackageId
    value: A valid access package ID, accessPackageId for the access package you want to unassign from the user.
  6. Create a new version of the workflow, including the new task, using New-MgIdentityGovernanceLifecycleWorkflowNewVersion command.

Manage assignments

Once the access packages, policies, and initial assignments have been created, then users are assigned access to the application's role.

Later, you can monitor for changes to the assignments, or programmatically add or remove assignments.

Retrieve existing assignments

This script illustrates using a filter to retrieve the assignments to the access package that are in state Delivered. The script generates a CSV file assignments.csv with a list of users that have assignments, with one row per assignment.

$assignmentFilter = "accessPackage/id eq '" + $accessPackageId + "' and state eq 'Delivered'"
$assignments = @(Get-MgEntitlementManagementAssignment -Filter $assignmentFilter -ExpandProperty target -All -ErrorAction Stop)
$sp = $assignments | select-object -Property Id,{$_.Target.id},{$_.Target.ObjectId},{$_.Target.DisplayName},{$_.Target.PrincipalName}
$sp | Export-Csv -Encoding UTF8 -NoTypeInformation -Path ".\assignments.csv"

Remove an assignment

You can remove a user's assignment with the New-MgEntitlementManagementAssignmentRequest cmdlet.

$userId = "00aa00aa-bb11-cc22-dd33-44ee44ee44ee"
$filter = "accessPackage/Id eq '" + $accessPackageId + "' and state eq 'Delivered' and target/objectId eq '" + $userId + "'"
$assignment = Get-MgEntitlementManagementAssignment -Filter $filter -ExpandProperty target -all -ErrorAction stop
if ($assignment -ne $null) {
   $params = @{
      requestType = "adminRemove"
      assignment = @{ id = $assignment.id }
   }
   New-MgEntitlementManagementAssignmentRequest -BodyParameter $params
}

Next steps