Checks/Licensing/ARG.LIC.006.ps1

Register-ArgusCheck @{
    Id          = 'ARG.LIC.006'
    Title       = 'Unused licences per SKU'
    Area        = 'Licensing'
    Category    = 'Cost'
    Severity    = 'Medium'
    Description = 'Compares purchased seats (`prepaidUnits.enabled`) with assigned seats (`consumedUnits`) for every active, user-assignable SKU (`capabilityStatus` = Enabled, `appliesTo` = User). A SKU fails when more than **{UnusedPercent}%** or more than **{UnusedSeats}** seats are unused. Free, viral and developer SKUs (the IgnoredSkus list), SKUs with **{FreeSeatThreshold}** or more seats (free offers are provisioned with very large quantities) and trial SKUs (`isTrial` in `/directory/subscriptions`) are ignored.'
    Rationale   = 'Unused seats are a recurring cost with no business value. Reviewing them before each renewal is the simplest licence saving.'
    Remediation = @{
        Steps      = "1. Confirm the unused seats are not reserved for planned hires or a migration.`n2. Reassign the seats, or reduce the subscription quantity (for annual commitments, at the next renewal).`n3. Review the SKUs regularly, for example monthly."
        PortalUrl  = 'https://admin.microsoft.com/Adminportal/Home#/licenses'
    }
    References  = @(
        @{ Title = 'Buy or remove licenses for a Microsoft business subscription'; Url = 'https://learn.microsoft.com/en-us/microsoft-365/commerce/licenses/buy-licenses' }
        @{ Title = 'Product names and service plan identifiers for licensing'; Url = 'https://learn.microsoft.com/en-us/entra/identity/users/licensing-service-plan-reference' }
    )
    Requires    = @{
        Services    = @('Graph')
        GraphScopes = @('LicenseAssignment.Read.All')
        DataSets    = @('SubscribedSkus', 'Subscriptions')
    }
    Parameters  = @{
        UnusedPercent     = 10
        UnusedSeats       = 5
        FreeSeatThreshold = 10000
        IgnoredSkus       = @($script:ArgusFreeSkus)
    }
    Tags        = @('Licensing', 'Cost')
    Test        = {
        param($Context)
        $maxPercent = [double]$Context.Parameters.UnusedPercent
        $maxSeats = [int]$Context.Parameters.UnusedSeats
        $skus = @($Context.Data['SubscribedSkus'])
        $categories = Get-ArgusSkuCategory -SubscribedSku $skus -Subscription @($Context.Data['Subscriptions']) `
            -IgnoredSku ([string[]]@($Context.Parameters.IgnoredSkus)) -FreeSeatThreshold ([int]$Context.Parameters.FreeSeatThreshold)

        $evaluated = @($skus | Where-Object {
                (Get-ArgusProperty $_ 'capabilityStatus' '') -eq 'Enabled' -and
                (Get-ArgusProperty $_ 'appliesTo' '') -eq 'User' -and
                [int](Get-ArgusProperty $_ 'prepaidUnits.enabled' 0) -gt 0 -and
                $categories[([string](Get-ArgusProperty $_ 'skuId' '')).ToLowerInvariant()] -eq 'Paid'
            })

        $findings = @($evaluated | ForEach-Object {
                $purchased = [int](Get-ArgusProperty $_ 'prepaidUnits.enabled' 0)
                $assigned = [int](Get-ArgusProperty $_ 'consumedUnits' 0)
                $unused = [math]::Max(0, $purchased - $assigned)
                $percent = [math]::Round(100.0 * $unused / $purchased, 1)
                if ($unused -gt 0 -and ($percent -gt $maxPercent -or $unused -gt $maxSeats)) {
                    [pscustomobject]@{
                        Sku           = @(Get-ArgusSkuName -SkuId @(Get-ArgusProperty $_ 'skuId') -SubscribedSku $skus)[0]
                        SkuPartNumber = Get-ArgusProperty $_ 'skuPartNumber' ''
                        Purchased     = $purchased
                        Assigned      = $assigned
                        Unused        = $unused
                        UnusedPercent = $percent
                    }
                }
            } | Sort-Object Unused -Descending)

        $status = if ($findings.Count -gt 0) { 'Failed' } else { 'Passed' }
        $unusedTotal = 0
        foreach ($finding in $findings) { $unusedTotal += $finding.Unused }
        $summary = if ($findings.Count -gt 0) { "{AffectedCount} of {EvaluatedCount} paid SKUs have more than {UnusedPercent}% or more than {UnusedSeats} seats unused ($unusedTotal unused seats in total)." }
        else { 'All {EvaluatedCount} paid SKUs are within {UnusedPercent}% / {UnusedSeats} unused seats.' }
        New-ArgusResult -Status $status -Findings $findings -EvaluatedCount $evaluated.Count -Summary $summary
    }
}