# ============================================================
# 設定(ここだけ触れば運用に合わせて調整)
# ============================================================
$Config = @{
SyslogServer = "192.168.0.10"
SyslogPort = 514
ThresholdHours = 3.0 # 3時間を超えたら Error
Facility = "local0" # RFC5424 facility
Flag = 0 # Bit判定用(1 → 強制Error)
ForceError = $false
EventSource = "UptimeMonitorScript"
EventLogName = "Application"
AppName = "UptimeMonitor"
MsgId = "UPTIME_CHECK"
}
# ============================================================
# -----------------------------
# 関数: uptime 取得
# -----------------------------
function Get-Uptime {
$os = Get-CimInstance -ClassName Win32_OperatingSystem
return (Get-Date) - $os.LastBootUpTime
}
# -----------------------------
# PRI 計算
# -----------------------------
function Get-SyslogPri {
param(
[Parameter(Mandatory=$true)][string]$FacilityName,
[Parameter(Mandatory=$true)][ValidateSet("info","error")] [string]$SeverityName
)
$facilityCodes = @{
"local0" = 16; "local1" = 17; "local2" = 18; "local3" = 19
"local4" = 20; "local5" = 21; "local6" = 22; "local7" = 23
}
$severityCodes = @{ "error" = 3; "info" = 6 }
return ($facilityCodes[$FacilityName] * 8 + $severityCodes[$SeverityName])
}
# -----------------------------
# RFC5424 syslog 送信
# -----------------------------
function Send-SyslogRfc5424 {
param(
[int]$Pri, [string]$AppName, [string]$ProcId,
[string]$MsgId, [string]$StructuredData,
[string]$Message, [string]$Server, [int]$Port
)
$version = 1
$timestamp = (Get-Date).ToString("yyyy-MM-dd'T'HH:mm:ss.fffK")
$hostname = $env:COMPUTERNAME
$syslog = "<$Pri>$version $timestamp $hostname $AppName $ProcId $MsgId $StructuredData $Message"
$client = New-Object System.Net.Sockets.UdpClient
try {
$bytes = [System.Text.Encoding]::UTF8.GetBytes($syslog)
[void]$client.Send($bytes, $bytes.Length, $Server, $Port)
}
finally {
$client.Close()
}
}
# -----------------------------
# メイン処理
# -----------------------------
$uptime = Get-Uptime
$uptimeHours = [math]::Round($uptime.TotalHours, 2)
$uptimeSeconds = [math]::Round($uptime.TotalSeconds)
$evaluation = if ($uptimeHours -ge $Config.ThresholdHours) { "OverThreshold" } else { "WithinThreshold" }
# Error 判定
$severity =
if ($Config.ForceError -or *1 {
"error"
}
else {
if ($uptimeHours -ge $Config.ThresholdHours) { "error" } else { "info" }
}
# メッセージ
$message = "Uptime: {0:F2}h ({1}s). Threshold: {2}h. Eval: {3}. Severity: {4}. Flag: {5}." -f `
$uptimeHours, $uptimeSeconds, $Config.ThresholdHours, $evaluation, $severity, $Config.Flag
# イベントログ
if (-not [System.Diagnostics.EventLog]::SourceExists($Config.EventSource)) {
try { New-EventLog -LogName $Config.EventLogName -Source $Config.EventSource } catch {}
}
# severity に応じて EntryType など設定
$entryType = if ($severity -eq "error") {
[System.Diagnostics.EventLogEntryType]::Error
} else {
[System.Diagnostics.EventLogEntryType]::Information
}
# ここで EventId を決める(PS5.1対応)
$eventId = if ($severity -eq "error") { 20001 } else { 20000 }
Write-EventLog -LogName $Config.EventLogName -Source $Config.EventSource `
-EventId $eventId `
-EntryType $entryType `
-Message $message
# syslog PRI / SD
$pri = Get-SyslogPri -FacilityName $Config.Facility -SeverityName $severity
$sd = ('[uptime@32473 uptime="{0:F2}" seconds="{1}" threshold="{2}" eval="{3}" flag="{4}"]' -f `
$uptimeHours, $uptimeSeconds, $Config.ThresholdHours, $evaluation, $Config.Flag)
# 送信
Send-SyslogRfc5424 `
-Pri $pri `
-AppName $Config.AppName `
-ProcId $PID `
-MsgId $Config.MsgId `
-StructuredData $sd `
-Message $message `
-Server $Config.SyslogServer `
-Port $Config.SyslogPort