a1a17e81a1
Includes updated JS challenge scripts with Claude-User whitelist, same-site referer bypass, Blackbox-Exporter allowed bot, and all new exporters, cheat sheets, and automation scripts.
596 lines
24 KiB
PowerShell
596 lines
24 KiB
PowerShell
<#
|
|
.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
|
|
}
|
|
}
|