All scripts
Microsoft 365 168
Get-M365LicenseUsageReport
Pulls every license SKU in the tenant and shows assigned versus available seats, so you can spot licenses worth reclaiming before the next renewal.
Get-M365LicenseUsageReport.ps1
<#
.SYNOPSIS
Get-M365LicenseUsageReport.ps1 - Reports assigned vs. available Microsoft 365 licenses.
.DESCRIPTION
Pulls every license SKU in the tenant via Microsoft Graph and shows how many
seats are consumed versus purchased, so you can spot SKUs worth reclaiming
before the next renewal. Requires Graph scope: Organization.Read.All
.AUTHOR
Shehryar Hassan
.EXAMPLE
.\Get-M365LicenseUsageReport.ps1 -OutputPath ".\LicenseReport.csv"
#>
param(
[Parameter(Mandatory=$false)]
[string]$OutputPath = ".\LicenseReport.csv"
)
Write-Host "=============================================" -ForegroundColor Cyan
Write-Host " Microsoft 365 License Usage Report" -ForegroundColor Cyan
Write-Host "=============================================" -ForegroundColor Cyan
if (-not (Get-MgContext)) {
Write-Host "[INFO] Connecting to Microsoft Graph..." -ForegroundColor Yellow
Connect-MgGraph -Scopes "Organization.Read.All"
}
$skus = Get-MgSubscribedSku -All
$report = foreach ($sku in $skus) {
$total = $sku.PrepaidUnits.Enabled
$used = $sku.ConsumedUnits
$free = $total - $used
$percentUsed = if ($total -gt 0) { [math]::Round(($used / $total) * 100, 1) } else { 0 }
[PSCustomObject]@{
SkuPartNumber = $sku.SkuPartNumber
Total = $total
Consumed = $used
Available = $free
PercentUsed = $percentUsed
}
}
$report | Sort-Object PercentUsed | Export-Csv -Path $OutputPath -NoTypeInformation
Write-Host "[SUCCESS] Report exported to: $OutputPath" -ForegroundColor Green
$underused = $report | Where-Object { $_.Total -gt 0 -and $_.PercentUsed -lt 50 }
if ($underused) {
Write-Host "[INFO] SKUs under 50% utilization, worth a second look before renewal:" -ForegroundColor Yellow
$underused | Format-Table SkuPartNumber, Total, Consumed, PercentUsed -AutoSize
}Read it before you run it, and test in a safe tenant first.