Microsoft 365 licensing

How to find disabled users with licences in Microsoft 365

List disabled accounts that still hold licences with Microsoft Graph PowerShell, filter blocked users in the Microsoft 365 admin centre, or use Altivane's Licensing report for a rated list.

By the Published Updated

To find disabled users with licences in Microsoft 365, list the accounts where accountEnabled is false and keep those with at least 1 assigned licence. Disabling an account does not remove its licences. Removing one starts a 30 day countdown on the mailbox, so check it first.

Choose the method that fits the job
MethodBest fit
PowerShellA CSV of every disabled account that holds a licence, with how each was assigned.
Admin centreA quick look at blocked accounts for 1 product, or at 1 person's licences.
AltivaneRecommended for regular clean-ups, rated against a threshold.

Before you start

Use an account that can read users and subscriptions, such as Global Reader. The PowerShell example requests User.Read.All and LicenseAssignment.Read.All; your organisation may require administrator consent. Saving a custom filter in the admin centre needs a role that manages user views, such as User Administrator.

Disabled here means sign-in is blocked: the admin centre says blocked, and Microsoft Graph stores accountEnabled as false. Guests are included, and the user list can lag for accounts changed a moment ago. The examples read and export and change nothing, apart from the admin centre filter, a saved view every admin sees until it is deleted.

Option 1

Find disabled users with licences with PowerShell

Install the modules once, then connect and export every disabled account that holds a licence. Microsoft Graph applies the filter, so only those accounts come back.

PowerShell
# Install once, if the modules are not already installed.
Install-Module Microsoft.Graph.Authentication, Microsoft.Graph.Users -Scope CurrentUser
Install-Module Microsoft.Graph.Identity.DirectoryManagement -Scope CurrentUser
PowerShell
$ErrorActionPreference = 'Stop'
Connect-MgGraph -Scopes 'User.Read.All', 'LicenseAssignment.Read.All' -NoWelcome
try {
    $names = @{}
    foreach ($sku in Get-MgSubscribedSku -All) {
        $names[$sku.SkuId.ToString()] = $sku.SkuPartNumber
    }
    $query = @{
        Filter           = 'accountEnabled eq false and assignedLicenses/$count ne 0'
        Property         = 'displayName,userPrincipalName,userType,licenseAssignmentStates'
        ConsistencyLevel = 'eventual'
        CountVariable    = 'disabledCount'
    }
    $users = Get-MgUser -All @query
    $report = @(foreach ($user in $users) {
        $held = @($user.LicenseAssignmentStates | ForEach-Object {
            $id = $_.SkuId.ToString()
            $product = if ($names.ContainsKey($id)) { $names[$id] } else { $id }
            $via = if ($_.AssignedByGroup) { "group $($_.AssignedByGroup)" } else { 'direct' }
            "$product ($via)"
        })
        [pscustomobject]@{
            DisplayName       = $user.DisplayName
            UserPrincipalName = $user.UserPrincipalName
            UserType          = $user.UserType
            Licences          = $held -join '; '
        }
    })
    if ($report.Count -eq 0) {
        Write-Output 'No disabled account holds a licence.'
    } else {
        $report | Sort-Object DisplayName |
            Export-Csv -Path './disabled-with-licences.csv' -NoTypeInformation -Encoding utf8
        Write-Output "$($report.Count) disabled accounts hold licences."
    }
} finally {
    Disconnect-MgGraph | Out-Null
}

Keep ConsistencyLevel and CountVariable: the licence count needs them, or Microsoft Graph returns an error. Licences gives part numbers, each followed by direct or the ID of the group that assigned it.

Check a single account

Reconnect with Connect-MgGraph, then read 1 person's licences. The main export above disconnects when it finishes.

PowerShell
# Run while connected to Microsoft Graph. Replace the example account.
$properties = 'displayName,accountEnabled,licenseAssignmentStates'
$user = Get-MgUser -UserId 'person@example.com' -Property $properties
$user | Select-Object DisplayName, AccountEnabled
$user.LicenseAssignmentStates | Select-Object SkuId, AssignedByGroup, State, Error

AssignedByGroup is empty for a licence assigned directly and holds the group's ID otherwise.

Option 2

Review blocked accounts in the admin centre

  1. Sign in to the Microsoft 365 admin centre for the correct tenant.
  2. Go to Users > Active users, select Filter set, then New filter.
  3. In the Custom filter pane, name the filter, choose blocked users under Sign-in status, optionally choose 1 product under Assigned product license, and select Add.
  4. Select a person, open the Licenses and Apps tab and read the Licenses section.
  5. Close the pane without changes. To delete the filter, switch to it, then choose Filter set, Edit filter, the ellipsis (...) and Delete.

This suits a quick look at 1 product or 1 person. For every blocked account's licences in 1 list, use PowerShell or a report.

Common questions

Can I remove the licence from a disabled account straight away?

Not before checking the mailbox. Removing a licence holds its data for 30 days, then deletes it, and any holds must go first. To keep the mailbox, convert it to a shared mailbox while the licence is still assigned. Under 50 GB it can then lose the licence, but the account must stay.

Why is an enabled account that nobody uses not on the list?

The list holds disabled accounts only. To find enabled accounts with no recent sign-in, see how to find inactive users.

Why does the PowerShell call return an error?

The licence count is an advanced query, so the request needs the consistency level eventual and a count. The script sets both; keep them if you adapt the call.

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