Microsoft 365 Group-Based Licensing Errors: Diagnosis and PowerShell Automation
Group-based licensing silently fails in ways that cost hours of troubleshooting — MutuallyExclusiveViolation, missing UsageLocation, nested groups with zero error output. This guide covers every error type, Graph PowerShell detection scripts, and how to build a preventive automation layer.

Microsoft 365 Group-Based Licensing Errors: Diagnosis and PowerShell Automation
TL;DR: Group-based licensing is the only scalable way to manage M365 licenses in organizations with more than a few dozen users — but it silently fails in ways that will cost you hours of troubleshooting. This article covers every error type, how to detect them with Microsoft Graph PowerShell before users start complaining, and how to build a preventive automation layer around the most common failure points.
The Problem
A new hire starts on Monday. Their manager submitted the onboarding request Friday. You added them to the licensing group Saturday morning. It is now 9 AM and they cannot access Teams or Outlook. The Microsoft 365 admin center shows the group is assigned — but the user has no license.
What you are looking at is a silent failure in group-based licensing (GBL). The mechanism processes license assignments asynchronously, writes errors to the user object, and sends no alert. Unless you know exactly where to look, you will spend the morning chasing a ghost.
Group-based licensing requires Entra ID P1 or higher — which is included in Microsoft 365 Business Premium, E3, E5, and Enterprise Mobility + Security. The premise is straightforward: assign licenses to a security group, add users to that group, licenses flow automatically. At scale — managing hundreds of accounts across departments with different license requirements — it is genuinely the right approach. The problem is the failure mode.
Microsoft's queue-based processing means an error that happens during license assignment at 2 AM Saturday will not surface in your awareness until a user calls Monday morning. And unlike Conditional Access policy failures or MFA issues where the user gets an error message, GBL failures leave the user in a state where they simply have no service — no clear indication of what went wrong or why.
Why It Happens
Entra ID processes group license assignments through an internal queuing system. When a user joins a licensed group, the system registers the event and schedules processing. If assignment fails — due to conflicting service plans, missing profile data, or infrastructure-level issues — the error is recorded on the user object rather than thrown as an exception that would surface in real time.
The five root causes, in order of frequency:
1. Missing UsageLocation — Microsoft cannot assign licenses to users with no country/region set, because certain services are geographically restricted by law. New accounts created directly in Entra ID have no UsageLocation by default. Accounts synced from on-premises via Entra ID Connect inherit it from AD attributes (msExchUsageLocation or c) — but those fields are often left blank in on-premises AD configurations.
2. Mutually exclusive service plans — Some service plans within different M365 product licenses cannot coexist on the same user. A common collision: assigning both an E3 license (which includes MCOSTANDARD — Skype for Business Online) and a separate Teams Phone Standard license to the same user via two different groups. The system fails to assign either license from the conflicting group.
3. Nested groups — GBL only processes direct group members. If you add a group as a member of a licensed group, users inside the nested group receive no licenses — and no error is written anywhere. This is the quietest failure mode in the entire system.
4. Duplicate proxy addresses in Exchange Online — If two user objects share the same email alias (common after mailbox migrations), the Exchange Online license assignment fails with a proxy address conflict error.
5. Dependency violations — Some license add-ons require a base service plan to function. Remove the base plan's group without first removing the dependent add-on, and the add-on enters an error state that blocks cleanup.
Step-by-Step Diagnosis and Resolution
Step 1: Find Users in Error State
The admin center path is: Microsoft 365 Admin Center → Billing → Licenses → select product → Groups tab → select group → look for red error indicators.
For bulk investigation across all groups and licenses, Graph PowerShell is faster:
Connect-MgGraph -Scopes "User.Read.All", "Group.Read.All", "Organization.Read.All"
# Get all SKUs available in the tenant
Get-MgSubscribedSku -All | Select-Object SkuPartNumber, SkuId | Sort-Object SkuPartNumber
# Find all users with licensing errors
$allUsers = Get-MgUser -All -Property "displayName,userPrincipalName,licenseAssignmentStates,usageLocation"
$errorReport = foreach ($user in $allUsers) {
$errors = $user.LicenseAssignmentStates | Where-Object { $_.State -eq "Error" }
foreach ($err in $errors) {
$groupName = if ($err.AssignedByGroup) {
(Get-MgGroup -GroupId $err.AssignedByGroup -ErrorAction SilentlyContinue).DisplayName
} else { "Direct Assignment" }
[PSCustomObject]@{
UserPrincipalName = $user.UserPrincipalName
DisplayName = $user.DisplayName
UsageLocation = $user.UsageLocation
SourceGroup = $groupName
SkuId = $err.SkuId
ErrorCode = $err.Error
}
}
}
$errorReport | Export-Csv -Path "gbl_errors_$(Get-Date -Format 'yyyyMMdd').csv" -NoTypeInformation
Run this weekly as a scheduled task and you will catch errors before users notice.
Step 2: Fix ProhibitedInUsageLocationViolation (Missing UsageLocation)
This is the most common error. Bulk-fix users missing the UsageLocation property:
# Find all users with no UsageLocation set
$usersWithoutLocation = Get-MgUser -All `
-Filter "usageLocation eq null" `
-Property "id,displayName,userPrincipalName"
Write-Host "Found $($usersWithoutLocation.Count) users without UsageLocation"
# Set UsageLocation — adjust country code as needed (ISO 3166-1 alpha-2)
foreach ($user in $usersWithoutLocation) {
Update-MgUser -UserId $user.Id -UsageLocation "US"
Write-Host "Set UsageLocation=US for: $($user.UserPrincipalName)"
}
# Force reprocessing immediately after fixing
foreach ($user in $usersWithoutLocation) {
Invoke-MgLicenseUser -UserId $user.UserPrincipalName
}
Critical note: if you have users in multiple countries, do not bulk-set everyone to US. Pull the correct country from HR records or Active Directory before running this. Setting the wrong location locks some users out of services that are not available in their assigned country — for example, Teams Audio Conferencing is not available in all markets.
Step 3: Resolve MutuallyExclusiveViolation (Conflicting Service Plans)
Check which service plans exist in each SKU before assigning them to the same group or user:
# List all service plans in a specific SKU
$skuPartNumber = "SPE_E3" # Microsoft 365 E3
$sku = Get-MgSubscribedSku -All | Where-Object { $_.SkuPartNumber -eq $skuPartNumber }
$sku.ServicePlans | Select-Object ServicePlanName, ServicePlanId | Sort-Object ServicePlanName
Resolve the conflict by disabling the conflicting plan in one of the groups:
$e3SkuId = (Get-MgSubscribedSku -All | Where-Object { $_.SkuPartNumber -eq "SPE_E3" }).SkuId
# MCOSTANDARD (Skype for Business Online Plan 2) conflicts with Teams Phone Standard
$mcoStandardId = "0feaeb32-d00e-4d66-bd5a-43b5b83db82c"
# Reassign E3 to the group with MCOSTANDARD disabled
Set-MgGroupLicense -GroupId "<GROUP-GUID>" `
-AddLicenses @{
SkuId = $e3SkuId
DisabledPlans = @($mcoStandardId)
} `
-RemoveLicenses @()
Step 4: Check for Duplicate Proxy Addresses
# Connect to Exchange Online first
Connect-ExchangeOnline -UserPrincipalName admin@contoso.com
# Find recipients sharing a proxy address
$suspectAlias = "duplicate.user@contoso.onmicrosoft.com"
Get-Recipient -Filter "EmailAddresses -eq '$suspectAlias'" |
Select-Object DisplayName, RecipientType, PrimarySmtpAddress, EmailAddresses
If two objects are returned, you need to remove the duplicate alias from one before the Exchange Online license assignment will succeed.
Step 5: Force Reprocessing After Fixes
After resolving the root cause, the system may not retry automatically. Trigger it manually:
# Single user
Invoke-MgLicenseUser -UserId "user@contoso.com"
# Bulk reprocessing from your error report
$errorReport | Select-Object -ExpandProperty UserPrincipalName -Unique | ForEach-Object {
Invoke-MgLicenseUser -UserId $_
Start-Sleep -Milliseconds 200 # Avoid throttling on large tenants
}
Step 6: Build a Full Licensing Audit Report
For a complete picture of all group-based assignments vs. direct assignments across the tenant:
Connect-MgGraph -Scopes "User.Read.All", "Group.Read.All"
$skuTable = @{}
Get-MgSubscribedSku -All | ForEach-Object {
$skuTable[$_.SkuId] = $_.SkuPartNumber
}
$allUsers = Get-MgUser -All -Property "displayName,userPrincipalName,licenseAssignmentStates,usageLocation,accountEnabled"
$report = foreach ($user in $allUsers) {
foreach ($assignment in $user.LicenseAssignmentStates) {
$source = if ($assignment.AssignedByGroup) {
(Get-MgGroup -GroupId $assignment.AssignedByGroup -ErrorAction SilentlyContinue).DisplayName
} else { "[Direct Assignment]" }
[PSCustomObject]@{
User = $user.UserPrincipalName
AccountEnabled = $user.AccountEnabled
UsageLocation = $user.UsageLocation
License = $skuTable[$assignment.SkuId]
AssignedFrom = $source
State = $assignment.State
Error = $assignment.Error
}
}
}
$report | Export-Csv -Path "license_audit_$(Get-Date -Format 'yyyyMMdd').csv" -NoTypeInformation
Write-Host "Total assignments: $($report.Count)"
Write-Host "Errors found: $(($report | Where-Object { $_.State -eq 'Error' }).Count)"
Common Pitfalls and Edge Cases
Pitfall 1: Deleting a Group With an Active License Assignment
You cannot delete a group that has a license assigned — the portal shows an error, PowerShell throws an exception. This is intentional. The correct sequence is: remove the license from the group with Set-MgGroupLicense -RemoveLicenses @(skuId), wait for propagation (minutes to up to an hour for large groups), then delete the group.
Hidden trap within this trap: if any user in that group had a DependencyViolation — meaning another license they hold depends on the one being removed — removing the group license puts those dependent licenses into an error state on the user. You cannot remove the group until those user-level errors are manually resolved first. Fix with Invoke-MgLicenseUser after sorting the dependency chain.
Pitfall 2: Microsoft Adds New Services to Existing SKUs
Microsoft periodically adds new service plans to existing product licenses. When they do, every group that assigns that product automatically enables the new service for all group members — regardless of whether your group was configured to restrict specific service plans.
Example: when Microsoft added Clipchamp to Microsoft 365 E3, organizations that had carefully restricted their E3 groups to only Exchange and SharePoint suddenly found Clipchamp enabled across the tenant.
Monitor this via the Message Center (Settings → Org settings → Services → Message center) and subscribe to product change notifications. After each SKU update, audit your groups' DisabledPlans configuration and update accordingly.
Pitfall 3: Dynamic Group Rule Changes Remove All Members
Modifying the membership rule of a dynamic group causes Entra ID to remove all current members and reprocess from scratch. During this window, users lose their licenses — and with them, access to Exchange, Teams, and SharePoint.
For production environments: create a new dynamic group with the new rule, assign licenses, confirm 100% assignment, then remove the old group. Never modify a rule on a group that is the sole license source for active users. The propagation delay alone can run 15-45 minutes for groups under 10,000 users and up to 24 hours for very large groups.
Pitfall 4: Nested Groups Fail Silently
This is the most dangerous failure mode because there is absolutely no error written anywhere. If you add Group B as a member of licensed Group A, users in Group B receive no licenses. No error in audit logs, no error on the user object, no notification. The system processes Group A's direct members only.
Diagnose the gap with PowerShell:
$groupId = "<LICENSED-GROUP-GUID>"
# Direct members (these receive licenses)
$directMembers = Get-MgGroupMember -GroupId $groupId -All
Write-Host "Direct members: $($directMembers.Count)"
# All transitive members (these DO NOT receive licenses from GBL)
$transitiveMembers = Get-MgGroupTransitiveMember -GroupId $groupId -All
Write-Host "Transitive members: $($transitiveMembers.Count)"
$unlicensedCount = $transitiveMembers.Count - $directMembers.Count
if ($unlicensedCount -gt 0) {
Write-Warning "$unlicensedCount users in nested groups are NOT receiving licenses!"
}
If there is a gap, flatten the nested groups — add users directly to the licensed group.
Pitfall 5: The Azure AD / MSOnline PowerShell Deprecation
If you are still using Connect-MsolService, Get-MsolUser, or Connect-AzureAD in your license management scripts — those modules were deprecated in March 2024 and stopped functioning as of March 2025. Any scripts using them are now broken.
Migrate to Microsoft Graph PowerShell: Connect-MgGraph, Get-MgUser, Set-MgGroupLicense. The parameter names and output object structures differ significantly — this is not a find-and-replace migration.
How We Handle This at Evolit
At Evolit, we handle employee onboarding through Nexma, which automates the entire workflow — from manager request through HR approval to account provisioning and group membership assignment in Entra ID. Because UsageLocation is collected as part of the onboarding form, it is set on the user account before the account is added to any licensing group, which eliminates ProhibitedInUsageLocationViolation at the source.
Without a workflow tool, you can achieve the same result by building a pre-flight check script that validates UsageLocation before calling New-MgGroupMember. The key is making this a mandatory step in your onboarding process, not a recoverable manual fix — because by the time the user calls to say their email does not work, the error has already been waiting silently for hours.
You can read more about how Nexma handles M365 provisioning at nexma.app.
Summary
- GBL failures are silent — proactively query
licenseAssignmentStatesvia Graph PowerShell weekly instead of waiting for user complaints ProhibitedInUsageLocationViolationis the most common error — always setUsageLocationbefore adding users to licensed groups- Nested groups do not work and produce zero warnings — audit with
Get-MgGroupTransitiveMembervsGet-MgGroupMemberto catch the gap - Changing a dynamic group membership rule removes all members temporarily — always stage changes on a new group
- After fixing any error, run
Invoke-MgLicenseUserto trigger immediate reprocessing rather than waiting up to 24 hours - Azure AD and MSOnline PowerShell modules are dead — migrate all license management scripts to Microsoft Graph PowerShell SDK