Since I released the Test-ExchangeServerHealth.ps1 script one of the most common feature requests has been to add health checks for Database Availability Groups.
So today I am pleased to announce the availability of v1.0 of Get-DAGHealth.ps1, a Database Availability Group health check PowerShell script.
This is the first release to your feedback and bug reports are welcome in the comments below. I hope to eventually merge this with the Test-ExchangeServerHealth.ps1 script to provide a single, daily health check script that you can use for your Exchange environments.
Please read the usage instructions in below or in the script help info.
Download the script file here: Get-DAGHealth.ps1 (downloaded 2202 times so far)
Running Get-DAGHealth.ps1
The script is written and tested for Exchange Server 2010 and Exchange Server 2013 CU1.
The script requires the Exchange Management Tools to run. You can execute it from the Exchange Management Shell, or a regular PowerShell session and it will add the Exchange snapin if not already loaded.
You can also execute it as a scheduled task. I use the follow settings in my scheduled task to make it work:
- Run whether user is logged on or not
- Run with highest privileges
- Action:
- Start a program: powershell.exe
- Arguments: -command “c:\scripts\daghealth\get-daghealth.ps1 -Detailed -SendEmail”
- You may need to modify your script execution policy to run this script as it is not signed
- You may need to open the Properties of the downloaded file and “unblock” it before it will run
Use Get-Help to see more usage details and examples.
PS C:\Scripts\DAGHealth> get-help .\Get-DAGHealth.ps1 -Examples
NAME
C:\Scripts\DAGHealth\Get-DAGHealth.ps1
SYNOPSIS
Get-DAGHealth.ps1 - Exchange Server 2010 Database Availability Group Health Check Script.
-------------------------- EXAMPLE 1 --------------------------
C:\PS>.\Get-DAGHealth.ps1
Checks all DAGs in the organization and outputs a health summary to the PowerShell window.
-------------------------- EXAMPLE 2 --------------------------
C:\PS>.\Get-DAGHealth.ps1 -Detailed
Checks all DAGs in the organization and outputs a detailed health report to the PowerShell
window. Due to the amount of detail the full report may get cut off in your window. I recommend
detailed reports be output to HTML file or email instead.
-------------------------- EXAMPLE 3 --------------------------
C:\PS>.\Get-DAGHealth.ps1 -Detailed -SendEmail
Checks all DAGs in the organization and outputs a detailed health report via email using
the SMTP settings you configure in the script.
I generally recommend using the HTML file or email output to get the best results. The HTML output gives a color-coded health report to bring to your attention any potential health issues such as databases not active on their first preference server, unhealthy copies or queues, unhealthy content indexes, and other things that can sometimes go unnoticed with DAGs.

The report is indicative only. You should investigate and validate any issues that it flags to determine what if any action is required to resolve them.
Download the script file here: Get-DAGHealth.ps1 (downloaded 2202 times so far)
Change Log:
- V1.0 – 14/02/2013 – Initial release
- V1.1 – 24/04/2013 – Bug fixes, Exchange 2013 compatibility
Feedback and bug reports welcome in the comments below. If you like this script please feel free to share this article with your friends and colleagues on Twitter, Facebook, LinkedIn, Google+ etc. You might also be interested in some of my other PowerShell scripts.




GENIUS!!
Thanks Paul, Another great script
Up and running. So far works just fine. Nice work Paul! No flaws detected yet.
Whoah, can’t wait to give this a run tomorrow
I’m trying to run the DAG Heath Report on the same server I have your previous Health Check report running. When I run the Dag Report, Powershell gives me the following errors, any ideas?
Update-TypeData : The following error occurred while loading the extended type data file:
Microsoft.PowerShell, C:\Program Files\Microsoft\Exchange Server\V14\bin\exchange.types.ps1xml : File skipped because i
t was already present from “Microsoft.PowerShell”.
At C:\Program Files\Microsoft\Exchange Server\V14\bin\RemoteExchange.ps1:94 char:17
+ Update-TypeData <<<< -PrependPath $typeFilePath
+ CategoryInfo : InvalidOperation: (:) [Update-TypeData], RuntimeException
+ FullyQualifiedErrorId : TypesXmlUpdateException,Microsoft.PowerShell.Commands.UpdateTypeDataCommand
Update-TypeData : The following error occurred while loading the extended type data file:
Microsoft.PowerShell, C:\Program Files\Microsoft\Exchange Server\V14\bin\Exchange.partial.Types.ps1xml : File skipped b
ecause it was already present from "Microsoft.PowerShell".
Microsoft.PowerShell, C:\Program Files\Microsoft\Exchange Server\V14\bin\exchange.types.ps1xml : File skipped because i
t was already present from "Microsoft.PowerShell".
At C:\Program Files\Microsoft\Exchange Server\V14\bin\RemoteExchange.ps1:104 char:16
+ Update-TypeData <<<< -PrependPath $partialTypeFile
+ CategoryInfo : InvalidOperation: (:) [Update-TypeData], RuntimeException
+ FullyQualifiedErrorId : TypesXmlUpdateException,Microsoft.PowerShell.Commands.UpdateTypeDataCommand
Thanks. I believe that is a harmless bug during the script initialization that can be ignored, but let me know if you’re also not getting any results at all from the script when it finishes. In the mean time I’ll try to squash that bug.
It seems to be working fine, great script.
Thanks paul
great script….
Thank you very much, Paul, for sharing your work! Awesome!
For your information, and I guess you already know, when running the script, the following errors are displayed, though the script is executing perfectly.
Update-TypeData : The following error occurred while loading the extended type data file:
Microsoft.PowerShell, D:\Program Files\Microsoft\Exchange Server\V14\bin\exchange.types.ps1xml : File skipped because it was already present from “Microsoft.PowerShell”.
Update-TypeData : The following error occurred while loading the extended type data file:
Microsoft.PowerShell, D:\Program Files\Microsoft\Exchange Server\V14\bin\Exchange.partial.Types.ps1xml : File skipped because it was already present from “Microsoft.PowerShell”.
I was running the script in a normal EMS session.
Thanks again!
Cheers,
Alex
Thanks Alex, I’ll work on that bug.
Awesome script Paul.
Thanks!
Hi Paul
This script is really awesome and am huge fan of you
Only one Flow which i found is , if the DB is moved or failover from one server to another server
can it be show like
DBName on server2 should be on Server1
what am trying tell is DB is server1 , due to some N/w issue and the DB was moved and sitting on Server 2
can this report show like DBName on server2 should be on Server1
or am i missing the information in this report.
The script doesn’t attempt to diagnose in detail or recommend a specific action be taken. It is intended to present you enough details of possible issues so that you can make decisions about how to remediate problems.
So in the case of databases not being on their activation preference 1 server, the script flags that in the summary table, and then in the details table it also tells you which server is AP1 for that DB (but you can easily see that in EMC anyway). So then its up to you whether the DB should be moved or not.
Thanks awesome script
very helpful
Who needs expensive monitoring software when you got great scripts like this.
Thanks Paul, great work mate.
Ed
Good monitoring software is worth the price. But yeah, for those who can’t afford it thank goodness PowerShell lets us build scripts like this
Just ran it, worked perfectly first time. Scheduled task is in place to run it a few times per day. Not quite at the point where I can sit on the beach 8 hours a day, but getting close thanks to Paul :-p
Hi Paul,
I am getting the below error when trying to run the script. My be a user error but just wondering if you can help?
[PS] C:\Install.set>.\Get-DAGHealth.ps1
The ‘<' operator is reserved for future use.
At C:\Install.set\Get-DAGHealth.ps1:109 char:51
+ $summaryintro = "Database Availability Group < <<<$($dag.Name) Health Summary:”
+ CategoryInfo : ParserError: (<:OperatorToken) [], ParseException
+ FullyQualifiedErrorId : RedirectionNotSupported
All good find the error. It was a user error in the email address…
Super! Very usefull and great script. Thank you very much.
Little bug report:
1. I’m also get Update-TypeData error ( http://pastebin.com/putBAuAu ) on first run of script as Alex C.
2. Because of Russian date and time formats on server I get email with question marks instead of month name.
So I added -Encoding parameter to Send-MailMessage commandlet and month name now in russian like it should. Now my command looks like this:
Send-MailMessage @smtpsettings -Body $htmlreport -BodyAsHtml -Encoding ([System.Text.Encoding]::UTF8)
Thanks again.
Best regards,
Oleg.
I always seem to forget to set that encoding. Thanks for pointing it out, will fix in next version.
I’ve just added one line in the if ($SendEmail) block:
$encoding = [System.Text.Encoding]::UTF8
No need to add more paramaters to command line.
Also added more options to switch operators to support russian translation, they now look like
Switch ($($line.TCPListener))
{
$null { $htmltablerow = $htmltablerow + “$($line.TCPListener)” }
“Passed” { $htmltablerow = $htmltablerow + “$($line.TCPListener)” }
“Проверка пройдена” { $htmltablerow = $htmltablerow + “$($line.TCPListener)” }
default { $htmltablerow = $htmltablerow + “$($line.TCPListener)” }
}
+ “-Encoding $encoding” after send-emailmessage
Thanks for the effort Paul!
Thx Paul … really nice!
I am having a hard time getting this to run as a scheduled job where “Run whether user is logged on or not” is selected. It runs just fine with the “Run only when user is logged on”.
When redirecting output I get:
VERBOSE: Connecting to myserv1.domain
VERBOSE: Connecting to myserv1.domain
VERBOSE: Connecting to myserv1.domain
VERBOSE: Connecting to myserv1.domain
Failed to connect to an Exchange server in the current site.
Any ideas?
Are you also ticking the “run with highest privileges” box?
I am checking it.
Sorry that is not very clear. Yes, it is checked.
Could it be the credentials you’re using do not have the required rights? I’ll admit I haven’t put any thought yet into a nice RBAC role for this script and I just run it with a full Org Admin in my test lab for now. I’m wondering if you’re accidentally running it as the local admin on the server or something like that?
First I gave only view only org manager rights but then I gave full Org Man rights. And the script runs as the user when logged in as the user or if I select “Run only when user is logged on”. I will play with it more and will update if I find something.
Great script. I missed only the sort function in line 162 for a optimized view (for the case that the server have different names).
$tmpservers = @(Get-ExchangeServer) |sort
Thanks Paul!
Great script once again
Cheers!
Thank you, script is very useful, I testing in my enviroment, and have some questions.
When i get report on mail, some word looks like ????? for example curent date and PASSED for member health, in yellow bars i see ?????
I am using russian 2008 r2 and Exchange 2010, where i must fix code page ? Please help.
Anyway thanks, script realy helps monitor DAG Group
Try adding the encoding parameter that another person mentions here:
http://exchangeserverpro.com/get-daghealth-ps1-database-availability-group-health-check-script#comment-13966
Great script!
Is there a way to modify it so that it only sends an email if the script turns up a red flag? That would be really useful.
Well, it is PowerShell so of course it can be modified to do anything you like
But consider that the script also checks for a lot of “warning” conditions that aren’t necessarily an error or serious fault but may be something that the administrator wants to be aware of.
Works Perfect!
Q: On the Health Summary table, Column Preference, it shows 1 Green and the rest of the DB’s 2 Yellow. What does the Yellow represents?
Thanks.
Database Mounted on Preference
DB01 SecondServer 1
DB02 FirstServer 2
DB03 SecondServer 2
DB04 FirstServer 2
DB05 SecondServer 2
DB06 FirstServer 2
DB07 SecondServer 2
DB08 FirstServer 2
DBTest SecondServer 2
Yellow indicates that the database is mounted on a server that is not Activation Preference 1.
Great script, Paul. I added a check for Incremental and Full backups to the “Detailed” switch in your script, but I’m having problems comparing the date to a variable. Any thoughts on what I can do? I can send you the whole script if you want to see how it’s pulled in.
$incrPass = ((Get-Date).AddDays(-1)).ToString(“yyyy-MM-dd HH:mm:ss”)
$incrWarn = ((Get-Date).AddDays(-4)).ToString(“yyyy-MM-dd HH:mm:ss”)
#Warn if Incremental backups have not run recently
If ($(line.”Last Incremental Backup”).ToString -lt $incrPass)
{
$htmltablerow = $htmltablerow + “$($line.”Last Incremental Backup”)”
}
Elseif ($(line.”Last Incremental Backup”).ToString -lt $incrWarn)
{
$htmltablerow = $htmltablerow + “$($line.”Last Incremental Backup”)”
}
I’ve published an entire script for checking backups. You might prefer to use that or use some of the code from it to customize your own.
http://exchangeserverpro.com/set-automated-exchange-2010-database-backup-alert-email
Sounds good, I’ll check it out. Thanks.
Just to follow up, I looked at your code and then back at mine when I realized I was missing a “$” in my “($(line.”Last Incremental backup”)” section. I looks like it all works now. I can send you the change if you want to give it a shot. If not, no worries.
Thanks again, and keep the scripts coming!
This script is awesome Paul!
How often do you recommend running this script. Is it safe to run it maybe every hour or once a twice a day? Just want to make sure that it’s not putting any kind of load on my servers.
Thx.
I consider it safe to run without putting load on the servers. I run it once in the morning so the report is in my inbox when I start work.
Thanks, It works great on my environment
There´s something Im not sure what it means..
In the Member Health table from one of my DAGs (got 4) shows “N/A” in the following columns
DB Copy Suspended
DB Initializing
DB Disconnected
DB Log Copy Keeping Up
DB Log Replay Keeping Up
All the other columns in the same table shows “Passed”
Any idea?
That usually indicates the server hosts no passive database copies. It isn’t a problem unless you’re concerned about having a balanced distribution of active/passive copies in your DAG.
Thanks for the great script Paul. I’ve got it running twice a day, sending an email to our shared IT Team mailbox.
Top work
Awesome script!! Thank you very much!!
Thanks you very much for sharing this Awesome script!!…
can you add few other command to this script like
1) Get-Counter “\MSExchange Rpcclientaccess\User count”
2) Get-Counter “\MSExchange owa\Current Unique Users”
from this command we can monitor that no.of user connection has shared equally among CAS servers.
Great script, worked like a charm. I got the same error that other reported after the initial run, but none afterwards. Great way to keep track of those pesky “failed” indexes
Hi Paul, fantastic script. I just noticed however that after some recent server patching, that I’m getting some false-positves in the HTML output. “Healthy Queues” are all red, but with a value of zero, even though my queues are fine. “Truncation Lagged” and “Content Index” columns are all blank. Any ideas? I’m running 2010 SP2 RU3.
Thanks again!
-Alex
Run the script in a PowerShell window with the -verbose switch and see whether anything stands out.
Hi Paul…clean output with the verbose switch so not sure why “Healthy Queues” is listed as “0″ and is highlighted red. It was working fine prior to server patches…weird. Any other ideas?
Thanks!
Was it Windows patches or Exchange updates?
Hi Paul, FYI it was windows patches…
Can you ID the list of patches you installed on the date it stopped working, and either send them to me or paste them here? I let my lab servers automatically install updates and I’ve not run into this issue myself.
I am having the same issue on new servers running Exchange 2013 CU1 – Windows 2012.
Julian, I have not tested this script at all on Exchange 2013 so you may be seeing some other issue.
Well it’s definitely the same symptoms. Thanks for the script , I will try to troubleshoot when I find some time.
I get the same issue on WS2012.
@Alex – I’m thinking this may actually be a PowerShell v3 issue of some kind. Did your servers get updated with the Windows Management Framework 3.0 when the problem started?
@alex and @julian – I think I have found the problem. Will work on a fix and upload a new version as soon as I can.
Awesome script Paul. Really love the report. These colored reports definitely help with the management too. Keep up the great work.
Hi Paul,
Did someone reported that Activation Preference information is not shown in the report. This is happening in my case. Otherwise the script return valuable info.
Here is part of output when using “-verbose”:
VERBOSE: Retrieving Database Availability Groups
VERBOSE: 2 DAGs found
VERBOSE: —- Processing DAG xxxx
VERBOSE: x DAG members found
VERBOSE: xx DAG databases found
VERBOSE: —- Processing database xxxxxxxxxxxxxx
VERBOSE: xxxxxxxxxxxxxx has 3 copies
VERBOSE: Database Copy: xxxxxxxxxxxxxx\xxxxxxxxxxxx
VERBOSE: Server: xxxxxxxxxxxxxx
VERBOSE: Activation Preference:
VERBOSE: Status: Healthy
VERBOSE: Copy Queue: 0
VERBOSE: Replay Queue: 1
VERBOSE: Content Index: Healthy
VERBOSE: Database Copy: xxxxxxxxxxxxxx\xxxxxxxxxxxxxx
VERBOSE: Server: xxxxxxxxxxxxxx
VERBOSE: Activation Preference:
VERBOSE: Status: Healthy
VERBOSE: Copy Queue: 0
VERBOSE: Replay Queue: 1
VERBOSE: Content Index: Healthy
VERBOSE: Database Copy: xxxxxxxxxxxxxx\xxxxxxxxxxxxxx
VERBOSE: Server: xxxxxxxxxxxxxx
VERBOSE: Activation Preference:
VERBOSE: Status: Mounted
VERBOSE: Copy Queue: 0
VERBOSE: Replay Queue: 0
Thanks a lot.
Sorin
Interesting. Maybe a permissions issue? Using the same credentials can you run this command and tell me whether you see the list of servers and their preferences in the output?
Get-MailboxDatabase | select name,activationpreference
permissions are fine. Running Get-MailboxDatabase | select name,activationpreference returns correct information:
Name ActivationPreference
—- ——————–
DB1 {[xxxxxxxxxxxx, 1], [xxxxxxxxxxxx, 2], [xxxxxxxxxxxx, 3]}
DB2 {[xxxxxxxxxxxx, 1], [xxxxxxxxxxxx, 2], [xxxxxxxxxxxx, 3]}
DB3 {[xxxxxxxxxxxx, 1], [xxxxxxxxxxxx, 2], [xxxxxxxxxxxx, 3]}
Interesting. I will do my best to reproduce that and fix it.
OK, thanks a lot. drop me an email if you need help with testing.
Thanks Paul. It’s come just at the right time for us as we’ve just finished test our new DAG implementation and will be started the DB copies next week. I’ve run it on the test DBs we have in place and all is good so far!
Thanks Paul for your helpful Script,
Regarding to the Preference Tap refer to what ?
Preference is the Activation Preference for the database copy.
Hi,
Great script thanks Paul
I have setup scheduled tasks on your other ones and they send fine to multiple people, but with the DAG health one it seems to only send to the first person in the list. Is there need to do something slightly differenet with this script?
Cheers
Should work in the format:
To = “firstemail@domain.com”,”secondemail@domain.com”
Alternatively, try sending it to a distribution list.
Version 1.1 of Get-DAGHealth.ps1 is now available for download via the link in the article above.
Thanks to those who have provided bug reports and feedback so far. I appreciate your help making this script accurate and useful.
Hello Paul this is a great script I have only one question, how I can have the report sent by email when autentication is required ?
Send-MailMessage (way down the bottom of the script) has a -Credential parameter. I’d recommend using a low privilege account credential.
Technet:
http://technet.microsoft.com/en-us/library/hh849925.aspx
Very great job and wonderful script !
Few questions :
- When I do a detailed report, all the cells in the DAG Member Health array (last array) are yellow and there is “Transmis” inside. What does it mean ? (I’m on Exchange 2013 with CU1)
- Do you plan to make Test-ExchangeServerHealth.ps1 & Get-DailyBackupAlerts.ps1 Exchange 2013 compatible ? (It would be great
The first problem sounds like a non-English language server. I have an idea how to make that easier to deal with but for now you’d need to just look at the HTML generating sections of the script and possibly replace English words like “Success” and “Passed” to your language’s word.
Yes, I plan to test and update all the scripts for Exchange 2013 as time permits.
Thanks a lot, that was it !
Hi Paul,
Thanks for the script and Awesome work, challenge is when i execute is doens’t generate all the output on the email and i get the following errors on the Shell window;
“You must provide a value for this property.
+ CategoryInfo : NotSpecified: (0:Int32) [Get-MailboxDatabase], DataValidationException
+ FullyQualifiedErrorId : 16C4924A,Microsoft.Exchange.Management.SystemConfigurationTasks.GetMailboxDatabase”
This two sections are not populated on the email;
“Database Availability Group SVDTDAG01 Health Summary:
Database Mounted on Preference Total Copies Healthy Copies Unhealthy Copies Healthy Queues Unhealthy Queues Lagged Queues Healthy Indexes Unhealthy Indexes
Database Availability Group SVDTDAG01 Health Details:
Database Copy Database Name Mailbox Server Activation Preference Status Copy Queue Replay Queue Replay Lagged Truncation Lagged Content Index
Database Availability Group SVDTDAG01 Member Health:”
Kind Regards,
Brian
Run it with the -Verbose switch and see if you spot any errors or warnings.
I am having an issue with the scheduled task when i run it nothing happens but if I run the script manually with the options I get the email. For the arguments this is what i have:
-command “c:\scripts\daghealth\get-daghealth.ps1 -Detailed -SendEmail”.
Am i doing something wrong
Please make sure you have checked all the items in that bullet list I include in the article for running the script.
Ok i was trying to run it with a service account that has the password set to not expire but cannot log on locally to the server. It works with my domain admin account so I guess I will have to change the password on the task every month
It doesn’t need to be a domain admin account. I’ll try and write up the specific RBAC roles the account needs to run this script without giving it too many rights.
Ok will appreciate that. I tried running it with the local administrator account but it runs for several minutes without any output
Local accounts certainly won’t work, it does need to be a domain account. From memory it needs at least Exchange View-Only Org rights (there’s an existing group for that) and I think I also needed it to be a member of the local administrators group on the management server I run it on, presumably due to some PowerShell requirement that I haven’t quite worked out.
There is a bug in the script :
Once the UPTIME counter reaches 1000+ hours, it shows ’1′ in the HTML output.
We only just noticed this, because of monthly security updates force reboots often, except recently.
In this script?
No, the health check script, this one doesn’t do uptime
Its this bit: [int]$uptime = “{0:N0}” -f $uptime
Woops, wrong forum, this bug is in the ‘health check’ script , not the DAG one.
Great script, I do get a warning when running it , but the output seems fine on first glance;
WARNING: Unable to get Primary Active Manager information due to an Active
Manager call failure. Error: An Active Manager operation failed. Error
Operation failed with message: Error 0x6d1 (The procedure number is out of
range) from cli_AmGetDeferredRecoveryEntries.
I have a proposal for a new feature / improvement;
We have hundereds of databases, so the output spans several screens. This prevents us from easily spotting problems a a glance on a monitoring screen.
Would be great to have a switch (say -failureonly) that lists only the ‘failures’ in the output from;
Database Availability Group Health Details
Database Availability Group Health Summary
cheers
how to customize this script to run against one daggroup?
Look for the line in the script where Get-DatabaseAvailabilityGroup is and modify that line to just get the DAG you’re interested in.