Microsoft 365 licensing

How to find unused licences in Microsoft 365

Compare bought and assigned licences with Microsoft Graph PowerShell, read the Licenses page in the Microsoft 365 admin centre, or use Altivane's Licensing report for subscriptions needing attention.

By the Published Updated

To find unused licences in Microsoft 365, subtract the licences assigned from the licences bought for each subscription. A licence held by a disabled or idle account still counts as assigned, and free and trial products can carry counts large enough to swamp the rest.

Choose the method that fits the job
MethodBest fit
PowerShellA CSV of every subscription with its bought, assigned and unassigned counts.
Admin centreA quick look at 1 product's total and who it is assigned to.
AltivaneRecommended for regular reviews, with the subscriptions that need attention and the accounts holding licences they may not need.

Before you start

Use an account that can read subscription details: for Microsoft Graph, a supported Microsoft Entra role such as Global Reader or Directory Readers. The PowerShell example requests LicenseAssignment.Read.All, the least privileged permission Microsoft lists for the call; your organisation may require administrator consent. The admin centre needs an administrator who can open the Billing pages.

Here "unused" means bought and not assigned, as Microsoft reports it when you run the script or open the page. The examples read and export; they change nothing.

Option 1

Find unused licences with PowerShell

Install the modules once, then connect and export every subscription that can be assigned to users. The list of subscriptions does not support $filter, so the script reads all of it and sorts the most unassigned first.

PowerShell
# Install once, if the modules are not already installed.
Install-Module Microsoft.Graph.Authentication -Scope CurrentUser
Install-Module Microsoft.Graph.Identity.DirectoryManagement -Scope CurrentUser
PowerShell
$ErrorActionPreference = 'Stop'
Connect-MgGraph -Scopes 'LicenseAssignment.Read.All' -NoWelcome
try {
    $skus = @(Get-MgSubscribedSku -All | Where-Object { $_.AppliesTo -eq 'User' })
    if ($skus.Count -eq 0) {
        Write-Output 'No subscriptions that can be assigned to users were found.'
    } else {
        $report = @($skus | ForEach-Object {
            [pscustomobject]@{
                SkuPartNumber = $_.SkuPartNumber
                Status        = $_.CapabilityStatus
                Bought        = $_.PrepaidUnits.Enabled
                Assigned      = $_.ConsumedUnits
                Unassigned    = $_.PrepaidUnits.Enabled - $_.ConsumedUnits
                InGrace       = $_.PrepaidUnits.Warning
                Suspended     = $_.PrepaidUnits.Suspended
            }
        } | Sort-Object Unassigned -Descending)
        $report | Export-Csv -Path './unused-licences.csv' -NoTypeInformation -Encoding utf8
        $spare = @($report | Where-Object { $_.Unassigned -gt 0 })
        Write-Output "$($spare.Count) of $($skus.Count) subscriptions have unassigned licences."
    }
} finally {
    Disconnect-MgGraph | Out-Null
}

Bought counts enabled licences only, so a subscription that has expired or been cancelled can show a negative Unassigned; read Status, InGrace and Suspended beside it. Part numbers such as ENTERPRISEPACK are not product names: Microsoft publishes a page that maps one to the other. Filter on SkuPartNumber to leave out free or trial products.

Read a single subscription

Run this while connected. Enabled is the number bought and ConsumedUnits the number assigned.

PowerShell
# Replace the example part number.
Get-MgSubscribedSku -All | Where-Object { $_.SkuPartNumber -eq 'ENTERPRISEPACK' } |
    Select-Object SkuPartNumber,ConsumedUnits -ExpandProperty PrepaidUnits

Option 2

Read licence totals in the admin centre

  1. Sign in to the Microsoft 365 admin centre for the correct tenant.
  2. Go to Billing > Licenses.
  3. Read the total licences for each product. The page adds up every subscription with the same product name.
  4. Select a product to see the users and groups it is assigned to. A licence assigned through a group shows the group's name, not each member.
  5. Compare those assigned with the total. Leave without choosing Assign licenses or Unassign licenses.

This suits 1 product, such as before you buy more. It does not suit a full review: subscriptions are combined and group assignments make counting slow.

Common questions

Why do some products show thousands of unassigned licences?

Free and trial products can carry very large counts. Filter them out of the CSV on SkuPartNumber. Altivane leaves free products granted in bulk out of its totals.

Does an assigned licence mean it is in use?

No. A licence assigned to an account nobody uses counts as assigned, so the subscription figures hide it. Altivane's Disabled Accounts Holding Licences and Licences Held by Stale Users tables find some. To see who holds each licence, see how to export licensed users.

Why does Get-MgSubscribedSku fail or return nothing?

Check the permission and role: the call needs LicenseAssignment.Read.All with consent, and the signed-in account needs a supported role such as Global Reader.

Microsoft references

Technical references checked on 5 October 2026. The example scripts have been reviewed and syntax checked; they have not been run against a live tenant.

Talk to us about Altivane

Questions, or pricing? Get in touch.

Contact us