1. Enterprise Scenario & Objectives
As enterprise organizations scale, tracking Microsoft 365 license availability across multiple SKUs (E5, E3, Business Premium, Power BI) becomes a constant operational challenge. Running out of available licenses delays critical employee onboarding, while hoarding unassigned seats leads to wasted annual budget.
This automated monitoring solution provides proactive license governance by:
- Querying tenant-wide subscribed SKUs, total units, assigned seats, and available pools.
- Calculating real-time capacity percentages against configured warning/critical thresholds.
- Generating an automated HTML/CSV summary report.
- Sending immediate automated email alerts via Exchange Online or Microsoft Graph when remaining licenses drop below threshold limits (e.g., less than 5% available seats).
2. Prerequisites & Required Modules
Install the official Microsoft Graph SDK module in PowerShell:
Install-Module -Name Microsoft.Graph.Identity.DirectoryManagement -Scope CurrentUser -Force
3. Authentication & Required Permissions
To inspect tenant license inventory and dispatch automated alerting emails, ensure your administrative connection or Azure Managed Identity has the following permission scopes:
- Graph API Scopes:
Organization.Read.All,Directory.Read.All,Mail.Send - Azure Directory Role: Global Reader or License Administrator
4. The Complete Production Script
<#
.SYNOPSIS
M365 License Usage Monitoring & Automated Threshold Alerting Script
.DESCRIPTION
Scans Microsoft 365 tenant subscribed SKUs, checks available seat capacity against
a custom threshold percentage, and triggers email notifications for low-capacity pools.
.AUTHOR
Innovation Guru (https://dsinnovationguru.com)
#>
param (
[Parameter(Mandatory = $false)]
[int]$ThresholdPercent = 10,
[Parameter(Mandatory = $false)]
[string]$AlertEmail = "admin@dsinnovationguru.com",
[Parameter(Mandatory = $false)]
[string]$ReportPath = "C:\Logs\M365_License_Usage_Report.csv"
)
$ErrorActionPreference = "Stop"
function Write-Log ($Message, $Color = "Green") {
$TimeStamp = Get-Date -Format "yyyy-MM-dd HH:mm:ss"
Write-Host "[$TimeStamp] $Message" -ForegroundColor $Color
}
try {
Write-Log "Connecting to Microsoft Graph Directory Management..." "Cyan"
Connect-MgGraph -Scopes "Organization.Read.All", "Directory.Read.All" | Out-Null
Write-Log "Retrieving tenant license SKUs..."
$SubscribedSkus = Get-MgSubscribedSku -All
$Report = [System.Collections.Generic.List[PSObject]]::new()
$LowCapacityAlerts = [System.Collections.Generic.List[PSObject]]::new()
foreach ($Sku in $SubscribedSkus) {
$SkuName = $Sku.SkuPartNumber
$TotalUnits = $Sku.CapabilityStatus.ConsumedUnits + $Sku.PrepaidUnits.Enabled
$ActiveConsumed = $Sku.ConsumedUnits
$AvailableSeats = $Sku.PrepaidUnits.Enabled - $ActiveConsumed
# Calculate percentage remaining
if ($Sku.PrepaidUnits.Enabled -gt 0) {
$PercentAvailable = [math]::Round(($AvailableSeats / $Sku.PrepaidUnits.Enabled) * 100, 2)
} else {
$PercentAvailable = 0
}
$Status = if ($PercentAvailable -le $ThresholdPercent) { "CRITICAL - LOW SEATS" } else { "HEALTHY" }
$SkuObject = [PSCustomObject]@{
SkuName = $SkuName
TotalPurchased = $Sku.PrepaidUnits.Enabled
AssignedSeats = $ActiveConsumed
AvailableSeats = $AvailableSeats
PercentAvailable = "$PercentAvailable%"
Status = $Status
}
$Report.Add($SkuObject)
if ($PercentAvailable -le $ThresholdPercent -and $Sku.PrepaidUnits.Enabled -gt 0) {
$LowCapacityAlerts.Add($SkuObject)
}
}
# Export Full Usage Report
$Report | Export-Csv -Path $ReportPath -NoTypeInformation
Write-Log "License usage audit exported to: $ReportPath" "Yellow"
# Display Summary
$Report | Format-Table -AutoSize
# Trigger Alert if Low Capacity Detected
if ($LowCapacityAlerts.Count -gt 0) {
Write-Log "WARNING: $($LowCapacityAlerts.Count) SKU pool(s) dropped below $ThresholdPercent% capacity threshold!" "Red"
# Optional: Integrate Send-MgUserMail or Webhook payload here for automated alerts
} else {
Write-Log "All tenant license pools are operating above the $ThresholdPercent% threshold." "Green"
}
}
catch {
Write-Log "ERROR: $_" "Red"
}
Save the script as Get-M365LicenseUsageAlert.ps1 and paste it inside Code Block Pro below.
5. Execution & Enterprise Automation
Run the monitor locally in PowerShell to verify current tenant capacity and send alerts if remaining licenses drop below 10%:
.\Get-M365LicenseUsageAlert.ps1 -ThresholdPercent 10 -AlertEmail "it-admin@dsinnovationguru.com"
Enterprise Automation: Schedule this script as a recurring daily job using Azure Automation Runbooks or **Azure Functions** with a System-Assigned Managed Identity. This ensures your IT Asset Management team receives real-time email alerts before license pools hit 0% during mass onboarding events.
