[{"data":1,"prerenderedAt":2160},["ShallowReactive",2],{"post:\u002F2025\u002F11\u002F12\u002Fpowershell-scom-alert-when-a-custom-event-log-source-goes-silent\u002F":3},{"post":4,"newer":2107,"older":2116,"related":2128,"series":2158},{"id":5,"title":6,"body":7,"canonical":2089,"categories":2090,"date":2093,"description":2094,"extension":2095,"featured":2096,"hero":2097,"image":2097,"meta":2098,"navigation":1052,"path":2099,"readingTime":506,"seo":2100,"series":2097,"seriesOrder":2097,"sites":2101,"source":2097,"stem":2102,"tags":2103,"updated":2097,"url":2105,"__hash__":2106},"blog\u002Fblog\u002F2025\u002F11\u002F12\u002Fpowershell-scom-alert-when-a-custom-event-log-source-goes-silent.md","PowerShell: SCOM – Alert When a Custom Event Log Source Goes Silent",{"type":8,"value":9,"toc":2081},"minimark",[10,24,43,48,100,104,229,233,236,276,279,328,331,339,345,352,541,544,634,640,746,750,1964,1968,2028,2032,2077],[11,12,13,14,18,19,23],"p",{},"SCOM is very good at alerting on an event that happens. Alerting on an event that stops happening takes more thought, and it's exactly the failure mode of a backup agent, a sync job, or any homegrown service that writes a heartbeat entry to the Application log on success and simply goes quiet on failure. Operations Manager does have a native ",[15,16,17],"strong",{},"Missing Event"," monitor type: Microsoft's management pack authoring guide describes it as detecting \"an error state from an expected event not being detected in a particular time window\", with the example of a nightly transfer that must log success between 2:00 and 3:00 AM. That works well for a job with a fixed schedule and a known event ID. It fits less well when the rule is \"this source must log ",[20,21,22],"em",{},"something"," at least every 90 minutes, on these twelve servers, each with a different source name and threshold\", and you'd rather change a scheduled task parameter than author and seal another monitor.",[11,25,26,27,30,31,34,35,38,39,42],{},"For that case I run a small watchdog on the monitored server. It checks when the watched source last wrote any event, and if that's older than the threshold it writes an ",[15,28,29],{},"Error"," event under its own source. When the source starts logging again it writes an ",[15,32,33],{},"Information"," \"recovered\" event. A single SCOM unit monitor with ",[20,36,37],{},"Simple Event Detection"," and ",[20,40,41],{},"Windows Event Reset"," turns that pair into a health state that goes red and back to green on its own, with an alert that auto-resolves.",[44,45,47],"h2",{"id":46},"requirements","Requirements",[49,50,51,74,84,87,93],"ul",{},[52,53,54,57,58,38,62,65,66,69,70,73],"li",{},[15,55,56],{},"Windows PowerShell 5.1"," on the monitored server. The script uses ",[59,60,61],"code",{},"New-EventLog",[59,63,64],{},"Write-EventLog",", and Microsoft removed the ",[59,67,68],{},"*-EventLog"," cmdlets from PowerShell 6 and later, so it won't run under ",[59,71,72],{},"pwsh",".",[52,75,76,77,79,80,83],{},"Local administrator rights once, to register the alert source with ",[59,78,61],{}," before the task first runs (see Usage). After that the script runs fine as a Scheduled Task under SYSTEM. It checks for its source by reading that one log's registry key rather than calling ",[59,81,82],{},"[System.Diagnostics.EventLog]::SourceExists()",", which has to search every log including Security, and which Microsoft documents as failing under LocalSystem.",[52,85,86],{},"A SCOM agent on the server, reporting to a management group, and the unit monitor described under Usage, created in an unsealed management pack.",[52,88,89,90,73],{},"A Scheduled Task that runs the script on an interval noticeably shorter than ",[59,91,92],{},"MaxSilenceMinutes",[52,94,95,96,99],{},"Optional, for checking alerts from a management server: the ",[59,97,98],{},"OperationsManager"," PowerShell module (installed with the Operations console).",[44,101,103],{"id":102},"parameters","Parameters",[105,106,107,126],"table",{},[108,109,110],"thead",{},[111,112,113,117,120,123],"tr",{},[114,115,116],"th",{},"Name",[114,118,119],{},"Type",[114,121,122],{},"Required",[114,124,125],{},"Description",[127,128,129,146,160,178,195,212],"tbody",{},[111,130,131,137,140,143],{},[132,133,134],"td",{},[59,135,136],{},"SourceName",[132,138,139],{},"String",[132,141,142],{},"Yes",[132,144,145],{},"Event source (provider name) of the application being watched, as it appears in the log.",[111,147,148,152,155,157],{},[132,149,150],{},[59,151,92],{},[132,153,154],{},"Int",[132,156,142],{},[132,158,159],{},"How long the source can go without writing an event before it's considered silent.",[111,161,162,167,169,172],{},[132,163,164],{},[59,165,166],{},"LogName",[132,168,139],{},[132,170,171],{},"No",[132,173,174,175,73],{},"Log the watched source writes to, and the log the watchdog writes into. Defaults to ",[59,176,177],{},"Application",[111,179,180,185,187,189],{},[132,181,182],{},[59,183,184],{},"AlertSource",[132,186,139],{},[132,188,171],{},[132,190,191,192,73],{},"Event source the script registers and writes its own events under. Defaults to ",[59,193,194],{},"CustomSourceWatchdog",[111,196,197,202,204,206],{},[132,198,199],{},[59,200,201],{},"AlertEventId",[132,203,154],{},[132,205,171],{},[132,207,208,209,73],{},"Event ID of the Error event written when the source is silent. Defaults to ",[59,210,211],{},"9999",[111,213,214,219,221,223],{},[132,215,216],{},[59,217,218],{},"RecoveryEventId",[132,220,154],{},[132,222,171],{},[132,224,225,226,73],{},"Event ID of the Information event written when a silent source starts logging again. Defaults to ",[59,227,228],{},"9998",[44,230,232],{"id":231},"usage","Usage",[11,234,235],{},"Check a backup agent that should log something at least every 90 minutes:",[237,238,243],"pre",{"className":239,"code":240,"language":241,"meta":242,"style":242},"language-powershell shiki shiki-themes github-dark",".\\Test-EventSourceHeartbeat.ps1 -SourceName \"ContosoBackupAgent\" -MaxSilenceMinutes 90\n","powershell","",[59,244,245],{"__ignoreMap":242},[246,247,250,253,257,261,264,268,270,273],"span",{"class":248,"line":249},"line",1,[246,251,73],{"class":252},"s95oV",[246,254,256],{"class":255},"sDLfK","\\Test-EventSourceHeartbeat.ps1",[246,258,260],{"class":259},"snl16"," -",[246,262,263],{"class":252},"SourceName ",[246,265,267],{"class":266},"sU2Wk","\"ContosoBackupAgent\"",[246,269,260],{"class":259},[246,271,272],{"class":252},"MaxSilenceMinutes ",[246,274,275],{"class":255},"90\n",[11,277,278],{},"Give a second application its own alert source and ID pair, so the two show up as separate monitors and alerts:",[237,280,282],{"className":239,"code":281,"language":241,"meta":242,"style":242},".\\Test-EventSourceHeartbeat.ps1 -SourceName \"NightlySyncJob\" -MaxSilenceMinutes 120 -AlertSource \"SyncJobWatchdog\" -AlertEventId 9500 -RecoveryEventId 9501\n",[59,283,284],{"__ignoreMap":242},[246,285,286,288,290,292,294,297,299,301,304,306,309,312,314,317,320,322,325],{"class":248,"line":249},[246,287,73],{"class":252},[246,289,256],{"class":255},[246,291,260],{"class":259},[246,293,263],{"class":252},[246,295,296],{"class":266},"\"NightlySyncJob\"",[246,298,260],{"class":259},[246,300,272],{"class":252},[246,302,303],{"class":255},"120",[246,305,260],{"class":259},[246,307,308],{"class":252},"AlertSource ",[246,310,311],{"class":266},"\"SyncJobWatchdog\"",[246,313,260],{"class":259},[246,315,316],{"class":252},"AlertEventId ",[246,318,319],{"class":255},"9500",[246,321,260],{"class":259},[246,323,324],{"class":252},"RecoveryEventId ",[246,326,327],{"class":255},"9501\n",[11,329,330],{},"Sample output when the source has gone silent, and on the next run after it recovers:",[237,332,337],{"className":333,"code":335,"language":336,"meta":242},[334],"language-text","Last event from 'ContosoBackupAgent' was at 2025-11-11 22:14:07, 143.2 minutes ago.\nThreshold of 90 minutes exceeded. Wrote event 9999 (Error) under source 'CustomSourceWatchdog'.\n","text",[59,338,335],{"__ignoreMap":242},[237,340,343],{"className":341,"code":342,"language":336,"meta":242},[334],"Last event from 'ContosoBackupAgent' was at 2025-11-12 00:41:55, 3.4 minutes ago.\nSource recovered. Wrote event 9998 (Information) under source 'CustomSourceWatchdog'.\n",[59,344,342],{"__ignoreMap":242},[11,346,347,348,351],{},"Register the alert source, then the Scheduled Task that runs as SYSTEM every 15 minutes (run once, elevated). Registering the source here rather than on the task's first run matters because Windows needs a moment to enable a new source before events can be written under it. ",[59,349,350],{},"-RepetitionDuration"," is set explicitly to ten years so the repetition doesn't stop:",[237,353,355],{"className":239,"code":354,"language":241,"meta":242,"style":242},"New-EventLog -LogName \"Application\" -Source \"CustomSourceWatchdog\"\n$action = New-ScheduledTaskAction -Execute \"powershell.exe\" -Argument '-NoProfile -ExecutionPolicy Bypass -File \"C:\\Scripts\\Test-EventSourceHeartbeat.ps1\" -SourceName \"ContosoBackupAgent\" -MaxSilenceMinutes 90'\n$trigger = New-ScheduledTaskTrigger -Once -At (Get-Date).AddMinutes(1) -RepetitionInterval (New-TimeSpan -Minutes 15) -RepetitionDuration (New-TimeSpan -Days 3650)\n$principal = New-ScheduledTaskPrincipal -UserId \"SYSTEM\" -LogonType ServiceAccount -RunLevel Highest\nRegister-ScheduledTask -TaskName \"Heartbeat - ContosoBackupAgent\" -Action $action -Trigger $trigger -Principal $principal -Description \"Writes SCOM watchdog events when ContosoBackupAgent goes silent\"\n",[59,356,357,377,405,475,504],{"__ignoreMap":242},[246,358,359,361,363,366,369,371,374],{"class":248,"line":249},[246,360,61],{"class":255},[246,362,260],{"class":259},[246,364,365],{"class":252},"LogName ",[246,367,368],{"class":266},"\"Application\"",[246,370,260],{"class":259},[246,372,373],{"class":252},"Source ",[246,375,376],{"class":266},"\"CustomSourceWatchdog\"\n",[246,378,380,383,386,389,391,394,397,399,402],{"class":248,"line":379},2,[246,381,382],{"class":252},"$action ",[246,384,385],{"class":259},"=",[246,387,388],{"class":255}," New-ScheduledTaskAction",[246,390,260],{"class":259},[246,392,393],{"class":252},"Execute ",[246,395,396],{"class":266},"\"powershell.exe\"",[246,398,260],{"class":259},[246,400,401],{"class":252},"Argument ",[246,403,404],{"class":266},"'-NoProfile -ExecutionPolicy Bypass -File \"C:\\Scripts\\Test-EventSourceHeartbeat.ps1\" -SourceName \"ContosoBackupAgent\" -MaxSilenceMinutes 90'\n",[246,406,408,411,413,416,418,421,424,427,430,433,436,439,441,444,447,449,452,455,457,459,462,464,466,469,472],{"class":248,"line":407},3,[246,409,410],{"class":252},"$trigger ",[246,412,385],{"class":259},[246,414,415],{"class":255}," New-ScheduledTaskTrigger",[246,417,260],{"class":259},[246,419,420],{"class":252},"Once ",[246,422,423],{"class":259},"-",[246,425,426],{"class":252},"At (",[246,428,429],{"class":255},"Get-Date",[246,431,432],{"class":252},").AddMinutes(",[246,434,435],{"class":255},"1",[246,437,438],{"class":252},") ",[246,440,423],{"class":259},[246,442,443],{"class":252},"RepetitionInterval (",[246,445,446],{"class":255},"New-TimeSpan",[246,448,260],{"class":259},[246,450,451],{"class":252},"Minutes ",[246,453,454],{"class":255},"15",[246,456,438],{"class":252},[246,458,423],{"class":259},[246,460,461],{"class":252},"RepetitionDuration (",[246,463,446],{"class":255},[246,465,260],{"class":259},[246,467,468],{"class":252},"Days ",[246,470,471],{"class":255},"3650",[246,473,474],{"class":252},")\n",[246,476,478,481,483,486,488,491,494,496,499,501],{"class":248,"line":477},4,[246,479,480],{"class":252},"$principal ",[246,482,385],{"class":259},[246,484,485],{"class":255}," New-ScheduledTaskPrincipal",[246,487,260],{"class":259},[246,489,490],{"class":252},"UserId ",[246,492,493],{"class":266},"\"SYSTEM\"",[246,495,260],{"class":259},[246,497,498],{"class":252},"LogonType ServiceAccount ",[246,500,423],{"class":259},[246,502,503],{"class":252},"RunLevel Highest\n",[246,505,507,510,512,515,518,520,523,525,528,530,533,535,538],{"class":248,"line":506},5,[246,508,509],{"class":255},"Register-ScheduledTask",[246,511,260],{"class":259},[246,513,514],{"class":252},"TaskName ",[246,516,517],{"class":266},"\"Heartbeat - ContosoBackupAgent\"",[246,519,260],{"class":259},[246,521,522],{"class":252},"Action $action ",[246,524,423],{"class":259},[246,526,527],{"class":252},"Trigger $trigger ",[246,529,423],{"class":259},[246,531,532],{"class":252},"Principal $principal ",[246,534,423],{"class":259},[246,536,537],{"class":252},"Description ",[246,539,540],{"class":266},"\"Writes SCOM watchdog events when ContosoBackupAgent goes silent\"\n",[11,542,543],{},"Create the monitor in the Operations console (once per alert source and ID pair):",[545,546,547,566,577,584,604,619],"ol",{},[52,548,549,552,553,552,556,559,560,552,563,73],{},[15,550,551],{},"Authoring"," > ",[15,554,555],{},"Management Pack Objects",[15,557,558],{},"Monitors",", right-click, ",[15,561,562],{},"Create a Monitor",[15,564,565],{},"Unit Monitor",[52,567,568,569,552,572,552,574,576],{},"Choose ",[15,570,571],{},"Windows Events",[15,573,37],{},[15,575,41],{},", and select an unsealed management pack.",[52,578,579,580,583],{},"Target a class that exists on the servers you're watching, for example ",[15,581,582],{},"Windows Server Operating System",", and leave the monitor disabled if you'll enable it only for a group of servers with an override.",[52,585,586,589,590,592,593,596,597,38,599,596,602,73],{},[15,587,588],{},"Unhealthy event",": log ",[59,591,177],{},", expression ",[20,594,595],{},"Event ID"," equals ",[59,598,211],{},[20,600,601],{},"Event Source",[59,603,194],{},[52,605,606,589,609,592,611,596,613,38,615,596,617,73],{},[15,607,608],{},"Healthy event",[59,610,177],{},[20,612,595],{},[59,614,228],{},[20,616,601],{},[59,618,194],{},[52,620,621,622,625,626,629,630,633],{},"Map the unhealthy state to ",[15,623,624],{},"Critical"," (or ",[15,627,628],{},"Warning","), tick ",[15,631,632],{},"Generate alerts for this monitor",", and keep the alert set to resolve automatically when the monitor returns to healthy.",[11,635,636,637,639],{},"Confirm the alert from a management server with the ",[59,638,98],{}," module:",[237,641,643],{"className":239,"code":642,"language":241,"meta":242,"style":242},"Import-Module OperationsManager\nGet-SCOMAlert -Criteria \"ResolutionState != 255 and LastModified > '$((Get-Date).AddHours(-4))'\" |\n    Where-Object { $_.Name -eq \"\u003Calert name from the monitor>\" } |\n    Select-Object -Property Name, MonitoringObjectDisplayName, Severity, TimeRaised, ResolutionState\n",[59,644,645,653,689,715],{"__ignoreMap":242},[246,646,647,650],{"class":248,"line":249},[246,648,649],{"class":255},"Import-Module",[246,651,652],{"class":252}," OperationsManager\n",[246,654,655,658,660,663,666,669,672,674,677,680,683,686],{"class":248,"line":379},[246,656,657],{"class":255},"Get-SCOMAlert",[246,659,260],{"class":259},[246,661,662],{"class":252},"Criteria ",[246,664,665],{"class":266},"\"ResolutionState != 255 and LastModified > '",[246,667,668],{"class":259},"$",[246,670,671],{"class":266},"((",[246,673,429],{"class":255},[246,675,676],{"class":266},").AddHours(",[246,678,679],{"class":255},"-4",[246,681,682],{"class":266},"))",[246,684,685],{"class":266},"'\"",[246,687,688],{"class":259}," |\n",[246,690,691,694,697,700,703,706,709,712],{"class":248,"line":407},[246,692,693],{"class":255},"    Where-Object",[246,695,696],{"class":252}," { ",[246,698,699],{"class":255},"$_",[246,701,702],{"class":252},".Name ",[246,704,705],{"class":259},"-eq",[246,707,708],{"class":266}," \"\u003Calert name from the monitor>\"",[246,710,711],{"class":252}," } ",[246,713,714],{"class":259},"|\n",[246,716,717,720,722,725,728,731,733,736,738,741,743],{"class":248,"line":477},[246,718,719],{"class":255},"    Select-Object",[246,721,260],{"class":259},[246,723,724],{"class":252},"Property Name",[246,726,727],{"class":259},",",[246,729,730],{"class":252}," MonitoringObjectDisplayName",[246,732,727],{"class":259},[246,734,735],{"class":252}," Severity",[246,737,727],{"class":259},[246,739,740],{"class":252}," TimeRaised",[246,742,727],{"class":259},[246,744,745],{"class":252}," ResolutionState\n",[44,747,749],{"id":748},"script","Script",[237,751,753],{"className":239,"code":752,"language":241,"meta":242,"style":242},"\u003C#\n.SYNOPSIS\n    Writes SCOM-ready events when a custom event log source stops logging, and when it recovers.\n.DESCRIPTION\n    Finds the most recent event written by a given event source and compares its timestamp against a\n    silence threshold. If the source has never logged, or its last event is older than the threshold,\n    the script writes an Error event (AlertEventId) under a separate alert source. If the source is\n    healthy and the watchdog's own last event was that Error, it writes an Information event\n    (RecoveryEventId) so a SCOM Windows Event Reset monitor returns to healthy. Intended to run on a\n    schedule on the monitored server under Windows PowerShell 5.1.\n.PARAMETER SourceName\n    Event source (provider name) of the application being watched.\n.PARAMETER MaxSilenceMinutes\n    How long the source can go without writing an event before it is considered silent.\n.PARAMETER LogName\n    Log the watched source writes to, and the log the watchdog writes into. Defaults to Application.\n.PARAMETER AlertSource\n    Event source the script registers and writes its own events under. Defaults to CustomSourceWatchdog.\n.PARAMETER AlertEventId\n    Event ID of the Error event written when the source is silent. Defaults to 9999.\n.PARAMETER RecoveryEventId\n    Event ID of the Information event written when a silent source starts logging again. Defaults to 9998.\n.EXAMPLE\n    .\\Test-EventSourceHeartbeat.ps1 -SourceName \"ContosoBackupAgent\" -MaxSilenceMinutes 90\n.NOTES\n    Author  : Thomas Lasswell (https:\u002F\u002Fwww.techcolumnist.com)\n    Version : 1.0 (2025-11-12)\n    Requires: Windows PowerShell 5.1, local administrator rights to register the alert event source\n              (register it once, elevated, before scheduling the script)\n#>\n#Requires -Version 5.1\n#Requires -PSEdition Desktop\n[CmdletBinding()]\nparam (\n    [Parameter(Mandatory = $true)]\n    [string]$SourceName,\n\n    [Parameter(Mandatory = $true)]\n    [ValidateRange(1, 10080)]\n    [int]$MaxSilenceMinutes,\n\n    [Parameter(Mandatory = $false)]\n    [string]$LogName = \"Application\",\n\n    [Parameter(Mandatory = $false)]\n    [string]$AlertSource = \"CustomSourceWatchdog\",\n\n    [Parameter(Mandatory = $false)]\n    [ValidateRange(1, 65535)]\n    [int]$AlertEventId = 9999,\n\n    [Parameter(Mandatory = $false)]\n    [ValidateRange(1, 65535)]\n    [int]$RecoveryEventId = 9998\n)\n\nif ($AlertEventId -eq $RecoveryEventId) {\n    throw \"AlertEventId and RecoveryEventId must be different.\"\n}\n\n# Register the watchdog's own source if setup didn't. Test the one registry key instead of calling\n# SourceExists, which searches every log (including Security) and is documented to fail under LocalSystem.\nif (-not (Test-Path -Path \"HKLM:\\SYSTEM\\CurrentControlSet\\Services\\EventLog\\$LogName\\$AlertSource\")) {\n    New-EventLog -LogName $LogName -Source $AlertSource\n}\n\n$lastEvent = Get-WinEvent -FilterHashtable @{ LogName = $LogName; ProviderName = $SourceName } -MaxEvents 1 -ErrorAction SilentlyContinue\n$lastWatchdogEvent = Get-WinEvent -FilterHashtable @{ LogName = $LogName; ProviderName = $AlertSource } -MaxEvents 1 -ErrorAction SilentlyContinue\n$now = Get-Date\n\nif (-not $lastEvent) {\n    $message = \"Source '$SourceName' has no events in the '$LogName' log at all. Either it has never run on $env:COMPUTERNAME, the log has rolled over since, or the source name is wrong.\"\n    Write-Warning $message\n    Write-EventLog -LogName $LogName -Source $AlertSource -EventId $AlertEventId -EntryType Error -Message $message\n    return\n}\n\n$silentMinutes = [math]::Round(($now - $lastEvent.TimeCreated).TotalMinutes, 1)\nWrite-Host \"Last event from '$SourceName' was at $($lastEvent.TimeCreated.ToString('yyyy-MM-dd HH:mm:ss')), $silentMinutes minutes ago.\"\n\nif ($silentMinutes -gt $MaxSilenceMinutes) {\n    $message = \"Source '$SourceName' on $env:COMPUTERNAME has been silent for $silentMinutes minutes, exceeding the $MaxSilenceMinutes minute threshold. Last event: ID $($lastEvent.Id) at $($lastEvent.TimeCreated.ToString('yyyy-MM-dd HH:mm:ss')).\"\n    Write-EventLog -LogName $LogName -Source $AlertSource -EventId $AlertEventId -EntryType Error -Message $message\n    Write-Host \"Threshold of $MaxSilenceMinutes minutes exceeded. Wrote event $AlertEventId (Error) under source '$AlertSource'.\"\n    return\n}\n\n# Healthy. Only write a recovery event if the watchdog's last word was an alert, to keep the log quiet.\nif ($lastWatchdogEvent -and $lastWatchdogEvent.Id -eq $AlertEventId) {\n    $message = \"Source '$SourceName' on $env:COMPUTERNAME is logging again. Last event: ID $($lastEvent.Id) at $($lastEvent.TimeCreated.ToString('yyyy-MM-dd HH:mm:ss')).\"\n    Write-EventLog -LogName $LogName -Source $AlertSource -EventId $RecoveryEventId -EntryType Information -Message $message\n    Write-Host \"Source recovered. Wrote event $RecoveryEventId (Information) under source '$AlertSource'.\"\n} else {\n    Write-Host \"Within threshold. No event written.\"\n}\n",[59,754,755,761,768,773,780,785,791,797,803,809,815,826,832,842,848,858,864,874,880,890,896,906,912,920,926,934,940,946,952,958,964,977,988,1000,1009,1033,1047,1054,1071,1090,1103,1108,1126,1143,1148,1165,1182,1187,1204,1222,1239,1244,1261,1278,1293,1298,1303,1317,1326,1332,1337,1343,1349,1388,1404,1409,1414,1458,1495,1506,1511,1523,1556,1565,1595,1601,1606,1611,1640,1677,1682,1696,1758,1783,1808,1813,1818,1823,1829,1848,1894,1921,1939,1951,1959],{"__ignoreMap":242},[246,756,757],{"class":248,"line":249},[246,758,760],{"class":759},"sAwPA","\u003C#\n",[246,762,763,765],{"class":248,"line":379},[246,764,73],{"class":255},[246,766,767],{"class":259},"SYNOPSIS\n",[246,769,770],{"class":248,"line":407},[246,771,772],{"class":759},"    Writes SCOM-ready events when a custom event log source stops logging, and when it recovers.\n",[246,774,775,777],{"class":248,"line":477},[246,776,73],{"class":255},[246,778,779],{"class":259},"DESCRIPTION\n",[246,781,782],{"class":248,"line":506},[246,783,784],{"class":759},"    Finds the most recent event written by a given event source and compares its timestamp against a\n",[246,786,788],{"class":248,"line":787},6,[246,789,790],{"class":759},"    silence threshold. If the source has never logged, or its last event is older than the threshold,\n",[246,792,794],{"class":248,"line":793},7,[246,795,796],{"class":759},"    the script writes an Error event (AlertEventId) under a separate alert source. If the source is\n",[246,798,800],{"class":248,"line":799},8,[246,801,802],{"class":759},"    healthy and the watchdog's own last event was that Error, it writes an Information event\n",[246,804,806],{"class":248,"line":805},9,[246,807,808],{"class":759},"    (RecoveryEventId) so a SCOM Windows Event Reset monitor returns to healthy. Intended to run on a\n",[246,810,812],{"class":248,"line":811},10,[246,813,814],{"class":759},"    schedule on the monitored server under Windows PowerShell 5.1.\n",[246,816,818,820,823],{"class":248,"line":817},11,[246,819,73],{"class":255},[246,821,822],{"class":259},"PARAMETER",[246,824,825],{"class":259}," SourceName\n",[246,827,829],{"class":248,"line":828},12,[246,830,831],{"class":759},"    Event source (provider name) of the application being watched.\n",[246,833,835,837,839],{"class":248,"line":834},13,[246,836,73],{"class":255},[246,838,822],{"class":259},[246,840,841],{"class":259}," MaxSilenceMinutes\n",[246,843,845],{"class":248,"line":844},14,[246,846,847],{"class":759},"    How long the source can go without writing an event before it is considered silent.\n",[246,849,851,853,855],{"class":248,"line":850},15,[246,852,73],{"class":255},[246,854,822],{"class":259},[246,856,857],{"class":259}," LogName\n",[246,859,861],{"class":248,"line":860},16,[246,862,863],{"class":759},"    Log the watched source writes to, and the log the watchdog writes into. Defaults to Application.\n",[246,865,867,869,871],{"class":248,"line":866},17,[246,868,73],{"class":255},[246,870,822],{"class":259},[246,872,873],{"class":259}," AlertSource\n",[246,875,877],{"class":248,"line":876},18,[246,878,879],{"class":759},"    Event source the script registers and writes its own events under. Defaults to CustomSourceWatchdog.\n",[246,881,883,885,887],{"class":248,"line":882},19,[246,884,73],{"class":255},[246,886,822],{"class":259},[246,888,889],{"class":259}," AlertEventId\n",[246,891,893],{"class":248,"line":892},20,[246,894,895],{"class":759},"    Event ID of the Error event written when the source is silent. Defaults to 9999.\n",[246,897,899,901,903],{"class":248,"line":898},21,[246,900,73],{"class":255},[246,902,822],{"class":259},[246,904,905],{"class":259}," RecoveryEventId\n",[246,907,909],{"class":248,"line":908},22,[246,910,911],{"class":759},"    Event ID of the Information event written when a silent source starts logging again. Defaults to 9998.\n",[246,913,915,917],{"class":248,"line":914},23,[246,916,73],{"class":255},[246,918,919],{"class":259},"EXAMPLE\n",[246,921,923],{"class":248,"line":922},24,[246,924,925],{"class":759},"    .\\Test-EventSourceHeartbeat.ps1 -SourceName \"ContosoBackupAgent\" -MaxSilenceMinutes 90\n",[246,927,929,931],{"class":248,"line":928},25,[246,930,73],{"class":255},[246,932,933],{"class":259},"NOTES\n",[246,935,937],{"class":248,"line":936},26,[246,938,939],{"class":759},"    Author  : Thomas Lasswell (https:\u002F\u002Fwww.techcolumnist.com)\n",[246,941,943],{"class":248,"line":942},27,[246,944,945],{"class":759},"    Version : 1.0 (2025-11-12)\n",[246,947,949],{"class":248,"line":948},28,[246,950,951],{"class":759},"    Requires: Windows PowerShell 5.1, local administrator rights to register the alert event source\n",[246,953,955],{"class":248,"line":954},29,[246,956,957],{"class":759},"              (register it once, elevated, before scheduling the script)\n",[246,959,961],{"class":248,"line":960},30,[246,962,963],{"class":759},"#>\n",[246,965,967,970,973],{"class":248,"line":966},31,[246,968,969],{"class":759},"#",[246,971,972],{"class":259},"Requires -Version",[246,974,976],{"class":975},"s9osk"," 5.1\n",[246,978,980,982,985],{"class":248,"line":979},32,[246,981,969],{"class":759},[246,983,984],{"class":259},"Requires -PSEdition",[246,986,987],{"class":975}," Desktop\n",[246,989,991,994,997],{"class":248,"line":990},33,[246,992,993],{"class":252},"[",[246,995,996],{"class":255},"CmdletBinding",[246,998,999],{"class":252},"()]\n",[246,1001,1003,1006],{"class":248,"line":1002},34,[246,1004,1005],{"class":259},"param",[246,1007,1008],{"class":252}," (\n",[246,1010,1012,1015,1018,1021,1024,1027,1030],{"class":248,"line":1011},35,[246,1013,1014],{"class":252},"    [",[246,1016,1017],{"class":255},"Parameter",[246,1019,1020],{"class":252},"(",[246,1022,1023],{"class":975},"Mandatory",[246,1025,1026],{"class":259}," =",[246,1028,1029],{"class":255}," $true",[246,1031,1032],{"class":252},")]\n",[246,1034,1036,1038,1041,1044],{"class":248,"line":1035},36,[246,1037,1014],{"class":252},[246,1039,1040],{"class":259},"string",[246,1042,1043],{"class":252},"]$SourceName",[246,1045,1046],{"class":259},",\n",[246,1048,1050],{"class":248,"line":1049},37,[246,1051,1053],{"emptyLinePlaceholder":1052},true,"\n",[246,1055,1057,1059,1061,1063,1065,1067,1069],{"class":248,"line":1056},38,[246,1058,1014],{"class":252},[246,1060,1017],{"class":255},[246,1062,1020],{"class":252},[246,1064,1023],{"class":975},[246,1066,1026],{"class":259},[246,1068,1029],{"class":255},[246,1070,1032],{"class":252},[246,1072,1074,1076,1079,1081,1083,1085,1088],{"class":248,"line":1073},39,[246,1075,1014],{"class":252},[246,1077,1078],{"class":255},"ValidateRange",[246,1080,1020],{"class":252},[246,1082,435],{"class":255},[246,1084,727],{"class":259},[246,1086,1087],{"class":255}," 10080",[246,1089,1032],{"class":252},[246,1091,1093,1095,1098,1101],{"class":248,"line":1092},40,[246,1094,1014],{"class":252},[246,1096,1097],{"class":259},"int",[246,1099,1100],{"class":252},"]$MaxSilenceMinutes",[246,1102,1046],{"class":259},[246,1104,1106],{"class":248,"line":1105},41,[246,1107,1053],{"emptyLinePlaceholder":1052},[246,1109,1111,1113,1115,1117,1119,1121,1124],{"class":248,"line":1110},42,[246,1112,1014],{"class":252},[246,1114,1017],{"class":255},[246,1116,1020],{"class":252},[246,1118,1023],{"class":975},[246,1120,1026],{"class":259},[246,1122,1123],{"class":255}," $false",[246,1125,1032],{"class":252},[246,1127,1129,1131,1133,1136,1138,1141],{"class":248,"line":1128},43,[246,1130,1014],{"class":252},[246,1132,1040],{"class":259},[246,1134,1135],{"class":252},"]$LogName ",[246,1137,385],{"class":259},[246,1139,1140],{"class":266}," \"Application\"",[246,1142,1046],{"class":259},[246,1144,1146],{"class":248,"line":1145},44,[246,1147,1053],{"emptyLinePlaceholder":1052},[246,1149,1151,1153,1155,1157,1159,1161,1163],{"class":248,"line":1150},45,[246,1152,1014],{"class":252},[246,1154,1017],{"class":255},[246,1156,1020],{"class":252},[246,1158,1023],{"class":975},[246,1160,1026],{"class":259},[246,1162,1123],{"class":255},[246,1164,1032],{"class":252},[246,1166,1168,1170,1172,1175,1177,1180],{"class":248,"line":1167},46,[246,1169,1014],{"class":252},[246,1171,1040],{"class":259},[246,1173,1174],{"class":252},"]$AlertSource ",[246,1176,385],{"class":259},[246,1178,1179],{"class":266}," \"CustomSourceWatchdog\"",[246,1181,1046],{"class":259},[246,1183,1185],{"class":248,"line":1184},47,[246,1186,1053],{"emptyLinePlaceholder":1052},[246,1188,1190,1192,1194,1196,1198,1200,1202],{"class":248,"line":1189},48,[246,1191,1014],{"class":252},[246,1193,1017],{"class":255},[246,1195,1020],{"class":252},[246,1197,1023],{"class":975},[246,1199,1026],{"class":259},[246,1201,1123],{"class":255},[246,1203,1032],{"class":252},[246,1205,1207,1209,1211,1213,1215,1217,1220],{"class":248,"line":1206},49,[246,1208,1014],{"class":252},[246,1210,1078],{"class":255},[246,1212,1020],{"class":252},[246,1214,435],{"class":255},[246,1216,727],{"class":259},[246,1218,1219],{"class":255}," 65535",[246,1221,1032],{"class":252},[246,1223,1225,1227,1229,1232,1234,1237],{"class":248,"line":1224},50,[246,1226,1014],{"class":252},[246,1228,1097],{"class":259},[246,1230,1231],{"class":252},"]$AlertEventId ",[246,1233,385],{"class":259},[246,1235,1236],{"class":255}," 9999",[246,1238,1046],{"class":259},[246,1240,1242],{"class":248,"line":1241},51,[246,1243,1053],{"emptyLinePlaceholder":1052},[246,1245,1247,1249,1251,1253,1255,1257,1259],{"class":248,"line":1246},52,[246,1248,1014],{"class":252},[246,1250,1017],{"class":255},[246,1252,1020],{"class":252},[246,1254,1023],{"class":975},[246,1256,1026],{"class":259},[246,1258,1123],{"class":255},[246,1260,1032],{"class":252},[246,1262,1264,1266,1268,1270,1272,1274,1276],{"class":248,"line":1263},53,[246,1265,1014],{"class":252},[246,1267,1078],{"class":255},[246,1269,1020],{"class":252},[246,1271,435],{"class":255},[246,1273,727],{"class":259},[246,1275,1219],{"class":255},[246,1277,1032],{"class":252},[246,1279,1281,1283,1285,1288,1290],{"class":248,"line":1280},54,[246,1282,1014],{"class":252},[246,1284,1097],{"class":259},[246,1286,1287],{"class":252},"]$RecoveryEventId ",[246,1289,385],{"class":259},[246,1291,1292],{"class":255}," 9998\n",[246,1294,1296],{"class":248,"line":1295},55,[246,1297,474],{"class":252},[246,1299,1301],{"class":248,"line":1300},56,[246,1302,1053],{"emptyLinePlaceholder":1052},[246,1304,1306,1309,1312,1314],{"class":248,"line":1305},57,[246,1307,1308],{"class":259},"if",[246,1310,1311],{"class":252}," ($AlertEventId ",[246,1313,705],{"class":259},[246,1315,1316],{"class":252}," $RecoveryEventId) {\n",[246,1318,1320,1323],{"class":248,"line":1319},58,[246,1321,1322],{"class":259},"    throw",[246,1324,1325],{"class":266}," \"AlertEventId and RecoveryEventId must be different.\"\n",[246,1327,1329],{"class":248,"line":1328},59,[246,1330,1331],{"class":252},"}\n",[246,1333,1335],{"class":248,"line":1334},60,[246,1336,1053],{"emptyLinePlaceholder":1052},[246,1338,1340],{"class":248,"line":1339},61,[246,1341,1342],{"class":759},"# Register the watchdog's own source if setup didn't. Test the one registry key instead of calling\n",[246,1344,1346],{"class":248,"line":1345},62,[246,1347,1348],{"class":759},"# SourceExists, which searches every log (including Security) and is documented to fail under LocalSystem.\n",[246,1350,1352,1354,1357,1360,1362,1365,1367,1370,1373,1376,1379,1382,1385],{"class":248,"line":1351},63,[246,1353,1308],{"class":259},[246,1355,1356],{"class":252}," (",[246,1358,1359],{"class":259},"-not",[246,1361,1356],{"class":252},[246,1363,1364],{"class":255},"Test-Path",[246,1366,260],{"class":259},[246,1368,1369],{"class":252},"Path ",[246,1371,1372],{"class":266},"\"HKLM:\\SYSTEM\\CurrentControlSet\\Services\\EventLog\\",[246,1374,1375],{"class":252},"$LogName",[246,1377,1378],{"class":266},"\\",[246,1380,1381],{"class":252},"$AlertSource",[246,1383,1384],{"class":266},"\"",[246,1386,1387],{"class":252},")) {\n",[246,1389,1391,1394,1396,1399,1401],{"class":248,"line":1390},64,[246,1392,1393],{"class":255},"    New-EventLog",[246,1395,260],{"class":259},[246,1397,1398],{"class":252},"LogName $LogName ",[246,1400,423],{"class":259},[246,1402,1403],{"class":252},"Source $AlertSource\n",[246,1405,1407],{"class":248,"line":1406},65,[246,1408,1331],{"class":252},[246,1410,1412],{"class":248,"line":1411},66,[246,1413,1053],{"emptyLinePlaceholder":1052},[246,1415,1417,1420,1422,1425,1427,1430,1433,1436,1438,1441,1443,1446,1448,1451,1453,1455],{"class":248,"line":1416},67,[246,1418,1419],{"class":252},"$lastEvent ",[246,1421,385],{"class":259},[246,1423,1424],{"class":255}," Get-WinEvent",[246,1426,260],{"class":259},[246,1428,1429],{"class":252},"FilterHashtable ",[246,1431,1432],{"class":259},"@",[246,1434,1435],{"class":252},"{ LogName ",[246,1437,385],{"class":259},[246,1439,1440],{"class":252}," $LogName; ProviderName ",[246,1442,385],{"class":259},[246,1444,1445],{"class":252}," $SourceName } ",[246,1447,423],{"class":259},[246,1449,1450],{"class":252},"MaxEvents ",[246,1452,435],{"class":255},[246,1454,260],{"class":259},[246,1456,1457],{"class":252},"ErrorAction SilentlyContinue\n",[246,1459,1461,1464,1466,1468,1470,1472,1474,1476,1478,1480,1482,1485,1487,1489,1491,1493],{"class":248,"line":1460},68,[246,1462,1463],{"class":252},"$lastWatchdogEvent ",[246,1465,385],{"class":259},[246,1467,1424],{"class":255},[246,1469,260],{"class":259},[246,1471,1429],{"class":252},[246,1473,1432],{"class":259},[246,1475,1435],{"class":252},[246,1477,385],{"class":259},[246,1479,1440],{"class":252},[246,1481,385],{"class":259},[246,1483,1484],{"class":252}," $AlertSource } ",[246,1486,423],{"class":259},[246,1488,1450],{"class":252},[246,1490,435],{"class":255},[246,1492,260],{"class":259},[246,1494,1457],{"class":252},[246,1496,1498,1501,1503],{"class":248,"line":1497},69,[246,1499,1500],{"class":252},"$now ",[246,1502,385],{"class":259},[246,1504,1505],{"class":255}," Get-Date\n",[246,1507,1509],{"class":248,"line":1508},70,[246,1510,1053],{"emptyLinePlaceholder":1052},[246,1512,1514,1516,1518,1520],{"class":248,"line":1513},71,[246,1515,1308],{"class":259},[246,1517,1356],{"class":252},[246,1519,1359],{"class":259},[246,1521,1522],{"class":252}," $lastEvent) {\n",[246,1524,1526,1529,1531,1534,1537,1540,1542,1545,1547,1550,1553],{"class":248,"line":1525},72,[246,1527,1528],{"class":252},"    $message ",[246,1530,385],{"class":259},[246,1532,1533],{"class":266}," \"Source '",[246,1535,1536],{"class":252},"$SourceName",[246,1538,1539],{"class":266},"' has no events in the '",[246,1541,1375],{"class":252},[246,1543,1544],{"class":266},"' log at all. Either it has never run on ",[246,1546,668],{"class":252},[246,1548,1549],{"class":255},"env:",[246,1551,1552],{"class":252},"COMPUTERNAME",[246,1554,1555],{"class":266},", the log has rolled over since, or the source name is wrong.\"\n",[246,1557,1559,1562],{"class":248,"line":1558},73,[246,1560,1561],{"class":255},"    Write-Warning",[246,1563,1564],{"class":252}," $message\n",[246,1566,1568,1571,1573,1575,1577,1580,1582,1585,1587,1590,1592],{"class":248,"line":1567},74,[246,1569,1570],{"class":255},"    Write-EventLog",[246,1572,260],{"class":259},[246,1574,1398],{"class":252},[246,1576,423],{"class":259},[246,1578,1579],{"class":252},"Source $AlertSource ",[246,1581,423],{"class":259},[246,1583,1584],{"class":252},"EventId $AlertEventId ",[246,1586,423],{"class":259},[246,1588,1589],{"class":252},"EntryType Error ",[246,1591,423],{"class":259},[246,1593,1594],{"class":252},"Message $message\n",[246,1596,1598],{"class":248,"line":1597},75,[246,1599,1600],{"class":259},"    return\n",[246,1602,1604],{"class":248,"line":1603},76,[246,1605,1331],{"class":252},[246,1607,1609],{"class":248,"line":1608},77,[246,1610,1053],{"emptyLinePlaceholder":1052},[246,1612,1614,1617,1619,1622,1625,1628,1630,1633,1635,1638],{"class":248,"line":1613},78,[246,1615,1616],{"class":252},"$silentMinutes ",[246,1618,385],{"class":259},[246,1620,1621],{"class":252}," [",[246,1623,1624],{"class":259},"math",[246,1626,1627],{"class":252},"]::Round(($now ",[246,1629,423],{"class":259},[246,1631,1632],{"class":252}," $lastEvent.TimeCreated).TotalMinutes",[246,1634,727],{"class":259},[246,1636,1637],{"class":255}," 1",[246,1639,474],{"class":252},[246,1641,1643,1646,1649,1651,1654,1656,1658,1661,1663,1666,1668,1671,1674],{"class":248,"line":1642},79,[246,1644,1645],{"class":255},"Write-Host",[246,1647,1648],{"class":266}," \"Last event from '",[246,1650,1536],{"class":252},[246,1652,1653],{"class":266},"' was at ",[246,1655,668],{"class":259},[246,1657,1020],{"class":266},[246,1659,1660],{"class":252},"$lastEvent.TimeCreated.ToString",[246,1662,1020],{"class":266},[246,1664,1665],{"class":266},"'yyyy-MM-dd HH:mm:ss'",[246,1667,682],{"class":266},[246,1669,1670],{"class":266},", ",[246,1672,1673],{"class":252},"$silentMinutes",[246,1675,1676],{"class":266}," minutes ago.\"\n",[246,1678,1680],{"class":248,"line":1679},80,[246,1681,1053],{"emptyLinePlaceholder":1052},[246,1683,1685,1687,1690,1693],{"class":248,"line":1684},81,[246,1686,1308],{"class":259},[246,1688,1689],{"class":252}," ($silentMinutes ",[246,1691,1692],{"class":259},"-gt",[246,1694,1695],{"class":252}," $MaxSilenceMinutes) {\n",[246,1697,1699,1701,1703,1705,1707,1710,1712,1714,1716,1719,1721,1724,1727,1730,1732,1734,1737,1740,1743,1745,1747,1749,1751,1753,1755],{"class":248,"line":1698},82,[246,1700,1528],{"class":252},[246,1702,385],{"class":259},[246,1704,1533],{"class":266},[246,1706,1536],{"class":252},[246,1708,1709],{"class":266},"' on ",[246,1711,668],{"class":252},[246,1713,1549],{"class":255},[246,1715,1552],{"class":252},[246,1717,1718],{"class":266}," has been silent for ",[246,1720,1673],{"class":252},[246,1722,1723],{"class":266}," minutes, exceeding the ",[246,1725,1726],{"class":252},"$MaxSilenceMinutes",[246,1728,1729],{"class":266}," minute threshold. Last event: ID ",[246,1731,668],{"class":259},[246,1733,1020],{"class":266},[246,1735,1736],{"class":252},"$lastEvent.Id",[246,1738,1739],{"class":266},")",[246,1741,1742],{"class":266}," at ",[246,1744,668],{"class":259},[246,1746,1020],{"class":266},[246,1748,1660],{"class":252},[246,1750,1020],{"class":266},[246,1752,1665],{"class":266},[246,1754,682],{"class":266},[246,1756,1757],{"class":266},".\"\n",[246,1759,1761,1763,1765,1767,1769,1771,1773,1775,1777,1779,1781],{"class":248,"line":1760},83,[246,1762,1570],{"class":255},[246,1764,260],{"class":259},[246,1766,1398],{"class":252},[246,1768,423],{"class":259},[246,1770,1579],{"class":252},[246,1772,423],{"class":259},[246,1774,1584],{"class":252},[246,1776,423],{"class":259},[246,1778,1589],{"class":252},[246,1780,423],{"class":259},[246,1782,1594],{"class":252},[246,1784,1786,1789,1792,1794,1797,1800,1803,1805],{"class":248,"line":1785},84,[246,1787,1788],{"class":255},"    Write-Host",[246,1790,1791],{"class":266}," \"Threshold of ",[246,1793,1726],{"class":252},[246,1795,1796],{"class":266}," minutes exceeded. Wrote event ",[246,1798,1799],{"class":252},"$AlertEventId",[246,1801,1802],{"class":266}," (Error) under source '",[246,1804,1381],{"class":252},[246,1806,1807],{"class":266},"'.\"\n",[246,1809,1811],{"class":248,"line":1810},85,[246,1812,1600],{"class":259},[246,1814,1816],{"class":248,"line":1815},86,[246,1817,1331],{"class":252},[246,1819,1821],{"class":248,"line":1820},87,[246,1822,1053],{"emptyLinePlaceholder":1052},[246,1824,1826],{"class":248,"line":1825},88,[246,1827,1828],{"class":759},"# Healthy. Only write a recovery event if the watchdog's last word was an alert, to keep the log quiet.\n",[246,1830,1832,1834,1837,1840,1843,1845],{"class":248,"line":1831},89,[246,1833,1308],{"class":259},[246,1835,1836],{"class":252}," ($lastWatchdogEvent ",[246,1838,1839],{"class":259},"-and",[246,1841,1842],{"class":252}," $lastWatchdogEvent.Id ",[246,1844,705],{"class":259},[246,1846,1847],{"class":252}," $AlertEventId) {\n",[246,1849,1851,1853,1855,1857,1859,1861,1863,1865,1867,1870,1872,1874,1876,1878,1880,1882,1884,1886,1888,1890,1892],{"class":248,"line":1850},90,[246,1852,1528],{"class":252},[246,1854,385],{"class":259},[246,1856,1533],{"class":266},[246,1858,1536],{"class":252},[246,1860,1709],{"class":266},[246,1862,668],{"class":252},[246,1864,1549],{"class":255},[246,1866,1552],{"class":252},[246,1868,1869],{"class":266}," is logging again. Last event: ID ",[246,1871,668],{"class":259},[246,1873,1020],{"class":266},[246,1875,1736],{"class":252},[246,1877,1739],{"class":266},[246,1879,1742],{"class":266},[246,1881,668],{"class":259},[246,1883,1020],{"class":266},[246,1885,1660],{"class":252},[246,1887,1020],{"class":266},[246,1889,1665],{"class":266},[246,1891,682],{"class":266},[246,1893,1757],{"class":266},[246,1895,1897,1899,1901,1903,1905,1907,1909,1912,1914,1917,1919],{"class":248,"line":1896},91,[246,1898,1570],{"class":255},[246,1900,260],{"class":259},[246,1902,1398],{"class":252},[246,1904,423],{"class":259},[246,1906,1579],{"class":252},[246,1908,423],{"class":259},[246,1910,1911],{"class":252},"EventId $RecoveryEventId ",[246,1913,423],{"class":259},[246,1915,1916],{"class":252},"EntryType Information ",[246,1918,423],{"class":259},[246,1920,1594],{"class":252},[246,1922,1924,1926,1929,1932,1935,1937],{"class":248,"line":1923},92,[246,1925,1788],{"class":255},[246,1927,1928],{"class":266}," \"Source recovered. Wrote event ",[246,1930,1931],{"class":252},"$RecoveryEventId",[246,1933,1934],{"class":266}," (Information) under source '",[246,1936,1381],{"class":252},[246,1938,1807],{"class":266},[246,1940,1942,1945,1948],{"class":248,"line":1941},93,[246,1943,1944],{"class":252},"} ",[246,1946,1947],{"class":259},"else",[246,1949,1950],{"class":252}," {\n",[246,1952,1954,1956],{"class":248,"line":1953},94,[246,1955,1788],{"class":255},[246,1957,1958],{"class":266}," \"Within threshold. No event written.\"\n",[246,1960,1962],{"class":248,"line":1961},95,[246,1963,1331],{"class":252},[44,1965,1967],{"id":1966},"notes","Notes",[49,1969,1970,1982,1991,1997,2006,2019,2025],{},[52,1971,1972,1975,1976,1978,1979,1981],{},[15,1973,1974],{},"One alert source per watched application."," The recovery logic reads the watchdog's own last event, so two watched applications sharing one ",[59,1977,184],{}," would reset each other. Give each its own ",[59,1980,184],{}," and ID pair, and one monitor per pair, so alerts are distinguishable in the console instead of collapsing into one generic \"something is quiet\" alert.",[52,1983,1984,1987,1988,1990],{},[15,1985,1986],{},"Why a monitor and not a rule."," An alert-generating rule on event 9999 raises an alert every time the event is written, which is every run while the source stays silent, and nothing closes those alerts when the source recovers. A unit monitor changes state once, raises one alert, and with ",[20,1989,41],{}," returns to healthy on event 9998. The management pack authoring guide describes the three reset options: event reset, manual reset (a person must reset health in Health Explorer), and timer reset (automatic reset after a set time).",[52,1992,1993,1996],{},[15,1994,1995],{},"When to use the native Missing Event monitor instead."," If the application has a fixed schedule and logs a known success event, a Missing Event monitor needs no script on the server at all. The watchdog earns its place when thresholds differ per server or you want a rolling \"nothing in N minutes\" window rather than a scheduled one.",[52,1998,1999,2002,2003,2005],{},[15,2000,2001],{},"Silence versus a rolled-over log."," The script looks at what's in the log now. If the Application log is small and busy, the watched source's last event can be overwritten before the threshold is reached, and the watchdog reports \"no events at all\". Size the log so it holds more than ",[59,2004,92],{}," of history.",[52,2007,2008,2011,2012,2014,2015,2018],{},[15,2009,2010],{},"Event IDs."," ",[59,2013,64],{}," accepts IDs up to 65535. Stay clear of IDs the watched application itself uses, and remember that SCOM matches on source ",[20,2016,2017],{},"and"," ID, which is what keeps 9999 from one watchdog from tripping another's monitor.",[52,2020,2021,2024],{},[15,2022,2023],{},"Scheduling."," Run the task at a fraction of the threshold. Every 15 minutes against a 90-minute threshold gives you an alert within 15 minutes of the threshold being crossed, and a recovery within 15 minutes of the source logging again.",[52,2026,2027],{},"This deliberately doesn't touch the SCOM SDK on the monitored server. It writes plain Windows events and lets the agent that's already there, and already reporting to the management servers, do the rest.",[44,2029,2031],{"id":2030},"source","Source",[49,2033,2034,2043,2050,2057,2064,2070],{},[52,2035,2036],{},[2037,2038,2042],"a",{"href":2039,"rel":2040},"https:\u002F\u002Flearn.microsoft.com\u002Fen-us\u002Farchive\u002Ftechnet-wiki\u002F15207.operations-manager-management-pack-authoring-unit-monitors",[2041],"nofollow","Operations Manager management pack authoring: unit monitors (event detection and reset types)",[52,2044,2045],{},[2037,2046,2049],{"href":2047,"rel":2048},"https:\u002F\u002Flearn.microsoft.com\u002Fen-us\u002Farchive\u002Ftechnet-wiki\u002F51547.scom-monitor-a-specific-windows-event",[2041],"SCOM: monitor a specific Windows event (Operations console walkthrough)",[52,2051,2052],{},[2037,2053,2056],{"href":2054,"rel":2055},"https:\u002F\u002Flearn.microsoft.com\u002Fen-us\u002Fpowershell\u002Fmodule\u002Fmicrosoft.powershell.management\u002Fwrite-eventlog?view=powershell-5.1",[2041],"Write-EventLog (Windows PowerShell 5.1)",[52,2058,2059],{},[2037,2060,2063],{"href":2061,"rel":2062},"https:\u002F\u002Flearn.microsoft.com\u002Fen-us\u002Fpowershell\u002Fscripting\u002Fwhats-new\u002Fdifferences-from-windows-powershell",[2041],"Differences between Windows PowerShell 5.1 and PowerShell 7 (removed *-EventLog cmdlets)",[52,2065,2066],{},[2037,2067,657],{"href":2068,"rel":2069},"https:\u002F\u002Flearn.microsoft.com\u002Fen-us\u002Fpowershell\u002Fmodule\u002Foperationsmanager\u002Fget-scomalert",[2041],[52,2071,2072],{},[2037,2073,2076],{"href":2074,"rel":2075},"https:\u002F\u002Flearn.microsoft.com\u002Fen-us\u002Fpowershell\u002Fmodule\u002Fscheduledtasks\u002Fnew-scheduledtasktrigger",[2041],"New-ScheduledTaskTrigger",[2078,2079,2080],"style",{},"html pre.shiki code .s95oV, html code.shiki .s95oV{--shiki-default:#E1E4E8}html pre.shiki code .sDLfK, html code.shiki .sDLfK{--shiki-default:#79B8FF}html pre.shiki code .snl16, html code.shiki .snl16{--shiki-default:#F97583}html pre.shiki code .sU2Wk, html code.shiki .sU2Wk{--shiki-default:#9ECBFF}html .default .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html pre.shiki code .sAwPA, html code.shiki .sAwPA{--shiki-default:#6A737D}html pre.shiki code .s9osk, html code.shiki .s9osk{--shiki-default:#FFAB70}",{"title":242,"searchDepth":379,"depth":379,"links":2082},[2083,2084,2085,2086,2087,2088],{"id":46,"depth":379,"text":47},{"id":102,"depth":379,"text":103},{"id":231,"depth":379,"text":232},{"id":748,"depth":379,"text":749},{"id":1966,"depth":379,"text":1967},{"id":2030,"depth":379,"text":2031},"techcolumnist",[2091,2092],"ps","scripts","2025-11-12T14:00:00Z","A PowerShell watchdog that writes SCOM-ready silent and recovered events when a custom application stops logging, with the unit monitor to catch them.","md",false,null,{},"\u002Fblog\u002F2025\u002F11\u002F12\u002Fpowershell-scom-alert-when-a-custom-event-log-source-goes-silent",{"title":6,"description":2094},[2089],"blog\u002F2025\u002F11\u002F12\u002Fpowershell-scom-alert-when-a-custom-event-log-source-goes-silent",[241,2104],"scom","\u002F2025\u002F11\u002F12\u002Fpowershell-scom-alert-when-a-custom-event-log-source-goes-silent\u002F","W_GggB55y4O89RHJnamtKWK8MDgEAijOOhgS0vJ3xVg",{"title":2108,"description":2109,"date":2110,"url":2111,"categories":2112,"tags":2113,"image":2097,"readingTime":477,"canonical":2089,"sites":2115,"series":2097,"seriesOrder":2097},"PowerShell: Azure – Audit Who Has Owner Role Across All Subscriptions","A script that walks every subscription a credential can see and reports every Owner assignment, active or PIM-eligible, by the scope it was granted at.","2025-11-19T14:00:00Z","\u002F2025\u002F11\u002F19\u002Fpowershell-azure-audit-who-has-owner-role-across-all-subscriptions\u002F",[2091,2092],[241,2114],"azure",[2089],{"title":2117,"description":2118,"date":2119,"url":2120,"categories":2121,"tags":2122,"image":2097,"readingTime":506,"canonical":2089,"sites":2127,"series":2097,"seriesOrder":2097},"PowerShell: Windows 11 – Strip Preinstalled Apps from an Image","A PowerShell script that removes provisioned apps from a mounted Windows 11 WIM or a running system, plus the Windows 11 24H2+ policy that does it natively.","2025-11-05T14:00:00Z","\u002F2025\u002F11\u002F05\u002Fpowershell-windows-11-strip-preinstalled-apps-from-a-deployment-image\u002F",[2091,2092],[241,2123,2124,2125,2126],"windows-11","debloat","gpo","intune",[2089],[2129,2139,2149],{"title":2130,"description":2131,"date":2132,"url":2133,"categories":2134,"tags":2136,"image":2097,"readingTime":249,"canonical":2089,"sites":2137,"series":2097,"seriesOrder":2097},"PowerShell: Schedule a URL into Maintenance Mode","Found a nice article about how to script a URL (or web application) into maintenance mode.","2010-07-07T14:53:54Z","\u002F2010\u002F07\u002F07\u002Fschedule-a-url-into-maintenance-mode\u002F",[2135,2091,2092],"engineering",[2104,748,241],[2138,2089],"lasswell",{"title":2140,"description":2141,"date":2142,"url":2143,"categories":2144,"tags":2145,"image":2097,"readingTime":506,"canonical":2089,"sites":2148,"series":2097,"seriesOrder":2097},"PowerShell: Active Directory – Report Group Membership Sprawl","Rank AD security groups by nesting depth, transitive member count, ownership and staleness for an access review, plus a per-user Kerberos token size estimate.","2025-12-03T14:00:00Z","\u002F2025\u002F12\u002F03\u002Fpowershell-active-directory-report-group-membership-sprawl\u002F",[2091,2092],[241,2146,2147],"active-directory","reporting",[2089],{"title":2150,"description":2151,"date":2152,"url":2153,"categories":2154,"tags":2155,"image":2097,"readingTime":477,"canonical":2089,"sites":2157,"series":2097,"seriesOrder":2097},"PowerShell: Windows Server – Disable SMBv1 Fleet-Wide and Verify","A script that audits SMBv1 access (event 3000), disables the SMBv1 server and optional feature across Windows servers, and reports which ones still need a restart.","2025-11-26T14:00:00Z","\u002F2025\u002F11\u002F26\u002Fpowershell-windows-server-disable-smbv1-fleet-wide-and-verify-it-stuck\u002F",[2091,2092],[241,2156],"windows",[2089],{"doc":2097,"posts":2159},[],1790052513220]