Public/Get-LicenseInventory.ps1
|
function Get-LicenseInventory { <# .SYNOPSIS Retrieves the full Microsoft 365 license inventory for the tenant. .DESCRIPTION Queries Microsoft Graph for all subscribed SKUs and returns a comprehensive inventory showing what licenses are purchased, assigned, available, and their estimated monthly cost. Flags over-provisioned and fully utilized SKUs. .EXAMPLE Get-LicenseInventory Returns all subscribed SKUs with utilization data and cost estimates. .EXAMPLE Get-LicenseInventory | Where-Object Finding -eq 'OVER-PROVISIONED' | Format-Table Shows only over-provisioned license SKUs. .OUTPUTS PSCustomObject with properties: SkuPartNumber, FriendlyName, TotalLicenses, AssignedLicenses, AvailableLicenses, UtilizationPercent, MonthlyCost, Finding #> [CmdletBinding()] param() Test-GraphConnection $friendlyNames = Get-LicenseFriendlyName Write-Verbose "Retrieving subscribed SKUs from Microsoft Graph..." try { $skus = Get-MgSubscribedSku -All -ErrorAction Stop } catch { throw "Failed to retrieve subscribed SKUs: $_" } $results = foreach ($sku in $skus) { $skuPartNumber = $sku.SkuPartNumber $total = $sku.PrepaidUnits.Enabled $assigned = $sku.ConsumedUnits $available = $total - $assigned # Avoid divide-by-zero $utilization = if ($total -gt 0) { [math]::Round(($assigned / $total) * 100, 1) } else { 0 } # Look up friendly name and cost $lookup = $friendlyNames[$skuPartNumber] $friendlyName = if ($lookup) { $lookup.FriendlyName } else { $skuPartNumber } $monthlyCostPerLicense = if ($lookup) { $lookup.EstimatedMonthlyCost } else { 0 } $totalMonthlyCost = [math]::Round($monthlyCostPerLicense * $assigned, 2) # Determine finding $finding = 'OK' if ($total -gt 0) { $unassignedPercent = (($total - $assigned) / $total) * 100 if ($unassignedPercent -gt 20) { $finding = 'OVER-PROVISIONED' } elseif ($utilization -ge 95) { $finding = 'FULLY UTILIZED' } } [PSCustomObject]@{ SkuPartNumber = $skuPartNumber FriendlyName = $friendlyName TotalLicenses = $total AssignedLicenses = $assigned AvailableLicenses = $available UtilizationPercent = $utilization MonthlyCost = $totalMonthlyCost Finding = $finding } } return $results | Sort-Object MonthlyCost -Descending } |