Public/New-TCMMonitor.ps1

function New-TCMMonitor {
    <#
    .SYNOPSIS
        Create a configuration monitor that detects drift every 6 hours.
    .DESCRIPTION
        Creates a TCM monitor with a baseline. The monitor runs every 6 hours (fixed)
        and compares the current tenant config against the baseline, reporting drifts.
    .PARAMETER DisplayName
        A friendly name for the monitor.
    .PARAMETER Description
        Optional description.
    .PARAMETER Baseline
        The baseline object (from ConvertTo-TCMBaseline or manually constructed).
    .PARAMETER BaselinePath
        Path to a JSON file containing the baseline.
    .PARAMETER Parameters
        Optional key-value parameters (e.g., TenantId, FQDN) used in the baseline.
    .EXAMPLE
        New-TCMMonitor -DisplayName "Entra Monitor" -Baseline $baseline
    .EXAMPLE
        New-TCMMonitor -DisplayName "Exchange Monitor" -BaselinePath "./baselines/exchange.json"
    #>

    [CmdletBinding(SupportsShouldProcess)]
    param(
        [Parameter(Mandatory)]
        [string]$DisplayName,

        [string]$Description,

        [Parameter(ValueFromPipeline, ParameterSetName = 'Object')]
        [hashtable]$Baseline,

        [Parameter(ParameterSetName = 'File')]
        [string]$BaselinePath,

        [hashtable]$Parameters
    )

    process {
        if ($BaselinePath) {
            if (-not (Test-Path $BaselinePath)) {
                throw "Baseline file not found: $BaselinePath"
            }
            $Baseline = Get-Content $BaselinePath -Raw | ConvertFrom-Json -AsHashtable
        }

        if (-not $Baseline -or (-not $Baseline.resources -and -not $Baseline.Resources)) {
            throw 'A baseline with at least one resource is required. Use ConvertTo-TCMBaseline or provide a JSON file.'
        }

        # Support both camelCase and PascalCase resource keys
        $resources = if ($Baseline.Resources) { $Baseline.Resources } else { $Baseline.resources }
        $resourceCount = @($resources).Count
        Write-Host "Creating monitor '$DisplayName' with $resourceCount resources..." -ForegroundColor Cyan

        # Quota impact: show this monitor's cost + existing monitors
        $dailyCost = $resourceCount * 4
        $existingMonitors = @()
        try { $existingMonitors = @(Get-TCMMonitor) } catch { Write-Debug "Could not retrieve existing monitors: $_" }
        $existingDailyCost = ($existingMonitors | ForEach-Object {
            # Estimate: we don't always know resource count, but count what we can
            if ($_.baseline -and $_.baseline.resources) { $_.baseline.resources.Count * 4 }
        } | Measure-Object -Sum).Sum

        $totalDaily = $existingDailyCost + $dailyCost
        $quotaPercent = [math]::Round(($totalDaily / 800) * 100, 1)
        $color = if ($quotaPercent -gt 80) { 'Red' } elseif ($quotaPercent -gt 50) { 'Yellow' } else { 'Green' }

        Write-Host " This monitor: $dailyCost resources/day" -ForegroundColor DarkGray
        Write-Host " Total after creation: ~$totalDaily / 800 daily quota ($quotaPercent%)" -ForegroundColor $color

        if ($quotaPercent -gt 100) {
            Write-Warning "OVER QUOTA! Total monitored resources ($totalDaily/day) exceeds the 800/day limit. TCM will throttle or fail. Use ConvertTo-TCMBaseline -Profile SecurityCritical to reduce."
        }
        elseif ($quotaPercent -gt 80) {
            Write-Warning "Nearing quota limit ($quotaPercent%). Consider using ConvertTo-TCMBaseline -Profile SecurityCritical."
        }

        $body = @{
            displayName = $DisplayName
            baseline    = $Baseline
        }
        if ($Description) { $body.description = $Description }
        if ($Parameters)  { $body.parameters = $Parameters }

        if (-not $PSCmdlet.ShouldProcess($DisplayName, 'Create TCM monitor')) { return }
        $monitor = Invoke-TCMGraphRequest -Endpoint 'configurationMonitors' -Method POST -Body $body

        if (-not $monitor) {
            return
        }

        $monId = if ($monitor -is [System.Collections.IDictionary]) { $monitor['id'] } else { $monitor.id }
        $monStat = if ($monitor -is [System.Collections.IDictionary]) { $monitor['status'] } else { $monitor.status }

        Write-Host "Monitor created (Id: $monId, Status: $monStat)" -ForegroundColor Green
        Write-Host " Runs every 6 hours at fixed GMT times: 6 AM, 12 PM, 6 PM, 12 AM" -ForegroundColor DarkGray
        Write-Host " Use Get-TCMDrift to check for detected drifts." -ForegroundColor DarkGray

        $monitor
    }
}