Skip to content
LicenseMeter

Unassigned Microsoft 365 licenses, the shelfware problem

Shelfware is waste at the subscription level rather than the user level: seats you purchased that are assigned to nobody at all. No user is involved, so no user-centric report will ever surface it. The gap only shows when purchased and assigned counts are compared per SKU.

Where shelfware comes from

Renewals get sized for headroom that never materializes, a hiring plan slips after the true-up, a project ends and its seats are unassigned but not cancelled, or a bundle purchase brings more seats of a SKU than the team that needed it. The unassigned seats sit on the subscription, invisible in any per-user view, and bill in full.

The raw purchased-minus-assigned arithmetic is also misleading if taken naively. Microsoft auto-provisions free and viral SKUs into every tenant, such as WINDOWS_STORE with a million prepaid units or FLOW_FREE, and capacity-style allotments of thousands of units are licensing plumbing rather than purchases. A useful shelfware number has to exclude those.

Detect it manually

Get-MgSubscribedSku returns purchased and assigned counts per SKU; the difference is your unassigned seat count:

Connect-MgGraph -Scopes 'Organization.Read.All'
Get-MgSubscribedSku | Select-Object SkuPartNumber,
  @{ n = 'Purchased'; e = { $_.PrepaidUnits.Enabled } },
  ConsumedUnits,
  @{ n = 'Unassigned'; e = { $_.PrepaidUnits.Enabled - $_.ConsumedUnits } }
  • Ignore the free and viral rows before drawing conclusions: WINDOWS_STORE, FLOW_FREE, POWERAPPS_VIRAL, TEAMS_EXPLORATORY and similar SKUs show huge prepaid counts that represent no purchase and carry no cost.
  • The output speaks in SKU part numbers, not prices. Turning the unassigned counts into a monthly euro figure means mapping every SKU to your contract price by hand, and repeating that every run.

How LicenseMeter detects it

The sync reads subscribed SKUs through the read-only LicenseAssignment.Read.All permission and computes prepaidUnits.enabled minus consumedUnits per SKU. Free, viral and capacity-style SKUs are excluded by a curated exemption list plus a 5,000-unit capacity threshold, a guard added after the first live tenant sync showed how much noise Microsoft's auto-provisioned allotments create.

Because the signal is pure subscription data, shelfware detection works in every tenant: it needs no Entra ID P1 and is unaffected by concealed report names. Findings persist across nightly syncs, so a count that keeps growing is visible as a trend rather than a one-off snapshot.

The findings list in the demo workspace: filter by rule, select the affected seats, acknowledge in bulk.

What it costs

A shelfware finding is priced as the unassigned seat count times the SKU's monthly price from the per-tenant price book, prefilled with list-price estimates because Microsoft offers no API for your negotiated pricing, and editable to your actual rates.

In the 155-person sample tenant, unassigned paid seats waste € 892,10 a month, the largest single category in the demo workspace.

Sample figures come from the deterministic demo workspace, not from customer data. The waste calculator turns your own seat count into an estimate.

Related waste patterns

See which of your seats match this pattern.

Connect read-only and the free scan lists every affected account in your tenant, priced per seat and per month, with a PowerShell remediation script your IT reviews and runs.

Run my free scan

After the free scan, 14 days of full monitoring, free. No credit card, read-only access.