<#
.SYNOPSIS
    SCOM Prometheus Metrics Exporter
.DESCRIPTION
    Prometheus exporter for System Center Operations Manager - management server
    health, agent status, open alerts by severity, resolution state counts,
    management pack and monitor counts, override counts, pending actions,
    database sizes, stale agents, and alert age statistics. Exports metrics as
    Prometheus-compatible text format.
.PARAMETER Mode
    Output mode: 'stdout' (default), 'textfile', or 'http'
.PARAMETER Port
    HTTP port for http mode (default: 9650)
.PARAMETER TextfileDir
    Directory for textfile collector output (default: C:\ProgramData\node_exporter)
.PARAMETER InstallScheduledTask
    Switch to create a scheduled task for auto-start on system boot
.PARAMETER TaskIntervalMinutes
    Interval in minutes for the scheduled task (default: 2)
.NOTES
    Author:  Phil Connor
    Contact: contact@mylinux.work
    Website: https://mylinux.work
    License: MIT
    Version: 1.0

    Metrics Exported:
      Core Status:
        - scom_up
        - scom_exporter_info{version}

      Management Servers:
        - scom_management_server_health{server,health_state}

      Agents:
        - scom_agent_total
        - scom_agent_healthy
        - scom_agent_warning
        - scom_agent_critical
        - scom_agent_unmonitored
        - scom_agent_pending_actions

      Alerts:
        - scom_alerts_open_total
        - scom_alerts_by_severity{severity}
        - scom_alerts_by_resolution_state{resolution_state}
        - scom_alert_age_oldest_hours
        - scom_alert_age_average_hours

      Stale Agents:
        - scom_agent_stale_total

      Management Packs:
        - scom_management_pack_total

      Monitors:
        - scom_monitor_total
        - scom_monitor_healthy
        - scom_monitor_error
        - scom_monitor_warning

      Management Group:
        - scom_management_group_total

      Overrides:
        - scom_override_total

      Databases:
        - scom_database_size_bytes{database}

      Exporter:
        - scom_exporter_duration_seconds
        - scom_exporter_last_run_timestamp
#>

param(
    [ValidateSet('stdout', 'textfile', 'http')]
    [string]$Mode = 'stdout',

    [int]$Port = 9650,

    [string]$TextfileDir = 'C:\ProgramData\node_exporter',

    [switch]$InstallScheduledTask,

    [int]$TaskIntervalMinutes = 2
)

# Create a scheduled task to run this script every $TaskIntervalMinutes minutes
if ($InstallScheduledTask) {
    $taskName = "ScomMetricsExporter"
    $existingTask = Get-ScheduledTask -TaskName $taskName -ErrorAction SilentlyContinue

    if (-not $existingTask) {
        $taskAction = New-ScheduledTaskAction -Execute "powershell.exe" -Argument "-NoProfile -ExecutionPolicy Bypass -File `"$($MyInvocation.MyCommand.Path)`" -Mode textfile"

        if (-not $TaskIntervalMinutes -or $TaskIntervalMinutes -le 0) {
            throw "TaskIntervalMinutes must be a positive integer"
        }

        $taskTrigger = New-ScheduledTaskTrigger -Once -At (Get-Date).AddMinutes(1) -RepetitionInterval (New-TimeSpan -Minutes $TaskIntervalMinutes) -RepetitionDuration (New-TimeSpan -Days 365)
        $taskPrincipal = New-ScheduledTaskPrincipal -UserId "SYSTEM" -LogonType ServiceAccount -RunLevel Highest

        try {
            Write-Host "Creating scheduled task: $taskName"
            Register-ScheduledTask -TaskName $taskName -Action $taskAction -Trigger $taskTrigger -Principal $taskPrincipal -Description "Exports SCOM metrics for Prometheus every $TaskIntervalMinutes minutes"

            $createdTask = Get-ScheduledTask -TaskName $taskName -ErrorAction SilentlyContinue
            if (-not $createdTask) {
                throw "Failed to verify scheduled task creation"
            }
            Write-Host "Successfully created scheduled task: $taskName" -ForegroundColor Green
        } catch {
            Write-Error "Failed to create scheduled task: $($_.Exception.Message)"
            throw
        }
    } else {
        Write-Host "Scheduled task '$taskName' already exists, skipping creation"
    }
}

$ErrorActionPreference = 'SilentlyContinue'

# ============================================================================
# HELPER FUNCTIONS
# ============================================================================

function Get-UnixTimestamp {
    [int][double]::Parse((Get-Date -UFormat '%s'))
}

function Format-MetricValue {
    param([double]$Value, [int]$Decimals = 2)
    [math]::Round($Value, $Decimals)
}

function Test-ScomModule {
    try {
        Import-Module OperationsManager -ErrorAction Stop
        return $true
    } catch {
        return $false
    }
}

# ============================================================================
# SCOM METRICS
# ============================================================================

function Get-ScomMetrics {
    $sb = [System.Text.StringBuilder]::new()

    # --- Management Server Health ---
    [void]$sb.AppendLine('# HELP scom_management_server_health Management server health (1=healthy, 0=unhealthy)')
    [void]$sb.AppendLine('# TYPE scom_management_server_health gauge')
    try {
        $mgmtServers = Get-SCOMManagementServer
        if ($mgmtServers) {
            foreach ($ms in $mgmtServers) {
                $serverName = $ms.Name -replace '["]', ''
                $healthVal = switch ($ms.HealthState) {
                    'Success' { 1 }
                    default   { 0 }
                }
                $stateLabel = "$($ms.HealthState)"
                [void]$sb.AppendLine("scom_management_server_health{server=`"$serverName`",health_state=`"$stateLabel`"} $healthVal")
            }
        }
    } catch { }
    [void]$sb.AppendLine('')

    # --- Agent Counts ---
    [void]$sb.AppendLine('# HELP scom_agent_total Total number of SCOM agents')
    [void]$sb.AppendLine('# TYPE scom_agent_total gauge')
    [void]$sb.AppendLine('')
    [void]$sb.AppendLine('# HELP scom_agent_healthy Number of healthy agents')
    [void]$sb.AppendLine('# TYPE scom_agent_healthy gauge')
    [void]$sb.AppendLine('')
    [void]$sb.AppendLine('# HELP scom_agent_warning Number of agents in warning state')
    [void]$sb.AppendLine('# TYPE scom_agent_warning gauge')
    [void]$sb.AppendLine('')
    [void]$sb.AppendLine('# HELP scom_agent_critical Number of agents in critical state')
    [void]$sb.AppendLine('# TYPE scom_agent_critical gauge')
    [void]$sb.AppendLine('')
    [void]$sb.AppendLine('# HELP scom_agent_unmonitored Number of unmonitored agents')
    [void]$sb.AppendLine('# TYPE scom_agent_unmonitored gauge')
    try {
        $agents = Get-SCOMAgent
        $agentTotal = if ($agents) { @($agents).Count } else { 0 }
        $agentHealthy = if ($agents) { @($agents | Where-Object { $_.HealthState -eq 'Success' }).Count } else { 0 }
        $agentWarning = if ($agents) { @($agents | Where-Object { $_.HealthState -eq 'Warning' }).Count } else { 0 }
        $agentCritical = if ($agents) { @($agents | Where-Object { $_.HealthState -eq 'Error' }).Count } else { 0 }
        $agentUnmonitored = if ($agents) { @($agents | Where-Object { $_.HealthState -eq 'Uninitialized' -or $_.HealthState -eq 'NotMonitored' }).Count } else { 0 }
        [void]$sb.AppendLine("scom_agent_total $agentTotal")
        [void]$sb.AppendLine("scom_agent_healthy $agentHealthy")
        [void]$sb.AppendLine("scom_agent_warning $agentWarning")
        [void]$sb.AppendLine("scom_agent_critical $agentCritical")
        [void]$sb.AppendLine("scom_agent_unmonitored $agentUnmonitored")
    } catch {
        [void]$sb.AppendLine("scom_agent_total 0")
        [void]$sb.AppendLine("scom_agent_healthy 0")
        [void]$sb.AppendLine("scom_agent_warning 0")
        [void]$sb.AppendLine("scom_agent_critical 0")
        [void]$sb.AppendLine("scom_agent_unmonitored 0")
    }
    [void]$sb.AppendLine('')

    # --- Stale / Grayed-Out Agents ---
    [void]$sb.AppendLine('# HELP scom_agent_stale_total Number of stale or grayed-out agents')
    [void]$sb.AppendLine('# TYPE scom_agent_stale_total gauge')
    try {
        $staleAgents = @(Get-SCOMAgent | Where-Object { $_.HealthState -eq 'Uninitialized' }).Count
        [void]$sb.AppendLine("scom_agent_stale_total $staleAgents")
    } catch {
        [void]$sb.AppendLine("scom_agent_stale_total 0")
    }
    [void]$sb.AppendLine('')

    # --- Agent Pending Actions ---
    [void]$sb.AppendLine('# HELP scom_agent_pending_actions Number of agents with pending actions')
    [void]$sb.AppendLine('# TYPE scom_agent_pending_actions gauge')
    try {
        $pendingAgents = @(Get-SCOMPendingManagement).Count
        [void]$sb.AppendLine("scom_agent_pending_actions $pendingAgents")
    } catch {
        [void]$sb.AppendLine("scom_agent_pending_actions 0")
    }
    [void]$sb.AppendLine('')

    # --- Open Alerts Total ---
    [void]$sb.AppendLine('# HELP scom_alerts_open_total Total number of open alerts')
    [void]$sb.AppendLine('# TYPE scom_alerts_open_total gauge')
    try {
        $alerts = Get-SCOMAlert -ResolutionState 0
        $alertCount = if ($alerts) { @($alerts).Count } else { 0 }
        [void]$sb.AppendLine("scom_alerts_open_total $alertCount")
    } catch {
        [void]$sb.AppendLine("scom_alerts_open_total 0")
    }
    [void]$sb.AppendLine('')

    # --- Alerts by Severity ---
    [void]$sb.AppendLine('# HELP scom_alerts_by_severity Open alerts grouped by severity')
    [void]$sb.AppendLine('# TYPE scom_alerts_by_severity gauge')
    try {
        $allAlerts = Get-SCOMAlert -ResolutionState 0
        if ($allAlerts) {
            $critAlerts = @($allAlerts | Where-Object { $_.Severity -eq 'Error' }).Count
            $warnAlerts = @($allAlerts | Where-Object { $_.Severity -eq 'Warning' }).Count
            $infoAlerts = @($allAlerts | Where-Object { $_.Severity -eq 'Information' }).Count
            [void]$sb.AppendLine("scom_alerts_by_severity{severity=`"critical`"} $critAlerts")
            [void]$sb.AppendLine("scom_alerts_by_severity{severity=`"warning`"} $warnAlerts")
            [void]$sb.AppendLine("scom_alerts_by_severity{severity=`"information`"} $infoAlerts")
        } else {
            [void]$sb.AppendLine("scom_alerts_by_severity{severity=`"critical`"} 0")
            [void]$sb.AppendLine("scom_alerts_by_severity{severity=`"warning`"} 0")
            [void]$sb.AppendLine("scom_alerts_by_severity{severity=`"information`"} 0")
        }
    } catch {
        [void]$sb.AppendLine("scom_alerts_by_severity{severity=`"critical`"} 0")
        [void]$sb.AppendLine("scom_alerts_by_severity{severity=`"warning`"} 0")
        [void]$sb.AppendLine("scom_alerts_by_severity{severity=`"information`"} 0")
    }
    [void]$sb.AppendLine('')

    # --- Alerts by Resolution State ---
    [void]$sb.AppendLine('# HELP scom_alerts_by_resolution_state Alert count grouped by resolution state')
    [void]$sb.AppendLine('# TYPE scom_alerts_by_resolution_state gauge')
    try {
        $allResAlerts = Get-SCOMAlert
        if ($allResAlerts) {
            $grouped = $allResAlerts | Group-Object ResolutionState
            foreach ($group in $grouped) {
                $state = $group.Name
                [void]$sb.AppendLine("scom_alerts_by_resolution_state{resolution_state=`"$state`"} $($group.Count)")
            }
        }
    } catch { }
    [void]$sb.AppendLine('')

    # --- Alert Age Stats ---
    [void]$sb.AppendLine('# HELP scom_alert_age_oldest_hours Age of the oldest open alert in hours')
    [void]$sb.AppendLine('# TYPE scom_alert_age_oldest_hours gauge')
    [void]$sb.AppendLine('')
    [void]$sb.AppendLine('# HELP scom_alert_age_average_hours Average age of open alerts in hours')
    [void]$sb.AppendLine('# TYPE scom_alert_age_average_hours gauge')
    try {
        $openAlerts = Get-SCOMAlert -ResolutionState 0
        if ($openAlerts -and @($openAlerts).Count -gt 0) {
            $now = Get-Date
            $ages = @($openAlerts | ForEach-Object { ($now - $_.TimeRaised).TotalHours })
            $oldest = Format-MetricValue ($ages | Measure-Object -Maximum).Maximum
            $average = Format-MetricValue ($ages | Measure-Object -Average).Average
            [void]$sb.AppendLine("scom_alert_age_oldest_hours $oldest")
            [void]$sb.AppendLine("scom_alert_age_average_hours $average")
        } else {
            [void]$sb.AppendLine("scom_alert_age_oldest_hours 0")
            [void]$sb.AppendLine("scom_alert_age_average_hours 0")
        }
    } catch {
        [void]$sb.AppendLine("scom_alert_age_oldest_hours 0")
        [void]$sb.AppendLine("scom_alert_age_average_hours 0")
    }
    [void]$sb.AppendLine('')

    # --- Management Pack Count ---
    [void]$sb.AppendLine('# HELP scom_management_pack_total Total number of management packs')
    [void]$sb.AppendLine('# TYPE scom_management_pack_total gauge')
    try {
        $mpCount = @(Get-SCOMManagementPack).Count
        [void]$sb.AppendLine("scom_management_pack_total $mpCount")
    } catch {
        [void]$sb.AppendLine("scom_management_pack_total 0")
    }
    [void]$sb.AppendLine('')

    # --- Monitor Counts ---
    [void]$sb.AppendLine('# HELP scom_monitor_total Total number of monitors')
    [void]$sb.AppendLine('# TYPE scom_monitor_total gauge')
    [void]$sb.AppendLine('')
    [void]$sb.AppendLine('# HELP scom_monitor_healthy Number of monitors in healthy state')
    [void]$sb.AppendLine('# TYPE scom_monitor_healthy gauge')
    [void]$sb.AppendLine('')
    [void]$sb.AppendLine('# HELP scom_monitor_error Number of monitors in error state')
    [void]$sb.AppendLine('# TYPE scom_monitor_error gauge')
    [void]$sb.AppendLine('')
    [void]$sb.AppendLine('# HELP scom_monitor_warning Number of monitors in warning state')
    [void]$sb.AppendLine('# TYPE scom_monitor_warning gauge')
    try {
        $monitors = Get-SCOMMonitor
        $monTotal = if ($monitors) { @($monitors).Count } else { 0 }
        [void]$sb.AppendLine("scom_monitor_total $monTotal")

        $monitoringObjects = Get-SCOMClassInstance | Where-Object { $_.HealthState }
        if ($monitoringObjects) {
            $monHealthy = @($monitoringObjects | Where-Object { $_.HealthState -eq 'Success' }).Count
            $monError = @($monitoringObjects | Where-Object { $_.HealthState -eq 'Error' }).Count
            $monWarning = @($monitoringObjects | Where-Object { $_.HealthState -eq 'Warning' }).Count
            [void]$sb.AppendLine("scom_monitor_healthy $monHealthy")
            [void]$sb.AppendLine("scom_monitor_error $monError")
            [void]$sb.AppendLine("scom_monitor_warning $monWarning")
        } else {
            [void]$sb.AppendLine("scom_monitor_healthy 0")
            [void]$sb.AppendLine("scom_monitor_error 0")
            [void]$sb.AppendLine("scom_monitor_warning 0")
        }
    } catch {
        [void]$sb.AppendLine("scom_monitor_total 0")
        [void]$sb.AppendLine("scom_monitor_healthy 0")
        [void]$sb.AppendLine("scom_monitor_error 0")
        [void]$sb.AppendLine("scom_monitor_warning 0")
    }
    [void]$sb.AppendLine('')

    # --- Management Group Count ---
    [void]$sb.AppendLine('# HELP scom_management_group_total Number of management groups')
    [void]$sb.AppendLine('# TYPE scom_management_group_total gauge')
    try {
        $mgCount = @(Get-SCOMManagementGroup).Count
        [void]$sb.AppendLine("scom_management_group_total $mgCount")
    } catch {
        [void]$sb.AppendLine("scom_management_group_total 0")
    }
    [void]$sb.AppendLine('')

    # --- Override Count ---
    [void]$sb.AppendLine('# HELP scom_override_total Total number of overrides')
    [void]$sb.AppendLine('# TYPE scom_override_total gauge')
    try {
        $overrides = Get-SCOMOverride
        $overrideCount = if ($overrides) { @($overrides).Count } else { 0 }
        [void]$sb.AppendLine("scom_override_total $overrideCount")
    } catch {
        [void]$sb.AppendLine("scom_override_total 0")
    }
    [void]$sb.AppendLine('')

    # --- Database Sizes ---
    [void]$sb.AppendLine('# HELP scom_database_size_bytes SCOM database size in bytes')
    [void]$sb.AppendLine('# TYPE scom_database_size_bytes gauge')
    try {
        $dbQuery = @"
SELECT
    DB_NAME(database_id) AS db_name,
    SUM(size) * 8192 AS size_bytes
FROM sys.master_files
WHERE DB_NAME(database_id) IN ('OperationsManager', 'OperationsManagerDW')
GROUP BY database_id
"@
        $sqlModule = Get-Module -Name SqlServer -ListAvailable -ErrorAction SilentlyContinue
        $scomMgmt = Get-SCOMManagementGroup
        if ($sqlModule) {
            Import-Module SqlServer -ErrorAction SilentlyContinue
            $dbSettings = $scomMgmt | ForEach-Object {
                try { $_.GetSettings() } catch { $null }
            }
            $sqlInstance = if ($dbSettings) { $dbSettings.DefaultDataWarehouseServer } else { 'localhost' }
            $dbSizes = Invoke-Sqlcmd -ServerInstance $sqlInstance -Database 'master' -Query $dbQuery -ErrorAction Stop -QueryTimeout 10
            if ($dbSizes) {
                foreach ($row in $dbSizes) {
                    $dbName = $row.db_name -replace '["]', ''
                    [void]$sb.AppendLine("scom_database_size_bytes{database=`"$dbName`"} $($row.size_bytes)")
                }
            }
        }
    } catch { }
    [void]$sb.AppendLine('')

    $sb.ToString()
}

# ============================================================================
# COLLECT ALL METRICS
# ============================================================================

function Get-AllMetrics {
    $scriptStart = Get-Date
    $sb = [System.Text.StringBuilder]::new()

    # Exporter up - test OperationsManager module availability
    [void]$sb.AppendLine('# HELP scom_up SCOM reachability (1=up, 0=down)')
    [void]$sb.AppendLine('# TYPE scom_up gauge')
    try {
        $moduleAvailable = Test-ScomModule
        if (-not $moduleAvailable) {
            [void]$sb.AppendLine("scom_up 0")
            $scriptEnd = Get-Date
            $duration = Format-MetricValue ($scriptEnd - $scriptStart).TotalSeconds
            [void]$sb.AppendLine('')
            [void]$sb.AppendLine('# HELP scom_exporter_duration_seconds Time to generate all metrics')
            [void]$sb.AppendLine('# TYPE scom_exporter_duration_seconds gauge')
            [void]$sb.AppendLine("scom_exporter_duration_seconds $duration")
            [void]$sb.AppendLine('')
            [void]$sb.AppendLine('# HELP scom_exporter_last_run_timestamp Unix timestamp of last run')
            [void]$sb.AppendLine('# TYPE scom_exporter_last_run_timestamp gauge')
            [void]$sb.AppendLine("scom_exporter_last_run_timestamp $(Get-UnixTimestamp)")
            return $sb.ToString()
        }

        $testMs = Get-SCOMManagementServer -ErrorAction Stop
        $upVal = if ($testMs) { 1 } else { 0 }
        [void]$sb.AppendLine("scom_up $upVal")
    } catch {
        [void]$sb.AppendLine("scom_up 0")
        $scriptEnd = Get-Date
        $duration = Format-MetricValue ($scriptEnd - $scriptStart).TotalSeconds
        [void]$sb.AppendLine('')
        [void]$sb.AppendLine('# HELP scom_exporter_duration_seconds Time to generate all metrics')
        [void]$sb.AppendLine('# TYPE scom_exporter_duration_seconds gauge')
        [void]$sb.AppendLine("scom_exporter_duration_seconds $duration")
        [void]$sb.AppendLine('')
        [void]$sb.AppendLine('# HELP scom_exporter_last_run_timestamp Unix timestamp of last run')
        [void]$sb.AppendLine('# TYPE scom_exporter_last_run_timestamp gauge')
        [void]$sb.AppendLine("scom_exporter_last_run_timestamp $(Get-UnixTimestamp)")
        return $sb.ToString()
    }
    [void]$sb.AppendLine('')

    # Exporter info
    [void]$sb.AppendLine('# HELP scom_exporter_info Exporter version information')
    [void]$sb.AppendLine('# TYPE scom_exporter_info gauge')
    [void]$sb.AppendLine('scom_exporter_info{version="1.0"} 1')
    [void]$sb.AppendLine('')

    # Collect SCOM metrics
    [void]$sb.Append((Get-ScomMetrics))

    # Exporter runtime
    $scriptEnd = Get-Date
    $duration = Format-MetricValue ($scriptEnd - $scriptStart).TotalSeconds
    $timestamp = Get-UnixTimestamp

    [void]$sb.AppendLine('# HELP scom_exporter_duration_seconds Time to generate all metrics')
    [void]$sb.AppendLine('# TYPE scom_exporter_duration_seconds gauge')
    [void]$sb.AppendLine("scom_exporter_duration_seconds $duration")
    [void]$sb.AppendLine('')
    [void]$sb.AppendLine('# HELP scom_exporter_last_run_timestamp Unix timestamp of last successful run')
    [void]$sb.AppendLine('# TYPE scom_exporter_last_run_timestamp gauge')
    [void]$sb.AppendLine("scom_exporter_last_run_timestamp $timestamp")
    [void]$sb.AppendLine('')

    $sb.ToString()
}

# ============================================================================
# HTTP SERVER MODE
# ============================================================================

function Start-HttpServer {
    param([int]$ListenPort)

    $prefix = "http://+:$ListenPort/"
    $listener = [System.Net.HttpListener]::new()
    $listener.Prefixes.Add($prefix)

    try {
        $listener.Start()
        Write-Host "Starting SCOM metrics exporter on port $ListenPort..." -ForegroundColor Green
        Write-Host "Metrics available at http://localhost:$ListenPort/metrics"

        while ($listener.IsListening) {
            $context  = $listener.GetContext()
            $request  = $context.Request
            $response = $context.Response

            if ($request.Url.AbsolutePath -eq '/metrics') {
                $metrics = Get-AllMetrics
                $buffer  = [System.Text.Encoding]::UTF8.GetBytes($metrics)
                $response.ContentType = 'text/plain; version=0.0.4; charset=utf-8'
            }
            else {
                $html = @"
<!DOCTYPE html>
<html>
<head><title>SCOM Metrics Exporter v1.0</title></head>
<body>
<h1>SCOM Metrics Exporter v1.0</h1>
<p><a href="/metrics">Metrics</a></p>
<h2>Metrics</h2>
<ul>
<li>Management server health status</li>
<li>Agent totals and health breakdown</li>
<li>Open alerts by severity and resolution state</li>
<li>Alert age statistics</li>
<li>Management pack and monitor counts</li>
<li>Override count</li>
<li>Pending agent actions</li>
<li>Stale/grayed-out agent count</li>
<li>Database sizes (OperationsManager, OperationsManagerDW)</li>
</ul>
</body>
</html>
"@
                $buffer = [System.Text.Encoding]::UTF8.GetBytes($html)
                $response.ContentType = 'text/html; charset=utf-8'
            }

            $response.ContentLength64 = $buffer.Length
            $response.OutputStream.Write($buffer, 0, $buffer.Length)
            $response.OutputStream.Close()
        }
    }
    catch {
        Write-Error "HTTP server error: $_"
        Write-Error "If access denied, run: netsh http add urlacl url=http://+:$ListenPort/ user=Everyone"
    }
    finally {
        if ($listener.IsListening) {
            $listener.Stop()
        }
    }
}

# ============================================================================
# MAIN EXECUTION
# ============================================================================

switch ($Mode) {
    'http' {
        Start-HttpServer -ListenPort $Port
    }
    'textfile' {
        $OutputFile = Join-Path $TextfileDir 'scom_metrics.prom'

        $outputDir = Split-Path $OutputFile -Parent
        if (-not (Test-Path $outputDir)) {
            New-Item -Path $outputDir -ItemType Directory -Force | Out-Null
        }

        $tempFile = Join-Path $outputDir ".scom_metrics.$PID.tmp"

        try {
            $metrics = Get-AllMetrics
            $metrics | Out-File -FilePath $tempFile -Encoding utf8 -NoNewline

            $lineCount = ($metrics -split "`n").Count
            if ($lineCount -lt 10) {
                Remove-Item -Path $tempFile -Force -ErrorAction SilentlyContinue
                Write-Error "Metrics file too small ($lineCount lines), keeping previous"
                exit 1
            }

            Move-Item -Path $tempFile -Destination $OutputFile -Force
            Write-Host "Metrics written to $OutputFile ($lineCount lines)" -ForegroundColor Green
        }
        catch {
            Remove-Item -Path $tempFile -Force -ErrorAction SilentlyContinue
            Write-Error "Failed to generate metrics: $_"
            exit 1
        }
    }
    default {
        Get-AllMetrics | Write-Output
    }
}
