Get-MgSubscribedSku: 7 Things It Actually Tells You About Your Licenses

By Ahmet Tolga KAYA 5 min read
Get-MgSubscribedSku: 7 Things It Actually Tells You About Your Licenses

Get-MgSubscribedSku is the cmdlet behind almost every Microsoft 365 license script you’ll ever write. It doesn’t touch a single user it returns the tenant’s own subscription data: which SKUs you own, how many seats are consumed, and what service plans are bundled inside each one. Any script that assigns, removes, or reports on licenses reads from this cmdlet first, whether that’s obvious in the code or not.

Run alone, the output looks like a wall of GUIDs. Read correctly, it answers real operational questions: are we about to run out of E5 seats, what does ENTERPRISEPACK actually mean, and is that subscription still active.

What Get-MgSubscribedSku Returns

Get-MgSubscribedSku | Format-ListCode language: PHP (php)

Each object represents one commercial subscription your tenant has acquired not one user, one license SKU. A tenant with Office 365 E3, Microsoft 365 E5, and a Power BI add-on shows up as three separate objects here, regardless of how many people are actually licensed under each one.

The fields that matter day to day: SkuId (a GUID, used to reference the SKU in other cmdlets), SkuPartNumber (Microsoft’s internal product code), ConsumedUnits (licenses currently assigned), PrepaidUnits (what you’ve actually purchased, broken down by status), ServicePlans (the individual services bundled inside), and CapabilityStatus (Enabled, Suspended, Warning, or LockedOut — the last one means the subscription itself was canceled).

Permissions It Actually Needs

Connect-MgGraph -Scopes "Organization.Read.All"Code language: CSS (css)

If you haven’t set up the module or a Graph connection yet, installing the Microsoft Graph PowerShell module and connecting with the right scopes both come before this step. Organization.Read.All is the lowest-privilege scope that works. Directory.Read.All and LicenseAssignment.Read.All also grant access if a script already carries one of them for other reasons, but there’s no benefit to requesting anything broader just to run Get-MgSubscribedSku on its own.

Checking Available Seats, Not Just Totals

ConsumedUnits alone doesn’t tell you how many seats are left for that, you need PrepaidUnits, which is itself a nested object rather than a flat number. Expand it explicitly:

Get-MgSubscribedSku | Select-Object SkuPartNumber, ConsumedUnits -ExpandProperty PrepaidUnitsCode language: JavaScript (javascript)

PrepaidUnits.Enabled is the purchased seat count for that SKU. Subtract ConsumedUnits from it and you have actual seats available the number that matters before onboarding a new hire or approving a license request, not the total your finance system thinks you own.

Translating SkuPartNumber Into a Name You Recognize

SkuPartNumber values like ENTERPRISEPACK or SPE_E5 are Microsoft’s internal product codes, not the names shown in the admin center — ENTERPRISEPACK is Office 365 E3, for instance, and there’s no way to guess that from the string itself. Microsoft maintains a reference table of product names and service plan identifiers mapping every published code to its retail name, with a downloadable CSV if you’d rather join against it in a script than look codes up by hand.

That table lags brand-new SKUs, Copilot bundles especially, so an unfamiliar code isn’t automatically a mistake in your output — it might just be a product too recent for the published list.

Seeing What’s Inside a SKU

A single SKU bundles multiple services Exchange, Teams, and SharePoint all inside one Office 365 E3 license, for example. ServicePlans on each subscribed SKU object lists exactly which ones:

$licenses = Get-MgSubscribedSku
$licenses | Where-Object SkuPartNumber -eq 'ENTERPRISEPACK' | Select-Object -ExpandProperty ServicePlansCode language: JavaScript (javascript)

This is what you’d check before assuming a user has access to a specific service just because they’re licensed at all — the SKU name tells you the plan tier, not which individual services are actually turned on inside it.

Getting One Specific Subscription

For a single known SKU rather than the full list, pass its ID directly instead of piping through Where-Object:

Get-MgSubscribedSku -SubscribedSkuId "<SkuId_UnderscoreSkuId>"Code language: HTML, XML (xml)

The ID format here is two GUIDs joined with an underscore — the tenant’s account ID and the SKU ID — not just the SkuId alone. Pull it from a previous Get-MgSubscribedSku call’s Id property rather than trying to construct it by hand.

Why the Output Is Sometimes Empty or Wrong

An empty result usually means the connected scope doesn’t cover it — User.Read.All alone, for instance, doesn’t grant access to subscription data, regardless of how many other Graph calls are working fine in the same script. Reconnect with Organization.Read.All and it resolves immediately.

A CapabilityStatus of LockedOut on a SKU you expected to be active means the underlying subscription was canceled, not that something is broken in the script. And if ConsumedUnits looks stale compared to what you just assigned or removed, give it a minute — subscription counts don’t always reflect a license change instantaneously, even though the individual user’s AssignedLicenses property usually does.

For actually removing licenses once you’ve identified who’s over-provisioned, see how to remove Microsoft 365 licenses with PowerShell, which uses the SkuId this cmdlet returns as its starting point.

Frequently Asked Questions

What permission scope does Get-MgSubscribedSku need?

Organization.Read.All is the minimum. Directory.Read.All and LicenseAssignment.Read.All also work if the script already needs one of them for other reasons.

How do I see how many licenses are left, not just how many are used?

Expand PrepaidUnits alongside ConsumedUnits — PrepaidUnits.Enabled minus ConsumedUnits is the actual available seat count.

Why does SkuPartNumber show a code instead of a name I recognize?

It’s Microsoft’s internal product identifier, not the retail name. Cross-reference it against Microsoft’s product names and service plan identifiers reference table.

Does Get-MgSubscribedSku show individual users’ licenses?

No. It returns the tenant’s subscriptions, not per-user assignments. For that, query AssignedLicenses on the user object with Get-MgUser instead.

What does CapabilityStatus: LockedOut mean?

The subscription was canceled. It’s not an error in your script — it reflects the actual billing status of that SKU.

References

Microsoft — Get-MgSubscribedSku (Microsoft.Graph.Identity.DirectoryManagement) https://learn.microsoft.com/en-us/powershell/module/microsoft.graph.identity.directorymanagement/get-mgsubscribedsku

Microsoft — subscribedSku Resource Type https://learn.microsoft.com/en-us/graph/api/resources/subscribedsku

Microsoft — View Microsoft 365 Licenses and Services with PowerShell https://learn.microsoft.com/en-us/microsoft-365/enterprise/view-licenses-and-services-with-microsoft-365-powershell

Microsoft — Product Names and Service Plan Identifiers for Licensing https://learn.microsoft.com/en-us/entra/identity/users/licensing-service-plan-reference

Ahmet Tolga KAYA

Systems Engineer and Technical Writer focused on Windows, Microsoft technologies, infrastructure, cybersecurity, automation, and platform reliability.