Microsoft 365 · Licensing

When Microsoft Swapped Our E5 License — and How We Fixed It with PowerShell

June 2026 7 min read Microsoft 365 · Graph PowerShell · Entra ID

One day, our team noticed that the Office 365 E5 license had completely disappeared from the Microsoft 365 Admin Center. In its place was a new license called Microsoft 365 E5. Microsoft had retired the old SKU and replaced it with a new one — without any migration happening automatically on the group-based licensing side.

The Situation

On the surface, everything seemed fine. Users who already had the old license were still able to use all their Office apps and services — Exchange, Teams, SharePoint — without any interruption. This is because Microsoft preserves active assignments for existing users even after a SKU transition.

The hidden problem: The new Microsoft 365 E5 SKU showed zero consumed units. Any user added to a licensed group after the transition was not getting the license — because the groups were still pointing to the old, now-retired SKU ID.

New users added to existing groups were silently failing to receive their licenses. No error was shown to the end user. From a helpdesk perspective, tickets started coming in: "I can't access my mailbox", "Teams isn't working" — all from recently onboarded accounts.

Why Did This Happen?

In Microsoft 365, when you assign a license to a group (group-based licensing), it stores the SkuId — a unique GUID that identifies the specific product. When Microsoft retired the old SKU and introduced the new one, the SkuId changed. The groups in our tenant were still configured with the old SkuId, so any new license processing by those groups simply failed silently. Existing users retained their licenses as a snapshot — but the group could no longer assign new ones.

SKU Part Number Product Name Status
ENTERPRISEPREMIUM Office 365 E5 Retired / Expired
SPE_E5 Microsoft 365 E5 Active (New)

To make it more complex, each group had its own set of disabled service plans — meaning some groups had certain features like Microsoft Purview or Customer Lockbox turned off intentionally. We couldn't just blindly assign the new SKU; we had to preserve that per-group configuration too.

Reference: You can look up the full list of SKU part numbers, their friendly product names, and all included service plan identifiers in the official Microsoft documentation: Product names and service plan identifiers for licensing — Microsoft Entra ID . This is useful when you need to identify the exact SkuPartNumber or a specific service plan GUID in your tenant.

How We Solved It

The fix required three things: find all affected groups, capture their existing service plan configuration, and then reassign the new SKU with the same settings. We did this entirely using Microsoft Graph PowerShell.

Step 1 — Connect and Identify Both SKUs

Connect to Microsoft Graph with all required scopes upfront, then confirm the old and new SkuIds by querying the exact SkuPartNumber values. Copy the SkuId GUID values from the output — you will need them in the steps below.

POWERSHELL
# Connect with all required scopes upfront
Connect-MgGraph -Scopes "Directory.Read.All", "Organization.Read.All", "Group.ReadWrite.All"

# Retrieve both the old and new SKU by exact SkuPartNumber
Get-MgSubscribedSku -All | Where-Object {
    ($_.SkuPartNumber -eq "ENTERPRISEPREMIUM") -or
    ($_.SkuPartNumber -eq "SPE_E5")
} | Select-Object SkuPartNumber, SkuId, ConsumedUnits

Step 2 — Find All Groups Still Assigned the Old SKU

Using the old SkuId, query all groups that still have it assigned. Because AssignedLicenses is a collection property — not a scalar — you must use the OData any() lambda operator to filter against the skuId sub-property. A plain eq comparison will throw a BadRequest error.

POWERSHELL
$OldSkuId = "<ENTERPRISEPREMIUM-sku-guid>"  # paste from Step 1 output

Get-MgGroup -Filter "assignedLicenses/any(s:s/skuId eq $($OldSkuId))" `
    -All -ConsistencyLevel eventual -CountVariable c `
    -Property Id, DisplayName, AssignedLicenses |
    Select-Object Id, DisplayName
Filter syntax note: The -ConsistencyLevel eventual and -CountVariable parameters are mandatory when using advanced OData filters like any() against Microsoft Graph. Omitting them will result in a BadRequest error.

Step 3 — Export Groups with Their Service Plan Configuration

For each group, capture the service plan names and whether each plan is Enabled or Disabled. This gives you a full audit record before making any changes — critical for verifying the migration and reconstructing configurations if needed.

POWERSHELL
$OldSkuId = "<ENTERPRISEPREMIUM-sku-guid>"

# Get SKU metadata once — contains all service plans in this SKU
$Sku    = Get-MgSubscribedSku -All | Where-Object { $_.SkuId -eq $OldSkuId }
$Report = [System.Collections.Generic.List[PSObject]]::new()

$Groups = Get-MgGroup -Filter "assignedLicenses/any(s:s/skuId eq $($OldSkuId))" `
    -All -ConsistencyLevel eventual -CountVariable c `
    -Property Id, DisplayName, AssignedLicenses

foreach ($Group in $Groups) {
    $License       = $Group.AssignedLicenses | Where-Object { $_.SkuId -eq $OldSkuId }
    $DisabledGuids = $License.DisabledPlans

    foreach ($Plan in $Sku.ServicePlans) {
        $Status = if ($Plan.ServicePlanId -in $DisabledGuids) { "Disabled" } else { "Enabled" }

        $Report.Add([PSCustomObject] @{
            GroupName       = $Group.DisplayName
            GroupId         = $Group.Id
            ServicePlanName = $Plan.ServicePlanName
            ServicePlanId   = $Plan.ServicePlanId
            Status          = $Status
        })
    }
}

$Report | Export-Csv -Path "C:\Temp\Group_ServicePlan_Audit.csv" -NoTypeInformation
Write-Host "Exported to C:\Temp\Group_ServicePlan_Audit.csv" -ForegroundColor Green

Step 4 — Reassign the New SKU, Preserving Disabled Plans

After reviewing the exported CSV, loop through each group and assign the new SPE_E5 SkuId while carrying over the exact same disabled service plan GUIDs from the old assignment. This ensures no accidental feature enablement across any group.

POWERSHELL
$OldSkuId = "<ENTERPRISEPREMIUM-sku-guid>"
$NewSkuId = "<SPE_E5-sku-guid>"         # paste from Step 1 output

$Groups = Get-MgGroup -Filter "assignedLicenses/any(s:s/skuId eq $($OldSkuId))" `
    -All -ConsistencyLevel eventual -CountVariable c `
    -Property Id, DisplayName, AssignedLicenses

foreach ($Group in $Groups) {
    $OldLicense    = $Group.AssignedLicenses | Where-Object { $_.SkuId -eq $OldSkuId }
    $DisabledPlans = $OldLicense.DisabledPlans  # carry over existing disabled plans

    Write-Host "Assigning new SKU to: $($Group.DisplayName)" -ForegroundColor Cyan

    Set-MgGroupLicense -GroupId $Group.Id `
        -AddLicenses @{
            SkuId         = $NewSkuId
            DisabledPlans = $DisabledPlans
        } `
        -RemoveLicenses @()

    Write-Host "  Done. Disabled plans preserved." -ForegroundColor Green
}
Important: Do not remove the old SKU from groups immediately. Wait until you confirm the new SKU is processing correctly for all group members. You can verify by checking LicenseAssignmentStates on individual users or LicenseProcessingState on the group object.

The Outcome

After running the migration script, the new Microsoft 365 E5 SKU was assigned to all previously affected groups. The ConsumedUnits counter on the new SKU began incrementing as group-based licensing processed the assignments. New users added to those groups after this point received their licenses correctly.

Importantly, all service plan configurations — the intentional disablements per group — were preserved exactly as they were under the old SKU. No accidental feature enablement. No support tickets from users getting unexpected access.

Key Takeaways