Resolve Rule Alerts with PowerShell

I was working last week on a little PowerShell script to help me clear off old rule alerts but did not get around to posting about it. Then I saw that Scott Moss has just done a post on the same subject.

Well as I have done the work and mine is more of a script with parameters I thought that I would post it anyway. His one line is neat if you want to clear all rule alerts.

get-alert -criteria ‘ResolutionState = ”0” AND IsMonitorAlert = ”False”’| resolve-alert -comment “Closing rule generated alerts” | out-null

Note that these are all single apostrophes done 2 (or 3) times rather than double apostrophes. I have read that criteria is better/faster way to do a large number of objects in PowerShell but my script uses the more popularly used where-object.

Like Scott I found that one of the alert properties is IsMonitorAlert with a value of True or False. This value is not available as a column in the console which is a shame as it would be useful. I have been using Type but I have found that certain MPs put rules into Types that I would associate with monitors so it is not 100% reliable way of sorting alerts from rules and monitors. I am finding more and more uses for PowerShell but this is mainly due to the fact that the console is limited in many areas which need to be fixed.

Monitors should auto resolve when the problem is fixed unless it is a monitor with a manual reset! A parameter for that would also be useful. If the problem is not fixed and you clear the alert it does not generate another alert as Health Explorer is still showing the problem. You have to clear Health Explorer to remove the alert and then if the problem still exists then the alert will be generated again. But in general if a monitor alert is in the console it shows an underlying problem that needs fixed, or the monitor needs to be overridden or the monitor alert has not auto resolved correctly and needs investigation. In any case alerts from monitors are best done through the console.

Rules, on the other hand, always need to be manually resolved. One alert that keeps on coming up is script failures. The first thing I do is change that from Warning to Information. You can get a lot of these but if it is a one off then it is likely that it was trying to run when the server was busy. If it keeps on repeating then the problem needs looking at.

Normally in the console I would sort by last modified date (and group by Type to help) and look for rules that have not incremented their counters for a few days. Not too bad if you are at the customer site each day but if I am away for a while and come back I need to quickly clear the console and so I came up with this script. You can chose how many days and whether or not you want to close the alerts, count them or list them. The number of days is the number of days of alerts to keep.  If you put in 3 then the last 3 days will be kept and everything older will be closed. Note that this gets the date AND time so if you run it at 10 am then it keeps alerts from 10 am 3 days ago. In order to close alerts you must have close as the second parameter to avoid someone accidentally running the script and clearing alerts that they should not have done. Mind you with rules the alert just reappears if there is still a problem.

I prefer just deleting resolution state of 0 as I use different resolution states for different actions but if you want all change that to ($_.ResolutionState -lt 255) in the script and that covers all alerts that are not already closed.

Give the script a name like resolverules.ps1 and cut and paste the following text into it.

#Resolve alerts from rules only – not monitors
# 2 parameters – number of days and close or count
#use 0 for all alerts
#if close or count is not used as the 2nd parameter then alerts will be shown only
#to use close or count then there MUST be a valid number as the first parameter
#if no parameters are used then show all is done i.e. days = 0

param ($noofdays, $action)

$targetdate = (get-date).AddDays(-$noofdays)

If ($action -match “close”)
 get-alert | where-object { ($_.LastModified -lt $targetdate) -and ($_.ResolutionState -eq 0) -and ($_.IsMonitorAlert -match “False”)} | resolve-alert -comment “Resolve-Alert by PowerShell”
ElseIf ($action -match “count”)
 get-alert | where-object { ($_.LastModified -lt $targetdate) -and ($_.ResolutionState -eq 0) -and ($_.IsMonitorAlert -match “false”)} | ForEach-Object {$totalno++}
 get-alert | where-object { ($_.LastModified -lt $targetdate) -and ($_.ResolutionState -eq 0) -and ($_.IsMonitorAlert -match “false”)} | select-object Name, MonitoringObjectDisplayName, IsMonitorAlert, LastModified

Strange Things With The Script

Although Scott’s line uses IsMonitorAlert = ”False” which correctly gives the rules when I tried something similar in my script it gave monitors and so I have had to use ($_.IsMonitorAlert -ne “False”) which seems wrong but gives the correct results. On further investigation it transpires that –ne always gives False regardless of whether you put it equal to true or false and if you use –eq it always returns true regardless of whether you check it against true or false.

In the script I also tried it as
($_.IsMonitorAlert -ne “zzz”)  – this returns False
($_.IsMonitorAlert -eq “zzz”) – this returns True.

But when I used –match instead using True and False work correctly. If  I had used ($_.IsMonitorAlert -ne “True”) it would have worked and I would not have discovered this bug but I started with ($_.IsMonitorAlert -eq “False”) as the logical way to do it but as I have found –eq will always return true.

Just to check I also tried
get-Childitem “C:\Program Files\outlook express”  | where {$_.extension -eq “.exe”}
This works correctly using –eq and –ne.

Mystifying. I changed them all to -match in the script as that looks better.


  1. That script will work, but it won’t work after you hit X number of open alerts – look at my site for a script similar to these from 6 months ago or so. Basically you need to add a second loop to Get-Alert $alert before manipulating it – it’s very possible that by the time you interact with the alert in the pipeline it’s already expired from the allowable time period with which it can be changed, so doing a get-alert beforehand ensures it’s fresh.

  2. “True” and “False” are not strings… they are boolean. Since Powershell automatically converts strings “zzz” to a boolean… then that conversion will evaluate to “true”, since it is different than 0, null, or $false.

    try [bool]”blabla” it will return True
    [bool]”” will return false… 🙂
    magic of .Net types.

    for this reason, $_.IsMonitorAlert -ne “zzz” really means $_.IsMonitorAlert -ne $true

    use $true or $false variables whenever, rather than strings…

%d bloggers like this: