Sync all scripts from website downloads — 352 scripts total
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.
This commit is contained in:
@@ -0,0 +1,713 @@
|
||||
<#
|
||||
.SYNOPSIS
|
||||
Windows Event Log Prometheus Metrics Exporter
|
||||
.DESCRIPTION
|
||||
Prometheus exporter for Windows Event Log critical and error events. Scans
|
||||
System, Application, and Security event logs for errors, warnings, and
|
||||
critical events. Exports counts, rates, and recent event details as
|
||||
Prometheus-compatible text format for windows_exporter textfile collector.
|
||||
.PARAMETER Mode
|
||||
Output mode: 'stdout' (default), 'textfile', or 'http'
|
||||
.PARAMETER Port
|
||||
HTTP port for http mode (default: 9199)
|
||||
.PARAMETER TextfileDir
|
||||
Directory for textfile collector output (default: C:\ProgramData\node_exporter)
|
||||
.PARAMETER OutputFile
|
||||
Custom output file path
|
||||
.PARAMETER InstallScheduledTask
|
||||
Switch to create a scheduled task for auto-start on system boot
|
||||
.PARAMETER TaskIntervalMinutes
|
||||
Interval in minutes for the scheduled task (default: 5)
|
||||
.NOTES
|
||||
Author: Phil Connor
|
||||
Contact: contact@mylinux.work
|
||||
Website: https://mylinux.work
|
||||
License: MIT
|
||||
Version: 1.0
|
||||
|
||||
Metrics Exported:
|
||||
Core Status:
|
||||
- windows_eventlog_up
|
||||
- windows_eventlog_exporter_info{version}
|
||||
|
||||
System Log:
|
||||
- windows_eventlog_system_critical_total_1h
|
||||
- windows_eventlog_system_critical_total_6h
|
||||
- windows_eventlog_system_critical_total_24h
|
||||
- windows_eventlog_system_error_total_1h
|
||||
- windows_eventlog_system_error_total_6h
|
||||
- windows_eventlog_system_error_total_24h
|
||||
- windows_eventlog_system_warning_total_1h
|
||||
- windows_eventlog_system_warning_total_6h
|
||||
- windows_eventlog_system_warning_total_24h
|
||||
- windows_eventlog_system_top_source_count{source}
|
||||
- windows_eventlog_system_events_per_hour
|
||||
|
||||
Application Log:
|
||||
- windows_eventlog_application_critical_total_1h
|
||||
- windows_eventlog_application_critical_total_6h
|
||||
- windows_eventlog_application_critical_total_24h
|
||||
- windows_eventlog_application_error_total_1h
|
||||
- windows_eventlog_application_error_total_6h
|
||||
- windows_eventlog_application_error_total_24h
|
||||
- windows_eventlog_application_warning_total_1h
|
||||
- windows_eventlog_application_warning_total_6h
|
||||
- windows_eventlog_application_warning_total_24h
|
||||
- windows_eventlog_application_top_source_count{source}
|
||||
- windows_eventlog_application_events_per_hour
|
||||
- windows_eventlog_application_crash_total_24h
|
||||
- windows_eventlog_application_dotnet_error_total_24h
|
||||
|
||||
Security Log (requires admin):
|
||||
- windows_eventlog_security_failed_logon_total_24h
|
||||
- windows_eventlog_security_account_lockout_total_24h
|
||||
- windows_eventlog_security_privilege_escalation_total_24h
|
||||
- windows_eventlog_security_audit_policy_change_total_24h
|
||||
|
||||
Service Failures:
|
||||
- windows_eventlog_service_stopped_autostart{service}
|
||||
- windows_eventlog_service_crash_total_24h
|
||||
|
||||
Disk Events:
|
||||
- windows_eventlog_disk_error_total_24h{source}
|
||||
|
||||
System Stability:
|
||||
- windows_eventlog_unexpected_shutdown_total_24h
|
||||
- windows_eventlog_bugcheck_total_24h
|
||||
|
||||
Summary:
|
||||
- windows_eventlog_total_critical_error_all_logs
|
||||
- windows_eventlog_newest_event_timestamp{log}
|
||||
|
||||
Exporter:
|
||||
- windows_eventlog_exporter_duration_seconds
|
||||
- windows_eventlog_exporter_last_run_timestamp
|
||||
#>
|
||||
|
||||
param(
|
||||
[ValidateSet('stdout', 'textfile', 'http')]
|
||||
[string]$Mode = 'stdout',
|
||||
|
||||
[int]$Port = 9199,
|
||||
|
||||
[string]$TextfileDir = 'C:\ProgramData\node_exporter',
|
||||
|
||||
[string]$OutputFile,
|
||||
|
||||
[switch]$InstallScheduledTask,
|
||||
|
||||
[int]$TaskIntervalMinutes = 5
|
||||
)
|
||||
|
||||
# Create a scheduled task to run this script every $TaskIntervalMinutes minutes
|
||||
# The task will run as SYSTEM and will be set to run at startup
|
||||
if ($InstallScheduledTask) {
|
||||
$taskName = "WindowsEventLogExporter"
|
||||
$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 Windows event log 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 auto-start 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 Get-EventCount {
|
||||
param(
|
||||
[string]$LogName,
|
||||
[int[]]$Level,
|
||||
[int[]]$Id,
|
||||
[string[]]$ProviderName,
|
||||
[int]$Hours = 24
|
||||
)
|
||||
|
||||
$filter = @{
|
||||
LogName = $LogName
|
||||
StartTime = (Get-Date).AddHours(-$Hours)
|
||||
}
|
||||
if ($Level) { $filter['Level'] = $Level }
|
||||
if ($Id) { $filter['Id'] = $Id }
|
||||
if ($ProviderName) { $filter['ProviderName'] = $ProviderName }
|
||||
|
||||
try {
|
||||
$events = Get-WinEvent -FilterHashtable $filter -ErrorAction Stop
|
||||
return @($events).Count
|
||||
} catch {
|
||||
return 0
|
||||
}
|
||||
}
|
||||
|
||||
function Get-EventCountToTimestamp {
|
||||
param(
|
||||
[string]$LogName,
|
||||
[int[]]$Level
|
||||
)
|
||||
|
||||
try {
|
||||
$events = Get-WinEvent -FilterHashtable @{
|
||||
LogName = $LogName
|
||||
Level = $Level
|
||||
} -MaxEvents 1 -ErrorAction Stop
|
||||
|
||||
if ($events -and $events.Count -gt 0) {
|
||||
return [int][double]::Parse($events[0].TimeCreated.ToUniversalTime().ToString('yyyyMMddHHmmss').Substring(0,10))
|
||||
}
|
||||
} catch {}
|
||||
|
||||
try {
|
||||
$events = Get-WinEvent -FilterHashtable @{
|
||||
LogName = $LogName
|
||||
} -MaxEvents 1 -ErrorAction Stop
|
||||
|
||||
if ($events -and $events.Count -gt 0) {
|
||||
$epoch = [datetime]'1970-01-01'
|
||||
return [int]($events[0].TimeCreated.ToUniversalTime() - $epoch).TotalSeconds
|
||||
}
|
||||
} catch {}
|
||||
|
||||
return 0
|
||||
}
|
||||
|
||||
# ============================================================================
|
||||
# SYSTEM LOG EVENTS
|
||||
# ============================================================================
|
||||
|
||||
function Get-SystemLogMetrics {
|
||||
$sb = [System.Text.StringBuilder]::new()
|
||||
|
||||
try {
|
||||
# Critical events (Level 1)
|
||||
foreach ($window in @(@{Suffix='1h'; Hours=1}, @{Suffix='6h'; Hours=6}, @{Suffix='24h'; Hours=24})) {
|
||||
$count = Get-EventCount -LogName 'System' -Level 1 -Hours $window.Hours
|
||||
[void]$sb.AppendLine("# HELP windows_eventlog_system_critical_total_$($window.Suffix) System log critical events in last $($window.Suffix)")
|
||||
[void]$sb.AppendLine("# TYPE windows_eventlog_system_critical_total_$($window.Suffix) gauge")
|
||||
[void]$sb.AppendLine("windows_eventlog_system_critical_total_$($window.Suffix) $count")
|
||||
[void]$sb.AppendLine('')
|
||||
}
|
||||
|
||||
# Error events (Level 2)
|
||||
foreach ($window in @(@{Suffix='1h'; Hours=1}, @{Suffix='6h'; Hours=6}, @{Suffix='24h'; Hours=24})) {
|
||||
$count = Get-EventCount -LogName 'System' -Level 2 -Hours $window.Hours
|
||||
[void]$sb.AppendLine("# HELP windows_eventlog_system_error_total_$($window.Suffix) System log error events in last $($window.Suffix)")
|
||||
[void]$sb.AppendLine("# TYPE windows_eventlog_system_error_total_$($window.Suffix) gauge")
|
||||
[void]$sb.AppendLine("windows_eventlog_system_error_total_$($window.Suffix) $count")
|
||||
[void]$sb.AppendLine('')
|
||||
}
|
||||
|
||||
# Warning events (Level 3)
|
||||
foreach ($window in @(@{Suffix='1h'; Hours=1}, @{Suffix='6h'; Hours=6}, @{Suffix='24h'; Hours=24})) {
|
||||
$count = Get-EventCount -LogName 'System' -Level 3 -Hours $window.Hours
|
||||
[void]$sb.AppendLine("# HELP windows_eventlog_system_warning_total_$($window.Suffix) System log warning events in last $($window.Suffix)")
|
||||
[void]$sb.AppendLine("# TYPE windows_eventlog_system_warning_total_$($window.Suffix) gauge")
|
||||
[void]$sb.AppendLine("windows_eventlog_system_warning_total_$($window.Suffix) $count")
|
||||
[void]$sb.AppendLine('')
|
||||
}
|
||||
|
||||
# Top event sources
|
||||
try {
|
||||
$systemEvents = Get-WinEvent -FilterHashtable @{
|
||||
LogName = 'System'
|
||||
Level = 1, 2
|
||||
StartTime = (Get-Date).AddHours(-24)
|
||||
} -ErrorAction Stop
|
||||
|
||||
$topSources = $systemEvents | Group-Object ProviderName |
|
||||
Sort-Object Count -Descending |
|
||||
Select-Object -First 5
|
||||
|
||||
[void]$sb.AppendLine('# HELP windows_eventlog_system_top_source_count Event count for top sources in System log')
|
||||
[void]$sb.AppendLine('# TYPE windows_eventlog_system_top_source_count gauge')
|
||||
foreach ($source in $topSources) {
|
||||
$sourceName = $source.Name -replace '"', ''
|
||||
[void]$sb.AppendLine("windows_eventlog_system_top_source_count{source=`"$sourceName`"} $($source.Count)")
|
||||
}
|
||||
[void]$sb.AppendLine('')
|
||||
} catch {
|
||||
[void]$sb.AppendLine('# HELP windows_eventlog_system_top_source_count Event count for top sources in System log')
|
||||
[void]$sb.AppendLine('# TYPE windows_eventlog_system_top_source_count gauge')
|
||||
[void]$sb.AppendLine('')
|
||||
}
|
||||
|
||||
# Events per hour
|
||||
$total24h = Get-EventCount -LogName 'System' -Level 1, 2 -Hours 24
|
||||
$perHour = Format-MetricValue ($total24h / 24)
|
||||
[void]$sb.AppendLine('# HELP windows_eventlog_system_events_per_hour System log error/critical event rate per hour')
|
||||
[void]$sb.AppendLine('# TYPE windows_eventlog_system_events_per_hour gauge')
|
||||
[void]$sb.AppendLine("windows_eventlog_system_events_per_hour $perHour")
|
||||
[void]$sb.AppendLine('')
|
||||
}
|
||||
catch {
|
||||
Write-Warning "Failed to collect system log metrics: $_"
|
||||
}
|
||||
|
||||
$sb.ToString()
|
||||
}
|
||||
|
||||
# ============================================================================
|
||||
# APPLICATION LOG EVENTS
|
||||
# ============================================================================
|
||||
|
||||
function Get-ApplicationLogMetrics {
|
||||
$sb = [System.Text.StringBuilder]::new()
|
||||
|
||||
try {
|
||||
# Critical events (Level 1)
|
||||
foreach ($window in @(@{Suffix='1h'; Hours=1}, @{Suffix='6h'; Hours=6}, @{Suffix='24h'; Hours=24})) {
|
||||
$count = Get-EventCount -LogName 'Application' -Level 1 -Hours $window.Hours
|
||||
[void]$sb.AppendLine("# HELP windows_eventlog_application_critical_total_$($window.Suffix) Application log critical events in last $($window.Suffix)")
|
||||
[void]$sb.AppendLine("# TYPE windows_eventlog_application_critical_total_$($window.Suffix) gauge")
|
||||
[void]$sb.AppendLine("windows_eventlog_application_critical_total_$($window.Suffix) $count")
|
||||
[void]$sb.AppendLine('')
|
||||
}
|
||||
|
||||
# Error events (Level 2)
|
||||
foreach ($window in @(@{Suffix='1h'; Hours=1}, @{Suffix='6h'; Hours=6}, @{Suffix='24h'; Hours=24})) {
|
||||
$count = Get-EventCount -LogName 'Application' -Level 2 -Hours $window.Hours
|
||||
[void]$sb.AppendLine("# HELP windows_eventlog_application_error_total_$($window.Suffix) Application log error events in last $($window.Suffix)")
|
||||
[void]$sb.AppendLine("# TYPE windows_eventlog_application_error_total_$($window.Suffix) gauge")
|
||||
[void]$sb.AppendLine("windows_eventlog_application_error_total_$($window.Suffix) $count")
|
||||
[void]$sb.AppendLine('')
|
||||
}
|
||||
|
||||
# Warning events (Level 3)
|
||||
foreach ($window in @(@{Suffix='1h'; Hours=1}, @{Suffix='6h'; Hours=6}, @{Suffix='24h'; Hours=24})) {
|
||||
$count = Get-EventCount -LogName 'Application' -Level 3 -Hours $window.Hours
|
||||
[void]$sb.AppendLine("# HELP windows_eventlog_application_warning_total_$($window.Suffix) Application log warning events in last $($window.Suffix)")
|
||||
[void]$sb.AppendLine("# TYPE windows_eventlog_application_warning_total_$($window.Suffix) gauge")
|
||||
[void]$sb.AppendLine("windows_eventlog_application_warning_total_$($window.Suffix) $count")
|
||||
[void]$sb.AppendLine('')
|
||||
}
|
||||
|
||||
# Top event sources
|
||||
try {
|
||||
$appEvents = Get-WinEvent -FilterHashtable @{
|
||||
LogName = 'Application'
|
||||
Level = 1, 2
|
||||
StartTime = (Get-Date).AddHours(-24)
|
||||
} -ErrorAction Stop
|
||||
|
||||
$topSources = $appEvents | Group-Object ProviderName |
|
||||
Sort-Object Count -Descending |
|
||||
Select-Object -First 5
|
||||
|
||||
[void]$sb.AppendLine('# HELP windows_eventlog_application_top_source_count Event count for top sources in Application log')
|
||||
[void]$sb.AppendLine('# TYPE windows_eventlog_application_top_source_count gauge')
|
||||
foreach ($source in $topSources) {
|
||||
$sourceName = $source.Name -replace '"', ''
|
||||
[void]$sb.AppendLine("windows_eventlog_application_top_source_count{source=`"$sourceName`"} $($source.Count)")
|
||||
}
|
||||
[void]$sb.AppendLine('')
|
||||
} catch {
|
||||
[void]$sb.AppendLine('# HELP windows_eventlog_application_top_source_count Event count for top sources in Application log')
|
||||
[void]$sb.AppendLine('# TYPE windows_eventlog_application_top_source_count gauge')
|
||||
[void]$sb.AppendLine('')
|
||||
}
|
||||
|
||||
# Events per hour
|
||||
$total24h = Get-EventCount -LogName 'Application' -Level 1, 2 -Hours 24
|
||||
$perHour = Format-MetricValue ($total24h / 24)
|
||||
[void]$sb.AppendLine('# HELP windows_eventlog_application_events_per_hour Application log error/critical event rate per hour')
|
||||
[void]$sb.AppendLine('# TYPE windows_eventlog_application_events_per_hour gauge')
|
||||
[void]$sb.AppendLine("windows_eventlog_application_events_per_hour $perHour")
|
||||
[void]$sb.AppendLine('')
|
||||
|
||||
# Application crash events (WER)
|
||||
$crashCount = Get-EventCount -LogName 'Application' -ProviderName 'Application Error', 'Windows Error Reporting' -Hours 24
|
||||
[void]$sb.AppendLine('# HELP windows_eventlog_application_crash_total_24h Application crash events (WER) in last 24 hours')
|
||||
[void]$sb.AppendLine('# TYPE windows_eventlog_application_crash_total_24h gauge')
|
||||
[void]$sb.AppendLine("windows_eventlog_application_crash_total_24h $crashCount")
|
||||
[void]$sb.AppendLine('')
|
||||
|
||||
# .NET runtime errors
|
||||
$dotnetCount = Get-EventCount -LogName 'Application' -ProviderName '.NET Runtime' -Level 1, 2 -Hours 24
|
||||
[void]$sb.AppendLine('# HELP windows_eventlog_application_dotnet_error_total_24h .NET runtime errors in last 24 hours')
|
||||
[void]$sb.AppendLine('# TYPE windows_eventlog_application_dotnet_error_total_24h gauge')
|
||||
[void]$sb.AppendLine("windows_eventlog_application_dotnet_error_total_24h $dotnetCount")
|
||||
[void]$sb.AppendLine('')
|
||||
}
|
||||
catch {
|
||||
Write-Warning "Failed to collect application log metrics: $_"
|
||||
}
|
||||
|
||||
$sb.ToString()
|
||||
}
|
||||
|
||||
# ============================================================================
|
||||
# SECURITY LOG EVENTS (requires admin)
|
||||
# ============================================================================
|
||||
|
||||
function Get-SecurityLogMetrics {
|
||||
$sb = [System.Text.StringBuilder]::new()
|
||||
|
||||
try {
|
||||
# Failed logon attempts (Event ID 4625)
|
||||
$failedLogons = Get-EventCount -LogName 'Security' -Id 4625 -Hours 24
|
||||
[void]$sb.AppendLine('# HELP windows_eventlog_security_failed_logon_total_24h Failed logon attempts (4625) in last 24 hours')
|
||||
[void]$sb.AppendLine('# TYPE windows_eventlog_security_failed_logon_total_24h gauge')
|
||||
[void]$sb.AppendLine("windows_eventlog_security_failed_logon_total_24h $failedLogons")
|
||||
[void]$sb.AppendLine('')
|
||||
|
||||
# Account lockouts (Event ID 4740)
|
||||
$lockouts = Get-EventCount -LogName 'Security' -Id 4740 -Hours 24
|
||||
[void]$sb.AppendLine('# HELP windows_eventlog_security_account_lockout_total_24h Account lockout events (4740) in last 24 hours')
|
||||
[void]$sb.AppendLine('# TYPE windows_eventlog_security_account_lockout_total_24h gauge')
|
||||
[void]$sb.AppendLine("windows_eventlog_security_account_lockout_total_24h $lockouts")
|
||||
[void]$sb.AppendLine('')
|
||||
|
||||
# Privilege escalation (Event IDs 4672, 4673)
|
||||
$privEsc = Get-EventCount -LogName 'Security' -Id 4672, 4673 -Hours 24
|
||||
[void]$sb.AppendLine('# HELP windows_eventlog_security_privilege_escalation_total_24h Privilege escalation events (4672/4673) in last 24 hours')
|
||||
[void]$sb.AppendLine('# TYPE windows_eventlog_security_privilege_escalation_total_24h gauge')
|
||||
[void]$sb.AppendLine("windows_eventlog_security_privilege_escalation_total_24h $privEsc")
|
||||
[void]$sb.AppendLine('')
|
||||
|
||||
# Audit policy changes (Event ID 4719)
|
||||
$auditChanges = Get-EventCount -LogName 'Security' -Id 4719 -Hours 24
|
||||
[void]$sb.AppendLine('# HELP windows_eventlog_security_audit_policy_change_total_24h Audit policy change events (4719) in last 24 hours')
|
||||
[void]$sb.AppendLine('# TYPE windows_eventlog_security_audit_policy_change_total_24h gauge')
|
||||
[void]$sb.AppendLine("windows_eventlog_security_audit_policy_change_total_24h $auditChanges")
|
||||
[void]$sb.AppendLine('')
|
||||
}
|
||||
catch {
|
||||
Write-Warning "Failed to collect security log metrics (admin required): $_"
|
||||
}
|
||||
|
||||
$sb.ToString()
|
||||
}
|
||||
|
||||
# ============================================================================
|
||||
# SERVICE FAILURES
|
||||
# ============================================================================
|
||||
|
||||
function Get-ServiceFailureMetrics {
|
||||
$sb = [System.Text.StringBuilder]::new()
|
||||
|
||||
try {
|
||||
# Auto-start services that are stopped
|
||||
$stoppedAutoStart = Get-Service | Where-Object {
|
||||
$_.StartType -eq 'Automatic' -and $_.Status -ne 'Running'
|
||||
}
|
||||
|
||||
[void]$sb.AppendLine('# HELP windows_eventlog_service_stopped_autostart Auto-start services currently in stopped state')
|
||||
[void]$sb.AppendLine('# TYPE windows_eventlog_service_stopped_autostart gauge')
|
||||
if ($stoppedAutoStart) {
|
||||
foreach ($svc in $stoppedAutoStart) {
|
||||
$svcName = $svc.Name -replace '"', ''
|
||||
[void]$sb.AppendLine("windows_eventlog_service_stopped_autostart{service=`"$svcName`"} 1")
|
||||
}
|
||||
}
|
||||
[void]$sb.AppendLine('')
|
||||
|
||||
# Service crash events (SCM Event IDs 7031, 7034)
|
||||
$crashCount = Get-EventCount -LogName 'System' -ProviderName 'Service Control Manager' -Id 7031, 7034 -Hours 24
|
||||
[void]$sb.AppendLine('# HELP windows_eventlog_service_crash_total_24h Service crash events in last 24 hours')
|
||||
[void]$sb.AppendLine('# TYPE windows_eventlog_service_crash_total_24h gauge')
|
||||
[void]$sb.AppendLine("windows_eventlog_service_crash_total_24h $crashCount")
|
||||
[void]$sb.AppendLine('')
|
||||
}
|
||||
catch {
|
||||
Write-Warning "Failed to collect service failure metrics: $_"
|
||||
}
|
||||
|
||||
$sb.ToString()
|
||||
}
|
||||
|
||||
# ============================================================================
|
||||
# DISK EVENTS
|
||||
# ============================================================================
|
||||
|
||||
function Get-DiskEventMetrics {
|
||||
$sb = [System.Text.StringBuilder]::new()
|
||||
|
||||
try {
|
||||
$diskSources = @('disk', 'ntfs', 'volmgr', 'Ntfs', 'Disk', 'volsnap')
|
||||
|
||||
[void]$sb.AppendLine('# HELP windows_eventlog_disk_error_total_24h Disk errors in last 24 hours by source')
|
||||
[void]$sb.AppendLine('# TYPE windows_eventlog_disk_error_total_24h gauge')
|
||||
|
||||
foreach ($source in $diskSources) {
|
||||
$count = Get-EventCount -LogName 'System' -ProviderName $source -Level 1, 2, 3 -Hours 24
|
||||
if ($count -gt 0) {
|
||||
[void]$sb.AppendLine("windows_eventlog_disk_error_total_24h{source=`"$source`"} $count")
|
||||
}
|
||||
}
|
||||
[void]$sb.AppendLine('')
|
||||
}
|
||||
catch {
|
||||
Write-Warning "Failed to collect disk event metrics: $_"
|
||||
}
|
||||
|
||||
$sb.ToString()
|
||||
}
|
||||
|
||||
# ============================================================================
|
||||
# SYSTEM STABILITY
|
||||
# ============================================================================
|
||||
|
||||
function Get-SystemStabilityMetrics {
|
||||
$sb = [System.Text.StringBuilder]::new()
|
||||
|
||||
try {
|
||||
# Unexpected shutdown events (Event ID 6008)
|
||||
$unexpectedShutdowns = Get-EventCount -LogName 'System' -Id 6008 -Hours 24
|
||||
[void]$sb.AppendLine('# HELP windows_eventlog_unexpected_shutdown_total_24h Unexpected shutdown events (6008) in last 24 hours')
|
||||
[void]$sb.AppendLine('# TYPE windows_eventlog_unexpected_shutdown_total_24h gauge')
|
||||
[void]$sb.AppendLine("windows_eventlog_unexpected_shutdown_total_24h $unexpectedShutdowns")
|
||||
[void]$sb.AppendLine('')
|
||||
|
||||
# Bugcheck events
|
||||
$bugchecks = 0
|
||||
try {
|
||||
$bugcheckEvents = Get-WinEvent -FilterHashtable @{
|
||||
LogName = 'System'
|
||||
ProviderName = 'Microsoft-Windows-WER-SystemErrorReporting', 'BugCheck'
|
||||
StartTime = (Get-Date).AddHours(-24)
|
||||
} -ErrorAction Stop
|
||||
$bugchecks = @($bugcheckEvents).Count
|
||||
} catch {}
|
||||
[void]$sb.AppendLine('# HELP windows_eventlog_bugcheck_total_24h Bugcheck events in last 24 hours')
|
||||
[void]$sb.AppendLine('# TYPE windows_eventlog_bugcheck_total_24h gauge')
|
||||
[void]$sb.AppendLine("windows_eventlog_bugcheck_total_24h $bugchecks")
|
||||
[void]$sb.AppendLine('')
|
||||
}
|
||||
catch {
|
||||
Write-Warning "Failed to collect system stability metrics: $_"
|
||||
}
|
||||
|
||||
$sb.ToString()
|
||||
}
|
||||
|
||||
# ============================================================================
|
||||
# SUMMARY
|
||||
# ============================================================================
|
||||
|
||||
function Get-SummaryMetrics {
|
||||
$sb = [System.Text.StringBuilder]::new()
|
||||
|
||||
try {
|
||||
# Total critical+error across all logs
|
||||
$sysCritErr = Get-EventCount -LogName 'System' -Level 1, 2 -Hours 24
|
||||
$appCritErr = Get-EventCount -LogName 'Application' -Level 1, 2 -Hours 24
|
||||
$total = $sysCritErr + $appCritErr
|
||||
|
||||
[void]$sb.AppendLine('# HELP windows_eventlog_total_critical_error_all_logs Total critical and error events across all logs (24h)')
|
||||
[void]$sb.AppendLine('# TYPE windows_eventlog_total_critical_error_all_logs gauge')
|
||||
[void]$sb.AppendLine("windows_eventlog_total_critical_error_all_logs $total")
|
||||
[void]$sb.AppendLine('')
|
||||
|
||||
# Newest event timestamp per log
|
||||
[void]$sb.AppendLine('# HELP windows_eventlog_newest_event_timestamp Unix timestamp of newest event per log')
|
||||
[void]$sb.AppendLine('# TYPE windows_eventlog_newest_event_timestamp gauge')
|
||||
|
||||
foreach ($logName in @('System', 'Application', 'Security')) {
|
||||
try {
|
||||
$newestEvent = Get-WinEvent -LogName $logName -MaxEvents 1 -ErrorAction Stop
|
||||
if ($newestEvent) {
|
||||
$epoch = [datetime]'1970-01-01'
|
||||
$ts = [int]($newestEvent.TimeCreated.ToUniversalTime() - $epoch).TotalSeconds
|
||||
[void]$sb.AppendLine("windows_eventlog_newest_event_timestamp{log=`"$logName`"} $ts")
|
||||
}
|
||||
} catch {}
|
||||
}
|
||||
[void]$sb.AppendLine('')
|
||||
}
|
||||
catch {
|
||||
Write-Warning "Failed to collect summary metrics: $_"
|
||||
}
|
||||
|
||||
$sb.ToString()
|
||||
}
|
||||
|
||||
# ============================================================================
|
||||
# COLLECT ALL METRICS
|
||||
# ============================================================================
|
||||
|
||||
function Get-AllMetrics {
|
||||
$scriptStart = Get-Date
|
||||
$sb = [System.Text.StringBuilder]::new()
|
||||
|
||||
# Exporter up
|
||||
[void]$sb.AppendLine('# HELP windows_eventlog_up Exporter status (1=up, 0=down)')
|
||||
[void]$sb.AppendLine('# TYPE windows_eventlog_up gauge')
|
||||
[void]$sb.AppendLine('windows_eventlog_up 1')
|
||||
[void]$sb.AppendLine('')
|
||||
|
||||
# Exporter info
|
||||
[void]$sb.AppendLine('# HELP windows_eventlog_exporter_info Exporter version information')
|
||||
[void]$sb.AppendLine('# TYPE windows_eventlog_exporter_info gauge')
|
||||
[void]$sb.AppendLine('windows_eventlog_exporter_info{version="1.0"} 1')
|
||||
[void]$sb.AppendLine('')
|
||||
|
||||
# Collect all sections
|
||||
[void]$sb.Append((Get-SystemLogMetrics))
|
||||
[void]$sb.Append((Get-ApplicationLogMetrics))
|
||||
[void]$sb.Append((Get-SecurityLogMetrics))
|
||||
[void]$sb.Append((Get-ServiceFailureMetrics))
|
||||
[void]$sb.Append((Get-DiskEventMetrics))
|
||||
[void]$sb.Append((Get-SystemStabilityMetrics))
|
||||
[void]$sb.Append((Get-SummaryMetrics))
|
||||
|
||||
# Exporter runtime
|
||||
$scriptEnd = Get-Date
|
||||
$duration = Format-MetricValue ($scriptEnd - $scriptStart).TotalSeconds
|
||||
$timestamp = Get-UnixTimestamp
|
||||
|
||||
[void]$sb.AppendLine('# HELP windows_eventlog_exporter_duration_seconds Time to generate all metrics')
|
||||
[void]$sb.AppendLine('# TYPE windows_eventlog_exporter_duration_seconds gauge')
|
||||
[void]$sb.AppendLine("windows_eventlog_exporter_duration_seconds $duration")
|
||||
[void]$sb.AppendLine('')
|
||||
[void]$sb.AppendLine('# HELP windows_eventlog_exporter_last_run_timestamp Unix timestamp of last successful run')
|
||||
[void]$sb.AppendLine('# TYPE windows_eventlog_exporter_last_run_timestamp gauge')
|
||||
[void]$sb.AppendLine("windows_eventlog_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 Windows event log 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>Windows Event Log Exporter v1.0</title></head>
|
||||
<body>
|
||||
<h1>Windows Event Log Exporter v1.0</h1>
|
||||
<p><a href="/metrics">Metrics</a></p>
|
||||
<h2>Sections</h2>
|
||||
<ul>
|
||||
<li>System log events (critical, error, warning counts)</li>
|
||||
<li>Application log events (crashes, .NET runtime errors)</li>
|
||||
<li>Security log events (failed logons, lockouts, privilege escalation)</li>
|
||||
<li>Service failures (stopped auto-start services, crash events)</li>
|
||||
<li>Disk events (disk, ntfs, volmgr errors)</li>
|
||||
<li>System stability (unexpected shutdowns, bugchecks)</li>
|
||||
<li>Summary (total events, newest timestamps per log)</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' {
|
||||
if (-not $OutputFile) {
|
||||
$OutputFile = Join-Path $TextfileDir 'windows_eventlog.prom'
|
||||
}
|
||||
|
||||
$outputDir = Split-Path $OutputFile -Parent
|
||||
if (-not (Test-Path $outputDir)) {
|
||||
New-Item -Path $outputDir -ItemType Directory -Force | Out-Null
|
||||
}
|
||||
|
||||
$tempFile = Join-Path $outputDir ".windows_eventlog_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
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user