@H Raja
Thank you for your post!
Adding onto what @Vasil Michev mentioned, you can try a 3rd party PowerShell script
that I found from a customer question on our Azure Governance and Management Tech Community. For more info - Access Package Export
Generating report of all Access Package assignments in Azure AD Entitlement Management:
<#
.Synopsis
Get graph explorer access token by sending the user to sign in and asking to copy url
#>
function Get-GraphExplorerAccessToken
{
[CmdletBinding()]
[Alias()]
[OutputType([string])]
Param
(
[Parameter(Mandatory=$false,
ValueFromPipelineByPropertyName=$true,
Position=0)]
[String[]] $Scopes = "User.Read.All"
)
$url = "https://login.microsoftonline.com/common/oauth2/v2.0/authorize?nonce=graph_explorer&prompt=select_account&client_id=de8bc8b5-d9f9-48b1-a8ad-b748da725064&response_type=token&redirect_uri=https%3A%2F%2Fdeveloper.microsoft.com%2Fen-us%2Fgraph%2Fgraph-explorer&scope={0}" -f ($Scopes -join "+")
$url | Set-Clipboard
Write-Verbose "Please do the following:"
Write-Verbose ""
Write-Verbose "1. Go to the url on the clipboard"
Write-Verbose "2. Sign in with an account that has the required access"
Write-Verbose "3. Accept any consent (remember, this is the Microsoft Graph Explorer app, not a funky one)"
Write-Verbose "4. When back at the Graph Explorer, copy the url in the address bar (should now contain #access_token=...)"
# Loop and wait to find access token on the clipboard
$accessToken = $null
do {
$clipboardContent = Get-Clipboard
if($clipboardContent -like "*#access_token=*") {
$accessToken = ($clipboardContent -split "[#&]" | Where{$_ -like "access_token=*"}) -replace "access_token="
# Create base64 value of correct length (multiple of 4)
$base64 = $accessToken.Split(".")[1]
while(($base64.Length % 4) -ne 0) {
$base64 += "="
}
$accessTokenDecoded = [System.Text.Encoding]::UTF8.GetString(([System.Convert]::FromBase64String($base64))) | ConvertFrom-Json
$scopesInToken = $accessTokenDecoded.scp -split " "
$Scopes |
Where{$_ -notin $scopesInToken} |
Foreach{
Write-Warning "Token does not contain scope $($_)"
}
} else {
sleep -Milliseconds 100
}
} while(!$accessToken)
Write-Verbose "Access token found!"
return $accessToken
}
# Get access token and build rest param (parameters for Invoke-RestMethod)
$token = Get-GraphExplorerAccessToken -Verbose -Scopes "User.Read.All","EntitlementManagement.ReadWrite.All"
$restParams = @{Headers = @{Authorization = "Bearer $token"}}
# Endpoints
$graphBase = "https://graph.microsoft.com/beta"
$endpoints = @{
accessPackageCatalogs = "{0}/identityGovernance/entitlementManagement/accessPackageCatalogs" -f $graphBase
accessPackages = "{0}/identityGovernance/entitlementManagement/accessPackages?`$top=999" -f $graphBase
accessPackageAssignments = "{0}/identityGovernance/entitlementManagement/accessPackageAssignments?`$top=999" -f $graphBase
users = "{0}/users" -f $graphBase
groups = "{0}/groups" -f $graphBase
accessPackageAssignmentPolicies = "{0}/identityGovernance/entitlementManagement/accessPackageAssignmentPolicies?`$top" -f $graphBase
me = "{0}/me" -f $graphBase
directoryObjects = "{0}/directoryObjects" -f $graphBase
}
# Get all access packages (TODO: Add paging support ot support more than 999 access packages)
Write-Verbose "Getting all access packages..." -Verbose
$AccessPackages = Invoke-RestMethod $endpoints.accessPackages @restParams
if(($AccessPackages.value|measure).Count -gt 0) {
$AccessPackagesMap = $AccessPackages.value | Group-Object -AsHashTable -Property id -AsString
Write-Verbose "Found $($AccessPackagesMap.Count) access packages" -Verbose
} else {
Write-Error "No access packages found!" -ErrorAction Stop
}
# Get all access package assignment policies
Write-Verbose "Getting all access package assignment policies..." -Verbose
$AccessPackageAssignmentPolicies = Invoke-RestMethod $endpoints.accessPackageAssignmentPolicies @restParams
if(($AccessPackageAssignmentPolicies.value|measure).Count -gt 0) {
$AccessPackageAssignmentPoliciesMap = $AccessPackageAssignmentPolicies.value | Group-Object -AsHashTable -Property id -AsString
Write-Verbose "Found $($AccessPackageAssignmentPoliciesMap.Count) access package assignment policies" -Verbose
} else {
Write-Error "No access package assignment policies found!" -ErrorAction Stop
}
# Get all access package assignments
Write-Verbose "Getting all access package assignments..." -Verbose
$url = "https://graph.microsoft.com/beta/identityGovernance/entitlementManagement/accessPackageAssignments?`$expand=target"
$AccessPackageAssignments = New-Object System.Collections.ArrayList
while($url) {
$_Result = Invoke-RestMethod $url @restParams
$url = $_Result.'@odata.nextLink'
if($_Result.value) {
$AccessPackageAssignments.AddRange($_Result.value) | Out-Null
}
}
Write-Verbose "Found $($AccessPackageAssignments.Count) access package assignments" -Verbose
# Process into objects
Write-Verbose "Processing access package assignments" -Verbose
$Report = $AccessPackageAssignments | ForEach-Object {
[PSCustomObject] @{
AccessPackageId = $_.AccessPackageId
AccessPackageName = $AccessPackagesMap[$_.AccessPackageId].DisplayName
AssignmentPolicyId = $_.AssignmentPolicyId
AssignmentPolicy = $AccessPackageAssignmentPoliciesMap[$_.AssignmentPolicyId].DisplayName
AssignmentStatus = $_.AssignmentStatus
AssignmentState = $_.AssignmentState
IsExtended = $_.IsExtended
ExpiredDateTime = $_.ExpiredDateTime
Target = $_.Target.ObjectId
TargetDisplayName = $_.Target.DisplayName
TargetUPN = $_.Target.PrincipalName
}
}
$Report | Out-GridView
Install-Module ExportExcel -Scope CurrentUser
$Report | Export-Excel -Path ~\Desktop\report.xlsx -AutoSize -AutoFilter
Additional Links:
MS Graph REST API - accessPackage resource type
MS Graph REST API - accessPackageCatalog resource type
If you have any other questions, please let me know.
Thank you for your time and patience throughout this issue.
----------
Please remember to "Accept Answer" if any answer/reply helped, so that others in the community facing similar issues can easily find the solution.