DEV Community

Cover image for Solved: Access Package Report Script
Darian Vance
Darian Vance

Posted on • Originally published at wp.me

Solved: Access Package Report Script

🚀 Executive Summary

TL;DR: The “Insufficient privileges” error when scripting Azure Access Package reports often stems from using delegated permissions that lack the necessary high-privilege roles. This guide provides solutions ranging from an emergency interactive login with an Identity Governance Administrator to a robust, automated Service Principal approach with specific application permissions.

🎯 Key Takeaways

  • Azure Identity Governance endpoints frequently require specific high-privilege roles or application permissions, which are not typically covered by standard reader roles like Global Reader.
  • For automated reporting, implement an Azure AD App Registration (Service Principal) and grant it EntitlementManagement.Read.All and User.Read.All application permissions, ensuring admin consent is explicitly granted.
  • Always prefer certificate-based authentication for production Service Principals and securely store all credentials, including client secrets or certificate thumbprints, in Azure Key Vault to enhance security and manageability.

Tired of ‘Insufficient privileges’ errors when scripting Azure Access Package reports? This guide breaks down why your standard user permissions are failing and provides three real-world solutions, from a quick admin fix to a robust, automated Service Principal approach.

From the Trenches: Decoding the “Insufficient Privileges” Error on Azure Access Package Reports

It was 8 AM on a Monday, and the compliance team was breathing down my neck. They needed a full report of every user with active assignments to our ‘Project Titan’ Access Package for an external audit due by noon. I fired up my trusty PowerShell terminal, ran my usual Graph script, and… Authorization_RequestDenied. A wall of red text telling me I had ‘Insufficient privileges to complete the operation’. My Global Reader role, which can see almost everything else in Azure AD, was useless here. That’s when the coffee kicked in and I remembered the subtle, infuriating difference between who I am and who my script is.

The “Why”: Delegated vs. Application Permissions

This is the crux of the problem. When you run Connect-MgGraph and sign in with your own account, you’re using Delegated permissions. The script acts with a combination of the permissions you granted the “Microsoft Graph PowerShell” Enterprise App and your own personal permissions. You’d think being a Global Reader would be enough, but many Identity Governance endpoints require specific, high-privilege roles that aren’t part of the standard reader roles.

For automated, background reporting, you need Application permissions. This means the script authenticates as an application (a Service Principal) itself, not as you. This application is granted its own set of tenant-wide permissions that don’t depend on any user being signed in. This is the correct, secure, and automated way to handle these kinds of tasks.

The Fixes: From Emergency Hacks to Permanent Solutions

Depending on your urgency and long-term needs, here are three ways to solve this problem. I’ve used all three in my career.

Solution 1: The “Break Glass in Case of Emergency” Method

This is the quick and dirty fix for when the auditors are in the lobby and you just need the data now. It’s not scalable, not secure for automation, but it gets the job done in a pinch.

You simply run the script interactively using an account that has a highly privileged directory role. The Identity Governance Administrator role is designed for this. A Global Admin will also work, but that’s like using a sledgehammer to hang a picture frame.

# 1. Open PowerShell on your machine.
# 2. Make sure you are logged in as a user with the 'Identity Governance Administrator' role.

# The key is asking for the right scopes during connect.
Connect-MgGraph -Scopes "EntitlementManagement.Read.All", "Directory.Read.All"

# Now, your script to get the report should work.
$accessPackage = Get-MgEntitlementManagementAccessPackage -Filter "displayName eq 'Project Titan'" -ErrorAction Stop
Get-MgEntitlementManagementAccessPackageAssignment -AccessPackageId $accessPackage.Id -ExpandProperty "target" | Select-Object @{N="User";E={$_.Target.DisplayName}}, @{N="UserEmail";E={$_.Target.UserPrincipalName}}, State
Enter fullscreen mode Exit fullscreen mode

Warning: Never, ever hardcode the credentials of a Global Administrator or other privileged account into a script. This interactive method is for one-time, emergency use only.

Solution 2: The “Right Way” (The DevOps Approach)

This is the permanent, automated fix. We will create an identity for our script—an App Registration/Service Principal—and give it the exact API permissions it needs. This is perfect for running in an Azure Automation Account, a GitHub Action, or a scheduled task on a server.

  1. Create an App Registration: In Azure AD, go to “App registrations” and create a new one. Let’s call it svc-EntitlementReporting-spn.
  2. Grant API Permissions:
    • In the app, go to “API permissions” -> “Add a permission” -> “Microsoft Graph”.
    • Choose “Application permissions”.
    • Search for and add EntitlementManagement.Read.All and User.Read.All. The first lets you read access packages and assignments; the second lets you read the user profiles assigned to them.
    • Crucially, click the “Grant admin consent for [Your Tenant]” button. If you don’t, the permissions won’t activate.
  3. Create a Credential: Go to “Certificates & secrets”. The best practice is to upload the public key of a certificate, but for simplicity, you can also create a “Client secret”. Store this value securely!
  4. Update Your Script: Now, modify your script to connect non-interactively.
# These values should be stored securely (e.g., Azure Key Vault, Automation Variables)
$tenantId     = "your-tenant-id-guid"
$appId        = "your-app-registration-client-id"
$clientSecret = "your-super-secret-client-secret-value"

# Connect using the App's identity
Connect-MgGraph -TenantId $tenantId -AppId $appId -ClientSecret (ConvertTo-SecureString $clientSecret -AsPlainText -Force)

# The rest of your script runs without any user interaction!
Write-Host "Successfully connected as $($MgContext.Account)"
Get-MgEntitlementManagementAccessPackageAssignment -Filter "accessPackage/displayName eq 'Project Titan'" -ExpandProperty "target" | 
  Select-Object @{N="User";E={$_.Target.DisplayName}}, @{N="UserEmail";E={$_.Target.UserPrincipalName}}, State |
  Export-Csv -Path "C:\temp\ProjectTitan_Audit.csv" -NoTypeInformation

Write-Host "Report generated successfully."
Enter fullscreen mode Exit fullscreen mode

Pro Tip: Always use certificate-based authentication for production automation. Secrets expire and can be accidentally logged. Store your secrets and certificate thumbprints in Azure Key Vault and have your script pull them from there at runtime.

Solution 3: The “Forget the Code” GUI Approach

Let’s be real. Sometimes you don’t need a fancy script. You just need a CSV file, and you need it five minutes ago. The Azure Portal is your friend.

  1. Navigate to the Azure Portal and go to Microsoft Entra ID.
  2. Select Identity Governance from the left-hand menu.
  3. Click on Access packages and find the one you need to report on (e.g., “Project Titan”).
  4. Click on the Assignments tab.
  5. You’ll see a list of everyone with an assignment. Right above the list, there’s a handy Download button.

This will give you a CSV with all the core information. It’s not as flexible as a custom script if you need to join it with other data, but for a quick snapshot, it’s often the fastest path from A to B.


Darian Vance

👉 Read the original article on TechResolve.blog


☕ Support my work

If this article helped you, you can buy me a coffee:

👉 https://buymeacoffee.com/darianvance

Top comments (0)