- Complete PowerShell-based monitoring solution for Windows reboots - Detects startup, shutdown, and unexpected restart events - Rich Discord notifications with color-coded alerts - Automatic reboot reason detection (Windows Update, power loss, user-initiated) - Task Scheduler integration for reliable event monitoring - Comprehensive setup instructions and troubleshooting guide 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude <noreply@anthropic.com>
205 lines
6.4 KiB
PowerShell
205 lines
6.4 KiB
PowerShell
# Windows Reboot Monitor with Discord Notifications
|
|
# This script sends Discord webhook notifications when the system starts up or shuts down
|
|
|
|
param(
|
|
[Parameter(Mandatory=$true)]
|
|
[ValidateSet("startup", "shutdown")]
|
|
[string]$EventType,
|
|
|
|
[Parameter(Mandatory=$false)]
|
|
[string]$WebhookUrl = $env:DISCORD_WEBHOOK_URL,
|
|
|
|
[Parameter(Mandatory=$false)]
|
|
[string]$ComputerName = $env:COMPUTERNAME
|
|
)
|
|
|
|
# Configuration
|
|
$LogFile = "C:\Windows\Temp\reboot-monitor.log"
|
|
$ConfigFile = "C:\Windows\Temp\reboot-monitor-config.json"
|
|
|
|
# Function to log messages
|
|
function Write-Log {
|
|
param([string]$Message)
|
|
$timestamp = Get-Date -Format "yyyy-MM-dd HH:mm:ss"
|
|
"$timestamp - $Message" | Out-File -Append -FilePath $LogFile
|
|
Write-Host "$timestamp - $Message"
|
|
}
|
|
|
|
# Function to load configuration
|
|
function Get-Configuration {
|
|
if (Test-Path $ConfigFile) {
|
|
try {
|
|
$config = Get-Content $ConfigFile | ConvertFrom-Json
|
|
return $config
|
|
} catch {
|
|
Write-Log "Error reading config file: $($_.Exception.Message)"
|
|
}
|
|
}
|
|
return $null
|
|
}
|
|
|
|
# Function to save configuration
|
|
function Save-Configuration {
|
|
param($config)
|
|
try {
|
|
$config | ConvertTo-Json | Out-File -FilePath $ConfigFile
|
|
Write-Log "Configuration saved to $ConfigFile"
|
|
} catch {
|
|
Write-Log "Error saving config: $($_.Exception.Message)"
|
|
}
|
|
}
|
|
|
|
# Function to send Discord notification
|
|
function Send-DiscordNotification {
|
|
param(
|
|
[string]$WebhookUrl,
|
|
[string]$Message,
|
|
[string]$Color = "3066993" # Default blue color
|
|
)
|
|
|
|
if ([string]::IsNullOrEmpty($WebhookUrl)) {
|
|
Write-Log "No Discord webhook URL provided"
|
|
return $false
|
|
}
|
|
|
|
$embed = @{
|
|
title = "Windows System Monitor"
|
|
description = $Message
|
|
color = [int]$Color
|
|
timestamp = (Get-Date).ToString("yyyy-MM-ddTHH:mm:ss.fffZ")
|
|
fields = @(
|
|
@{
|
|
name = "Computer"
|
|
value = $ComputerName
|
|
inline = $true
|
|
},
|
|
@{
|
|
name = "Time"
|
|
value = Get-Date -Format "yyyy-MM-dd HH:mm:ss"
|
|
inline = $true
|
|
}
|
|
)
|
|
}
|
|
|
|
$payload = @{
|
|
embeds = @($embed)
|
|
} | ConvertTo-Json -Depth 3
|
|
|
|
try {
|
|
$response = Invoke-RestMethod -Uri $WebhookUrl -Method Post -Body $payload -ContentType "application/json"
|
|
Write-Log "Discord notification sent successfully"
|
|
return $true
|
|
} catch {
|
|
Write-Log "Failed to send Discord notification: $($_.Exception.Message)"
|
|
return $false
|
|
}
|
|
}
|
|
|
|
# Function to get system uptime
|
|
function Get-SystemUptime {
|
|
$uptime = (Get-CimInstance -ClassName Win32_OperatingSystem).LastBootUpTime
|
|
$uptimeDuration = (Get-Date) - $uptime
|
|
return @{
|
|
LastBoot = $uptime.ToString("yyyy-MM-dd HH:mm:ss")
|
|
Uptime = "{0} days, {1} hours, {2} minutes" -f $uptimeDuration.Days, $uptimeDuration.Hours, $uptimeDuration.Minutes
|
|
}
|
|
}
|
|
|
|
# Function to detect reboot reason
|
|
function Get-RebootReason {
|
|
try {
|
|
$shutdownEvent = Get-WinEvent -FilterHashtable @{LogName='System'; ID=1074} -MaxEvents 1 -ErrorAction SilentlyContinue
|
|
if ($shutdownEvent) {
|
|
$message = $shutdownEvent.Message
|
|
if ($message -match "Windows Update") {
|
|
return "Windows Update"
|
|
} elseif ($message -match "power") {
|
|
return "Power related"
|
|
} elseif ($message -match "user") {
|
|
return "User initiated"
|
|
}
|
|
}
|
|
|
|
# Check for unexpected shutdowns
|
|
$unexpectedEvent = Get-WinEvent -FilterHashtable @{LogName='System'; ID=6008} -MaxEvents 1 -ErrorAction SilentlyContinue
|
|
if ($unexpectedEvent) {
|
|
return "Unexpected shutdown (possible power loss)"
|
|
}
|
|
|
|
return "Unknown reason"
|
|
} catch {
|
|
Write-Log "Error getting reboot reason: $($_.Exception.Message)"
|
|
return "Unable to determine"
|
|
}
|
|
}
|
|
|
|
# Main script logic
|
|
Write-Log "Windows Reboot Monitor started - Event: $EventType"
|
|
|
|
# Load configuration
|
|
$config = Get-Configuration
|
|
if (-not $config) {
|
|
$config = @{
|
|
LastStartup = $null
|
|
LastShutdown = $null
|
|
StartupCount = 0
|
|
WebhookUrl = $WebhookUrl
|
|
}
|
|
}
|
|
|
|
# Use webhook from config if not provided as parameter
|
|
if ([string]::IsNullOrEmpty($WebhookUrl) -and $config.WebhookUrl) {
|
|
$WebhookUrl = $config.WebhookUrl
|
|
}
|
|
|
|
# Update webhook URL in config if provided
|
|
if (-not [string]::IsNullOrEmpty($WebhookUrl)) {
|
|
$config.WebhookUrl = $WebhookUrl
|
|
}
|
|
|
|
switch ($EventType) {
|
|
"startup" {
|
|
Write-Log "System startup detected"
|
|
|
|
$config.StartupCount++
|
|
$config.LastStartup = Get-Date -Format "yyyy-MM-dd HH:mm:ss"
|
|
|
|
# Get system information
|
|
$uptimeInfo = Get-SystemUptime()
|
|
$rebootReason = Get-RebootReason()
|
|
|
|
# Check if this is after an unexpected shutdown
|
|
$wasUnexpected = $false
|
|
if ($config.LastShutdown -eq $null -or $rebootReason -match "Unexpected|power") {
|
|
$wasUnexpected = $true
|
|
}
|
|
|
|
$message = if ($wasUnexpected) {
|
|
"🔴 **UNEXPECTED REBOOT DETECTED**`n`nSystem has restarted after an unexpected shutdown.`n`n**Possible cause:** $rebootReason`n**Boot time:** $($uptimeInfo.LastBoot)"
|
|
} else {
|
|
"🟢 **System Started**`n`nWindows machine is now online.`n`n**Reason:** $rebootReason`n**Boot time:** $($uptimeInfo.LastBoot)`n**Startup #:** $($config.StartupCount)"
|
|
}
|
|
|
|
$color = if ($wasUnexpected) { "15158332" } else { "3066993" } # Red for unexpected, blue for normal
|
|
|
|
Send-DiscordNotification -WebhookUrl $WebhookUrl -Message $message -Color $color
|
|
}
|
|
|
|
"shutdown" {
|
|
Write-Log "System shutdown detected"
|
|
|
|
$config.LastShutdown = Get-Date -Format "yyyy-MM-dd HH:mm:ss"
|
|
|
|
$uptimeInfo = Get-SystemUptime()
|
|
$rebootReason = Get-RebootReason()
|
|
|
|
$message = "🟡 **System Shutting Down**`n`nWindows machine is going offline.`n`n**Reason:** $rebootReason`n**Uptime:** $($uptimeInfo.Uptime)"
|
|
|
|
Send-DiscordNotification -WebhookUrl $WebhookUrl -Message $message -Color "16776960" # Yellow
|
|
}
|
|
}
|
|
|
|
# Save updated configuration
|
|
Save-Configuration -config $config
|
|
|
|
Write-Log "Windows Reboot Monitor completed - Event: $EventType" |