Graph PowerShell Script for Fetching Licensed Microsoft 365 Admins

Managing role assignments in Microsoft 365 is a critical administrative task—but it’s equally important to know which administrators are licensed and actively assigned to critical roles like Global Administrator, Teams Administrator, and more.

In this article, we’ll walk you through a Graph PowerShell script that reliably fetches licensed administrators along with their roles, user details, and sign-in status—using only Microsoft Graph v1.0.


The Script: Get All Licensed Microsoft 365 Admins and Their Roles

# Connect to Microsoft Graph
Connect-MgGraph -Scopes "Directory.Read.All", "User.Read.All"
                                
# Step 1: Get all activated directory roles
$roles = (Invoke-MgGraphRequest -Method GET -Uri "v1.0/directoryRoles").value
                                
# Step 2: Prepare user-role map
$licensedAdminsMap = @{}
                                
foreach ($role in $roles) {
$roleId = $role.id
$roleName = $role.displayName
Write-Host "Checking members for role: $roleName" -ForegroundColor Yellow
                                
# Step 3: Call /directoryRoles/{id}/members to get members of this role
try {
    $membersResponse = Invoke-MgGraphRequest -Method GET -Uri "v1.0/directoryRoles/$roleId/members"
    $members = $membersResponse.value
} catch {
    Write-Warning "Could not retrieve members for role $roleName"
    continue
}
                                
foreach ($member in $members) {
if (-not $member.userPrincipalName) { continue } # Skip non-user objects
                                
# Step 4: Check if user has license
try {
    $licenseInfo = Invoke-MgGraphRequest -Method GET -Uri "v1.0/users/$($member.id)/licenseDetails"
} catch {
    Write-Warning "License lookup failed for: $($member.displayName)"
    continue
}

if ($licenseInfo.value.Count -eq 0) {
    continue # Skip unlicensed users
}

$upn = $member.userPrincipalName

if (-not $licensedAdminsMap.ContainsKey($upn)) {
    $licensedAdminsMap[$upn] = @{
    DisplayName      = $member.displayName
    UserPrincipalName= $upn
    LicenseStatus    = "Licensed"
    Roles            = @($roleName)
    JobTitle         = $member.jobTitle
}
} else {
    $licensedAdminsMap[$upn].Roles += $roleName
}
}
}
                                
# Step 5: Format output
$licensedAdmins = $licensedAdminsMap.Values | ForEach-Object {
    [PSCustomObject]@{
        "Admin Name"         = $_.DisplayName
        "User Principal Name"= $_.UserPrincipalName
        "License Status"     = $_.LicenseStatus
        "Job Title"          = $_.JobTitle
        "Admin Roles"        = ($_.Roles -join ", ")
    }
}
                                
# Step 6: Display result
$licensedAdmins | Format-Table -AutoSize
                            

How the Script Works

  1. Connects to Microsoft Graph using the Connect-MgGraph cmdlet with read permissions.
  2. Retrieves all active directory roles using the /v1.0/directoryRoles endpoint.
  3. For each role, it calls /v1.0/directoryRoles/{id}/members to fetch assigned members.
  4. It filters out non-user objects and fetches license details using /users/{id}/licenseDetails.
  5. Only users with one or more licenses are included in the final output.
  6. Users with multiple roles are grouped, and their roles are concatenated.
  7. The script outputs a clean, formatted table showing each licensed administrator, their UPN, roles, and other useful metadata.

The output is formatted into a clean table for review or export.


Further Enhancements

You can easily extend this script to:

  • Export to CSV
  • $licensedAdmins | Export-Csv -Path "LicensedAdminsReport.csv" -NoTypeInformation -Encoding UTF8
  • Flag unlicensed admins by adding a separate section to track them.
  • Integrate sign-in activity by calling
  • Get-MgUser -ExpandProperty signInActivity.
  • Filter by department or job title, helpful for role reviews and audits.
  • Count number of roles per admin and flag those with unusually high access.
  • Modify the filter to:

    $filter = "category eq 'Policy' and activityDateTime ge $startTime"

Use Cases

  • Security Audits: Identify which licensed users have elevated access.
  • License Cost Reviews: Track how many admins are actively licensed.
  • Compliance Reporting: Provide regular reports to auditors or stakeholders.
  • Role Cleanup: Spot redundant or unused elevated roles.
  • Onboarding & Offboarding: Confirm that only intended users hold privileged access.

Possible Errors & Solutions

Error Cause Solution
userPrincipalName not found Member is not a user (e.g., service principal) Skip the object (already handled in script)
License lookup failed User account is inaccessible or license details API fails Wrapped in try/catch, script continues
403 Forbidden or 401 Unauthorized Insufficient Graph permissions Run Connect-MgGraph with Directory.Read.All and User.Read.All
No output / empty result No roles assigned or users not licensed Validate via Entra admin center and assign proper test data

Conclusion

This script offers a reliable, v1.0-compliant, and production-ready method to report on licensed administrators in Microsoft 365. It’s particularly useful for organizations that want to tighten security, ensure role compliance, and maintain license efficiency.

Because it avoids the beta endpoint, you can deploy it confidently in production environments without extra installations.


Graph PowerShell Explorer Widget

20 Graph PowerShell cmdlets with easily accessible "working" examples.


Permission Required

Example:


                


                


                

© m365corner.com. All Rights Reserved. Design by HTML Codex