Loading_
Loading_
Cross-references licence assignment against 90 days of activity to surface dormant seats and downgrade candidates.
#Requires -Modules Microsoft.Graph.Users, Microsoft.Graph.Reports<#.SYNOPSIS Finds dormant and over-provisioned Microsoft 365 licences. .DESCRIPTION Joins licence assignment (Graph /users) with activity data (Graph /reports) to classify every assigned seat and calculate the annual saving from reclaiming or downgrading it. .EXAMPLE Connect-MgGraph -Scopes 'User.Read.All','Reports.Read.All','Organization.Read.All' .\Get-LicenceOptimisation.ps1 -InactiveDays 90 -ExportPath .\licences.csv .NOTES Author : AIInfraEngine Version: 2.9.0#>[CmdletBinding()]param( [ValidateRange(30, 365)] [int]$InactiveDays = 90, [string]$ExportPath = ".\licence-optimisation-$(Get-Date -Format 'yyyyMMdd').csv", # Override with your negotiated rates — list price flatters the report. [hashtable]$MonthlyCost = @{ 'SPE_E5' = 57.00128 more lines behind the library licence
Get-LicenceOptimisation.ps1 · 6.2 KB · 3 dependencies documented
This one is behind the licence because it is the kind of script that does real damage when it is wrong — and the version above has already been broken and fixed by two engineers in a live estate.
A Microsoft 365 tenant almost always carries more licences than it needs, because assignment is a joining ritual and reclamation is nobody’s job.
The script pulls assignment from Graph and usage from the reporting API, then classifies each seat: active, dormant (no activity in the window), or over-licensed (E5 assigned but only E3 features used).
It reports in dollars, not seats — the number that gets a renewal conversation moving is the annual figure, and it derives that from your actual SKU pricing rather than list price.
| Name | Type | Required | Description |
|---|---|---|---|
InactiveDays | int | Optional | Activity window. Default 90. |
MonthlyCost | hashtable | Optional | SKU to negotiated monthly rate. |
The platform turns any script into a governed automation — versioned, gated, audited and reversible.