Public/Invoke-LicenseOptimization.ps1

function Invoke-LicenseOptimization {
    <#
    .SYNOPSIS
        Orchestrates a full Microsoft 365 license optimization analysis.
    .DESCRIPTION
        Runs all license analysis functions (inventory, underutilization, inactive users,
        savings report) and generates an HTML dashboard. Provides a comprehensive view of
        license waste and savings opportunities.
    .PARAMETER OutputPath
        Directory where the HTML report will be saved. Defaults to current directory.
    .PARAMETER DaysInactive
        Number of days without sign-in to flag as inactive. Default: 90.
    .PARAMETER IncludeGuests
        Include guest (external) users in the inactive user analysis.
    .EXAMPLE
        Invoke-LicenseOptimization -OutputPath "C:\Reports" -DaysInactive 60
        Runs full analysis and saves the HTML dashboard to C:\Reports.
    .EXAMPLE
        Invoke-LicenseOptimization -IncludeGuests
        Runs analysis including guest users and saves the report to the current directory.
    .OUTPUTS
        System.IO.FileInfo - the generated HTML report file
    #>

    [CmdletBinding()]
    param(
        [Parameter(Mandatory = $false)]
        [string]$OutputPath = (Get-Location).Path,

        [Parameter(Mandatory = $false)]
        [ValidateRange(1, 365)]
        [int]$DaysInactive = 90,

        [Parameter(Mandatory = $false)]
        [switch]$IncludeGuests
    )

    $stopwatch = [System.Diagnostics.Stopwatch]::StartNew()

    Write-Host ""
    Write-Host "M365 License Optimizer" -ForegroundColor DarkYellow
    Write-Host "======================" -ForegroundColor DarkYellow
    Write-Host ""

    # Step 1: Verify Graph connection
    Write-Host "[1/5] Verifying Microsoft Graph connection..." -ForegroundColor Cyan
    try {
        Test-GraphConnection
        Write-Host " Graph connection verified." -ForegroundColor Green
    }
    catch {
        Write-Error "Graph connection failed: $_"
        Write-Host ""
        Write-Host "To connect, run:" -ForegroundColor Yellow
        Write-Host " Connect-MgGraph -Scopes 'User.Read.All','Directory.Read.All','Reports.Read.All'" -ForegroundColor White
        return
    }

    # Step 2: License Inventory
    Write-Host "[2/5] Collecting license inventory..." -ForegroundColor Cyan
    try {
        $inventory = Get-LicenseInventory
        Write-Host " Found $($inventory.Count) SKU(s)." -ForegroundColor Green
    }
    catch {
        Write-Error "Failed to collect license inventory: $_"
        return
    }

    # Step 3: Underutilized Licenses
    Write-Host "[3/5] Analyzing underutilized licenses..." -ForegroundColor Cyan
    try {
        $underutilized = Get-UnderutilizedLicenses -DaysInactive $DaysInactive
        $underCount = if ($underutilized) { @($underutilized).Count } else { 0 }
        Write-Host " Found $underCount underutilized license(s)." -ForegroundColor Green
    }
    catch {
        Write-Warning "Underutilized license analysis failed: $_"
        $underutilized = @()
    }

    # Step 4: Inactive Licensed Users
    Write-Host "[4/5] Identifying inactive licensed users..." -ForegroundColor Cyan
    try {
        $inactiveParams = @{ DaysInactive = $DaysInactive }
        if ($IncludeGuests) { $inactiveParams['IncludeGuests'] = $true }
        $inactiveUsers = Get-InactiveLicensedUsers @inactiveParams
        $inactiveCount = if ($inactiveUsers) { @($inactiveUsers).Count } else { 0 }
        Write-Host " Found $inactiveCount inactive licensed user(s)." -ForegroundColor Green
    }
    catch {
        Write-Warning "Inactive user analysis failed: $_"
        $inactiveUsers = @()
    }

    # Step 5: Savings Report
    Write-Host "[5/5] Calculating savings..." -ForegroundColor Cyan
    try {
        $savingsReport = Get-LicenseSavingsReport -DaysInactive $DaysInactive
    }
    catch {
        Write-Warning "Savings report generation failed: $_"
        $savingsReport = @()
    }

    # Generate HTML dashboard
    $timestamp  = Get-Date -Format 'yyyyMMdd-HHmmss'
    $reportFile = Join-Path -Path $OutputPath -ChildPath "M365-LicenseOptimization-$timestamp.html"

    Write-Host "Generating HTML dashboard..." -ForegroundColor Cyan
    try {
        $htmlFile = New-HtmlDashboard `
            -Title "M365 License Optimization Report" `
            -LicenseInventory $inventory `
            -UnderutilizedLicenses $underutilized `
            -InactiveUsers $inactiveUsers `
            -SavingsReport $savingsReport `
            -OutputPath $reportFile

        Write-Host ""
        Write-Host "Report saved to: $($htmlFile.FullName)" -ForegroundColor Green
    }
    catch {
        Write-Warning "HTML dashboard generation failed: $_"
    }

    $stopwatch.Stop()
    Write-Host "Completed in $([math]::Round($stopwatch.Elapsed.TotalSeconds, 1)) seconds." -ForegroundColor DarkGray
    Write-Host ""

    return $htmlFile
}