With the release of Exchange Server 2016 a minor update to my Test-ExchangeServerHealth.ps1 script was necessary to fix a version detection bug with Exchange Server 2016.

If you run Exchange Server 2016 and want accurate health check reporting you can download the updated script from the TechNet or Github.

If you’d like to learn more about Test-ExchangeServerHealth.ps1 please go here.

The change in V1.15 was a very simple one. Exchange Server 2010 has build versions starting with 14.x, and Exchange Server 2013 has build versions starting with 15.x. I did not anticipate that Exchange Server 2016 would also use 15.x version numbers when I first wrote the script. The minor update changes the build version detection to use “15.0*” for Exchange 2013, and “15.1*” for Exchange 2016.

Other than that, the two products are so similar that the script appears to run just as well for Exchange 2016 as it for Exchange 2013. Which is not to say it runs perfectly. There were a number of hacks and workarounds needed for the script to work with Exchange 2013, and the overall script code has grown to an unmanageable size with poor structure, making any significant change risky at this point. This script actually started life almost 5 years ago in the Exchange 2007 era and today resembles a house that has had a dozen different renovations performed on it instead of a brand new home with everything well designed to fit together.

A year ago I announced I would rewrite the script from scratch. A lot of work and other life events have slowed me down, but that task continues and I hope to have something that is better suited to Exchange 2013 and 2016 released in the near future. In the meantime please continue to run Test-ExchangeServerHealth.ps1 for your health checks and report any bugs or issues to me so that I can fix them where possible.

About the Author

Paul Cunningham

Paul is a former Microsoft MVP for Office Apps and Services. He works as a consultant, writer, and trainer specializing in Office 365 and Exchange Server. Paul no longer writes for Practical365.com.


  1. Özer Yümsek

    Hello Paul,

    We are running the script and send mail it says “Client Access Server Role Services” and “Hub Transport Server Role Services” fails. We are running script on Exchange management shell it doesnt give an error.
    Client Access Server Role Services: Pass
    Hub Transport Server Role Services: Pass

    What can cause this error.

    Exchange server version is 2010 SP3 UR 18

    Thank you very much / Regards

  2. Ramana

    Hi Paul,

    Can we modify the script to monitor Edge servers which are in DMZ zone .


  3. ortacdemirel

    if you have closed exchange server, script stuck on “MAPI connectivity” test.

    Test result like:
    Offline databases:
    MAPI connectivity:

  4. Ryan

    Upgraded from 2016 CU2 to CU4 and the content indexes for lagged copies register as unhealthy with an AutoSuspended status. I can’t find a lot of information on this from Microsoft – is this expected behavior since CU3 or CU4?

    1. Avatar photo
      Paul Cunningham

      I’ve had a bunch of reports of this and someone has contributed some code fixes for the script that I need to review, so hopefully a fix (for the script reporting) will be available soon.

  5. Feras

    Hi Paul,
    This is great script indeed!!
    How can we get it to run from member server that does not have ExchMgmtTools installed on it against Exchange 2010 and 2013?? I guess it breaks due to the code between lines 502-521.
    Works with no issues if executed from an Exchange 2013 server.

  6. Suraj Kanekal

    I have create the ignorelist txt file but keep getting this error: C:\temp\ignorelist.txt could not be found. Plz Help.

  7. Dhillan

    Hi Paul,

    Thanks for developing this wonderful script and assisting admins to monitor their systems better.

    I have implemented this on one of the environments that I manage, however when the report gets sent through via email it comes as a Plain Text message and not HTML.

    Is there a setting in the script or on the server that I can change to get this in HTML format.


    1. Avatar photo
      Paul Cunningham

      Check the remote domains settings for the Exchange org where the email is coming from, the might be forcing outbound emails to plain text format.

  8. Mayur Tamhane

    Hi Paul,

    Much more thanks for the same, I would like to know whether I has to put my exchange server’s host names inside of this scripts OR just modify mail address and run directly.
    Also, if in case the script fail between operation its harm anything of my server?

    I Request you to please specify if that kind of codes is inside of this script.

    And what i have to make changes into your current script to run with my exchange 2013.

    Again Thank you…!

    Mayur Tamhane

  9. Gareth Briggs

    Hi Paul,

    Firstly, thanks for taking your time to develop the script, its a massive help for doing morning checks!!. I was just wondering if there any plans to include WhiteSpace and Backups into it?

    Thanks Gareth

    1. Avatar photo
      Paul Cunningham

      A lot of people have asked for those to be included and I would like to add them in future, but no ETA on when that will be.

  10. Lanna Smith

    Hi Paul,

    Script works perfect! How can I change the script for the output into an html file and email as attachment instead of results within the body of the email?

    Thank you

  11. Eric Stallswroth

    I am having difficulty with the script. It isn’t detecting my Exchange 2013 on-prem hybrid servers. If I specify the server name using the -Server parameter, it runs just fine. Is there any way to give the script a list of servers I want to run it against (as opposed to those I want it to ignore)?



  12. WG

    Hi Paul,

    This is a great script. I have used it for many years in the different versions.

    I am not able to get the ignorelist working for multiple servers.

    Should the txt file be “server1″,”server2” or just server1,server2.

    neither seems to work?

      1. Wai Cheng

        How about if there is spaces in the name? eg…

        Exch DB 1 <— spaces
        Exch DB 5

        I tried in the ignorelist.txt but does not work.

        Many thanks in advance

  13. Jan

    Hello Paul,

    I have changed line 952

    $qcount = $q | Measure-Object MessageCount -Sum


    $qcount = $q | where {$_.DeliveryType -ne ‘ShadowRedundancy’ } | Measure-Object MessageCount -Sum

    I don’t consider the ShadowRedundancy queue’s as critical. But it could be good information to have in a different column.

    1. Ralph Ninh

      Hello Paul,

      Thank you for sharing this wonderful script!

      From my experience, when the system is in trouble, one of the queues would be very large. The sum of the queues may unintentionally exceed a threshold if they are evenly distributed. I view the largest queue as the problem, and similar to Jan, exclude the ShadowRedundancy queues. I’ve modified the script as follow:

      Write-Host “Total Queue: ” -NoNewline;


      Write-Host “Max Queue: ” -NoNewline;

      $qcount = $q | Measure-Object MessageCount -Sum
      [int]$qlength = $qcount.sum


      $qcount = $q | Where {$_.DeliveryType -ne ‘ShadowRedundancy’ } | Measure-Object MessageCount -Maximum
      [int]$qlength = $qcount.Maximum

Leave a Reply