๐ณ Recipe ยท Licensing & Cost Optimization
Find E5 Users Without Microsoft 365 Copilot Licenses
Identify Microsoft 365 E5 license holders who are candidates for Copilot rollout or license gap analysis
Complexity
Intermediate
Impact
licensing + cost-optimization + reporting + governance + copilot-rollout
Context
Why This Matters
Microsoft 365 Copilot is a separate add-on SKU that must be explicitly assigned on top of a base license such as Microsoft 365 E5. As organizations roll out Copilot in phases, admins frequently need to answer two questions:
- Who already has E5 but hasn't been provisioned Copilot yet? (rollout planning, waitlist management)
- Are we missing revenue/productivity opportunities by leaving E5 seats without Copilot when budget exists?
This recipe produces a reliable, reproducible list of every user assigned an E5 SKU (SPE_E5 or equivalent) who does not have a Microsoft 365 Copilot SKU (Microsoft_365_Copilot) on their account. It also flags disabled accounts and service accounts so they can be excluded from Copilot assignment planning.
When to run this
- Before each wave of a phased Copilot rollout
- Quarterly license true-up or renewal planning
- After bulk onboarding events to verify add-on license parity
- When Finance requests a gap analysis between base and add-on SKUs
Expected Outcomes
After running this recipe you will have:
- A complete CSV report of every user with an E5 license but no Copilot license, including display name, UPN, account enabled status, department, job title, and the specific E5 SKU assigned
- Summary counts: total E5 users, users with Copilot, users without Copilot
- An inventory of all E5 and Copilot SKUs found in the tenant (part numbers vary:
SPE_E5,ENTERPRISEPREMIUM,Microsoft_365_Copilot) - A sorted, department-grouped list ready to hand to business owners for prioritization
- Clear separation of service/admin accounts (usually no department or job title) from human users
Risks & Considerations
Things to watch out for
- SKU part numbers vary across tenants and regions. Microsoft occasionally ships new E5 variants (e.g.,
SPE_E5_CALLINGMINUTES,ENTERPRISEPREMIUM_NOPSTNCONF). Always inspect/subscribedSkusoutput first to confirm which SKUs exist in your tenant. - Group-based licensing: Users may receive E5 via a license-assignment group rather than direct assignment. Both show up in
assignedLicenses, but the remediation path (add/remove) differs. - Disabled and service accounts will appear in results. Filter these out before using the list for Copilot provisioning to avoid wasting a paid add-on seat.
- Do not bulk-assign Copilot based on this list without business approval โ Copilot is a premium paid add-on ($30/user/month list price) and assignment should be driven by rollout plan, not license symmetry.
- Shared mailboxes sometimes carry an E5 license inappropriately. This report will surface that โ treat it as a finding for license reclamation.
- Privacy: The CSV contains UPNs, departments, and job titles. Treat it as internal HR-adjacent data and store accordingly.
Required Permissions
| Permission | Why It's Needed |
|---|---|
| Organization.Read.All | Required to list subscribed SKUs and identify E5 and Copilot SKU IDs in the tenant |
| User.Read.All | Required to enumerate all users and read their assignedLicenses, department, and jobTitle properties |
| Directory.Read.All | Alternative/broader permission if User.Read.All is not already granted; covers user and license directory reads |
The fastest way to get this done: just ask Dex. Copy the prompt below and paste it into your Dex conversation.
For IT Admins
Paste into Dex Pro
Find E5 users without Copilot via the Microsoft 365 Admin Center
The admin center does not offer a native "E5 minus Copilot" report, but you can approximate this list by cross-referencing two license views and exporting to Excel.
Step 1: Export the list of E5 users
- Sign in to the Microsoft 365 Admin Center as a Global Reader or License Administrator.
- Navigate to .
- Locate Microsoft 365 E5 (or your tenant's E5 variant) in the list and click it.
- On the license detail page, click the Assigned users tab.
- Click Export users to download a CSV of every user with this SKU. Save as
e5-users.csv.
Step 2: Export the list of Copilot users
- Return to .
- Click Microsoft 365 Copilot.
- Click the Assigned users tab, then Export users. Save as
copilot-users.csv.
Step 3: Compare the two lists in Excel
- Open both CSV files in Excel.
- In
e5-users.csv, add a new column HasCopilot. - Use a VLOOKUP or XLOOKUP formula against the UPN column of
copilot-users.csv:=IF(ISNA(VLOOKUP(A2, 'copilot-users.csv'!A:A, 1, FALSE)), "No", "Yes") - Filter the HasCopilot column to
No. The remaining rows are your E5 users without Copilot. - Sort by department and review before taking action.
Step 4 (optional): Review in Microsoft Entra
- For any user on the list, open Microsoft Entra admin center.
- Navigate to , search for the user, then open Licenses to verify assignment source (direct vs. group-based) before making changes.
This manual path is acceptable for small tenants but becomes error-prone beyond a few hundred users. Use the API or script approach for anything at scale.
Find E5 users without Copilot via Microsoft Graph
The query requires three Graph calls and client-side filtering (Graph does not support a "has SKU A but not SKU B" filter directly).
Step 1: List subscribed SKUs to get SKU IDs
GET https://graph.microsoft.com/v1.0/subscribedSkus?$select=skuId,skuPartNumber,consumedUnits,prepaidUnitsLook for entries where skuPartNumber matches E5 (SPE_E5, ENTERPRISEPREMIUM) and Copilot (Microsoft_365_Copilot). Record the GUIDs in skuId.
Example response (truncated)
{
"value": [
{
"skuId": "06ebc4ee-1bb5-47dd-8120-11324bc54e06",
"skuPartNumber": "SPE_E5",
"consumedUnits": 83
},
{
"skuId": "639dec6b-bb19-468b-871c-c5c441c4b0cb",
"skuPartNumber": "Microsoft_365_Copilot",
"consumedUnits": 58
}
]
}Step 2: List users assigned the E5 SKU
Use the assignedLicenses/any() filter with the E5 SKU ID from Step 1:
GET https://graph.microsoft.com/v1.0/users?$filter=assignedLicenses/any(x:x/skuId eq 06ebc4ee-1bb5-47dd-8120-11324bc54e06)&$select=id,displayName,userPrincipalName,accountEnabled,assignedLicenses,department,jobTitle&$top=999Page through results using the @odata.nextLink value until exhausted.
Step 3: Filter client-side for users without the Copilot SKU
Graph does not support not any() negation across assignedLicenses, so filter in your code:
const e5WithoutCopilot = users.filter(u => {
const skuIds = (u.assignedLicenses || []).map(l => l.skuId);
return skuIds.includes(E5_SKU_ID) && !skuIds.includes(COPILOT_SKU_ID);
});Step 4 (optional): Verify service plan detail
For any single user, confirm licensing details including service plans:
GET https://graph.microsoft.com/v1.0/users/{user-id}/licenseDetailsThrottling notes
- Use
$top=999to minimize pagination round trips. - Expect Graph throttling above ~10,000 users โ implement exponential backoff on HTTP 429 with the
Retry-Afterheader. - Results are eventually consistent; a user whose license was changed in the last few minutes may not yet reflect in
assignedLicenses.
Find E5 users without Copilot via PowerShell
The Microsoft Graph PowerShell SDK makes this a short, reliable script. The approach:
- Connect to Graph with the required read scopes
- Pull the SKU catalog and resolve the E5 and Copilot SKU IDs
- Query all users assigned the E5 SKU (server-side filter for efficiency)
- Filter client-side for the absence of the Copilot SKU
- Export to CSV
Prerequisites
- PowerShell 7.x recommended
Microsoft.Graphmodule:Install-Module Microsoft.Graph -Scope CurrentUser- Delegated scopes:
Organization.Read.All,User.Read.All
Inline example
# Connect with read scopes
Connect-MgGraph -Scopes "Organization.Read.All", "User.Read.All"
# Resolve SKU IDs dynamically (don't hardcode GUIDs)
$skus = Get-MgSubscribedSku -All
$e5Sku = $skus | Where-Object { $_.SkuPartNumber -in 'SPE_E5','ENTERPRISEPREMIUM' } | Select-Object -First 1
$copilotSku = $skus | Where-Object { $_.SkuPartNumber -like '*Copilot*' } | Select-Object -First 1
# Get E5 users via server-side filter
$e5Users = Get-MgUser -All -Filter "assignedLicenses/any(x:x/skuId eq $($e5Sku.SkuId))" `
-Property Id,DisplayName,UserPrincipalName,AccountEnabled,AssignedLicenses,Department,JobTitle
# Filter client-side for users WITHOUT Copilot
$result = $e5Users | Where-Object {
$_.AssignedLicenses.SkuId -notcontains $copilotSku.SkuId
}
$result | Export-Csv '.\E5-Users-Without-Copilot.csv' -NoTypeInformationUse the downloadable script below for a production-ready version with parameter handling, progress indicators, and error handling.
Next steps