This PowerShell script will perform a health check of your Exchange Server environment, including servers and database availability groups, and output a HTML report that you can send to your inbox.

The report includes a summary of issues that were found, as well as a color-coded table with the detailed test results to help you quickly spot problems.

This is a useful script to run as a daily health check first thing in the morning to identify any problems that may have occurred overnight, and give you a chance to fix them before your end users notice.

powershell-script-health-check-exchange

This script is available to download from the TechNet Script Gallery or Github. Comments are welcome below. If you find a bug please consider raising it as an issue on Github.

Script parameters:

  • -Server, Perform a health check of a single server
  • -ReportMode, Set to $true to generate a HTML report. A default file name is used if none is specified.
  • -ReportFile, Allows you to specify a different HTML report file name than the default.
  • -SendEmail, Sends the HTML report via email using the SMTP configuration within the script.
  • -AlertsOnly, Only sends the email report if at least one error or warning was detected.
  • -Log, Writes a log file to help with troubleshooting.

Examples:

.\Test-ExchangeServerHealth.ps1

Checks all servers in the organization and outputs the results to the shell window.

.\Test-ExchangeServerHealth.ps1 -Server HO-EX2010-MB1

Checks the server HO-EX2010-MB1 and outputs the results to the shell window.

.\Test-ExchangeServerHealth.ps1 -ReportMode -SendEmail

Checks all servers in the organization, outputs the results to the shell window, a HTML report, and emails the HTML report to the address configured in the script.

If you use the report mode you’ll get a HTML file containing the health check results, and/or an email to your designated address if you also use the send email option.

For the email functionality to work please update these variables in the script to suit your environment.

#...................................
# Modify these Email Settings
#...................................

$smtpsettings = @{
	To =  "administrator@exchangeserverpro.net"
	From = "exchangeserver@exchangeserverpro.net"
	Subject = "Exchange Server Health Report - $now"
	SmtpServer = "smtp.exchangeserverpro.net"
	}
A lot of people ask how to add multiple recipients to the SMTP settings. My advice is to use a distribution group, so that any time you need to modify the list of recipients you can simply change the distribution group membership instead of needing to modify the script code.

When running the script on non-English servers you can modify the following variables in the script to match your language so that the script does not give errors or incorrect results.

#...................................
# Modify these language 
# localization strings.
#...................................

# The server roles must match the role names you see when you run Test-ServiceHealth.
$casrole = "Client Access Server Role"
$htrole = "Hub Transport Server Role"
$mbrole = "Mailbox Server Role"
$umrole = "Unified Messaging Server Role"

# This should match the word for "Success", or the result of a successful Test-MAPIConnectivity test
$success = "Success"

For example, a German system would use the following values:

# The server roles must match the role names you see when you run Test-ServiceHealth.
$casrole = "Clientzugriffs-Serverrolle"
$htrole = "Hub-Transport-Serverrolle"
$mbrole = "Postfachserverrolle"
$umrole = "Unified Messaging-Serverrolle"

# This should match the word for "Success", or the result of a successful Test-MAPIConnectivity test
$success = "Erfolgreich"

Use the ignorelist.txt file to specify the names of any servers, DAGs, or databases that you want to ignore for the tests.

My scheduled task settings for this script are:

  • Run whether user is logged on or not
  • Run with highest privileges
  • Action: Start a program
    • Program: powershell.exe
    • Arguments: -command “C:\Scripts\ExchangeServerHealth\Test-ExchangeServerHealth.ps1 -Log -SendEmail”

FAQ

Q: Which version of PowerShell is required?

If you are running the script on a server that has Exchange 2010 or 2013 (or later) server roles or management tools installed then it should work.

Q: I’m running multiple versions of Exchange, will the script still work?

Yes, it should work as long as you run it from the highest version of Exchange. For example, in a mixed Exchange 2010/2013 environment you should run the script from an Exchange 2013 server.

Q: Why do I get an error when the script sends the email report?

Make sure you’ve configured the email settings section of the script to point to a Hub Transport that either accepts anonymous users (typically an internet-facing Hub Transport), or if you’re using a separate management server or admin workstation point the SMTP server to a Hub Transport that has a receive connector set up that the server you’re running the script on is allowed to relay through.

Q: Why aren’t Edge Transport servers checked?

Between firewalls and permissions the Edge Transport checks are difficult to account for so they are currently skipped by the script.

Q: What should I do when the script report an error/fail on my servers?

The script doesn’t perform any diagnostics when it detects an error, it only reports them to you. When you see an error you should investigate further using the management tools and cmdlets that are provided by Exchange.

If you are encountering situations where the script reports errors that turn out to be false alarms please let me know and I will do my best eliminate those false alarms.

Q: Can you add feature X to the script?

If you have additional requirements then you are encouraged to customize the script to suit your own needs.

[adrotate banner=”48″]

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.

Comments

  1. Scott

    Paul,
    I have been using this script on my exchange 2016 server for a long time with no errors. I just upgraded my mail servers because of a failure and now I am getting a mail flow failure. When I Test-Mailflow I get a success on both exchange servers. I test each individual database on the active server, and I get success. I am not sure where to look from this point. All mail seems to be working properly also so it appears there isn’t anything wrong. I just don’t want to ignore this because as I said this script is awesome and has saved me a lot of headaches over the past 8 years.

  2. Ivaylo

    Is there a way to export the result from the PS console to JSON file?

    1. Avatar photo
      Tony Redmond

      The output of the script is a HTML file. It’s built up from arrays like $dagdbcopyReport. You could export the source arrays to JSON using the ConvertTo-JSON cmdlet.

  3. kanchana

    Cannot process argument transformation on parameter ‘Server’. Cannot convert the “” value of type
    “Deserialized.Microsoft.Exchange.Data.Directory.Management.ExchangeServer” to type
    “Microsoft.Exchange.Configuration.Tasks.ServerIdParameter”.

    Im getting this error …any one know why

  4. JM

    Hi Guys,

    We are running the script on a 2016 Exchange Server, unfortunately after the last update last week all the MAPI Tests failed. Do you have any idea? If I run the test manually it’s ok.

    Thanks ;-).

  5. Mehmet

    i try to run script from remote a server, how can i run it ?

  6. Muthu

    Hi,

    Thanks for the script. We have deployed 2019 serevrs so it is the same. i have ran the script against the server But it is showing as 2013 only servers as . anything i needto modify

    1. Mehmet

      i try to run script from remote a server, how can i run it ?

  7. Kiran Gandhi

    Hi Paul,
    Thank you for the wonderful script. Is there a way to exclude content index health check because its No longer applicable to Exchange 2019 databases. The report contains the following :-

    Database Availability Group Health Check Summary
    The following DAG errors and warnings were detected.
    Database01- unhealthy content index count is 4 (of 4 )

  8. Dleon

    Hello Paul.

    Amazing script. Very useful to quickly identify what is wrong in big environments

    Is that possible to add Drives capacity and Drive usage percentage with thresholds to be able to predict back pressure?

    Thanks

  9. Srdjan

    Hello,

    Is it possible to run this script as a group managed service account?

    Best regards,
    Srdjan

  10. Tom

    I’m getting the following error and I’ve seen in the comments that others have received this too but didn’t see a specific fix…. Any quick suggestions. We have a loadbalancer that the URL will refer to in the error message below.

    Mail flow test: WARNING: Connecting to remote server outlook.vonbriesen.com failed with the following error message : WinRM cannot process the request. The following error occurred while using
    Kerberos authentication: Cannot find the computer XXXX.XXXXX.com. Verify that the computer exists on the network and that the name provided is spelled correctly. For more
    information, see the about_Remote_Troubleshooting Help topic.
    WARNING: Cannot validate argument on parameter ‘Session’. The argument is null or empty. Provide an argument that is not null or empty, and then try the command again.
    Remove-PSSession : Cannot validate argument on parameter ‘Id’. The argument is null. Provide a valid value for the argument, and then try running the command again.
    At C:\Healthcheck\Test-ExchangeServerHealth.ps1:452 char:22
    + Remove-PSSession $session.Id
    + ~~~~~~~~~~~
    + CategoryInfo : InvalidData: (:) [Remove-PSSession], ParameterBindingValidationException
    + FullyQualifiedErrorId : ParameterArgumentValidationError,Microsoft.PowerShell.Commands.RemovePSSessionCommand

    1. Jose Diaz

      Hi, I had the same error, I am using the same script in the las Exchange 2010 configuration and it work, now using the new Exchange 2016 the mail flow show me a fail test

    2. Eric Brock

      Tom,

      Did you get a fix for this issue? I just added several Exchange 2019 servers to our daily health check script, and they are all failing the mail flow test.

    3. JM

      Same here without solution at the moment, did you find one?

      1. JM

        Hi,

        I was able to adapt the script to make it done.

        – In the “Function Test-E15MailFlow()”, line 409 I “null” the $url :
        – Comment the line that retrieve the url (it force then to use the given url $url = “http://$e15mailboxserver/powershell”) :
        – Running it and it was OK, except for the mailbox server I’m running the script on because it test itself, I then just added a check if I’m on the server running the script to change it

        To resume, the beginning of this function is yet :

        Function Test-E15MailFlow()
        {
        param ( $e15mailboxserver )

        $e15mailflowresult = $null
        $url = $null

        Write-Verbose “Creating PSSession for $e15mailboxserver”
        # $url = (Get-PowerShellVirtualDirectory -Server $e15mailboxserver -AdPropertiesOnly | Where-Object {$_.Name -eq “Powershell (Default Web Site)”}).InternalURL.AbsoluteUri
        if ($url -eq $null)
        {
        $url = “http://$e15mailboxserver/powershell”

        if ($e15mailboxserver -eq “server1”)
        {
        $url = “http://server2/powershell”
        Write-Verbose “URL modified from server1 to $url”
        }

        Not that it may not be the cleanest way but it run without problems.

        Sincerely.

  11. Wai Cheng

    Hello Paul,

    Greeting… Great script. I have a question regarding to the ignorelist.txt

    I read from previous comments above the format for ignorelist.txt should be

    server1
    server2
    DB1

    However, the DB I wish the script to ignore in this format

    server1
    Exch DB B (<– contain spaces)

    I tried to add to the the ignorelist.txt but does not work.

    Any suggestions?

    Many thanks in advance,

  12. Prashant N

    Hi,

    We have mixed environment of Exchange 2010 (soon to be decommissioned in DAG) and Exchange 2016 (single server, no DAG, all the mailboxes are moved to O365, serves as a SMTP Server for on-premise applications).

    When I run the script in the PowerShell, I get correct details for all Exchange 2010 Mailboxes, DAG, etc.

    However none of Exchange 2016 related details (Mailbox Databases in EX-16), are part of the HTML report that is sent.

    Is this by design?

    Also can I run the script from a remote machine than running within the EX-16 server?

  13. TFC

    Hi,
    I dont know why I’m getting this error. Any idea?
    PS C:\Program Files\Microsoft\Exchange Server\V15\Scripts> .\new-TestCasConnectivityUser.ps1 -ReportMode -SendEmail

    The only acceptable parameters are in the form of: [-OU ] [-Password ] [-UMDialPlan -UMExtension ].

  14. Bryan Clark

    We applied patches to our server on August 26th and the health check report after that point now says that we Failed the Cluster Network Test. I did a test-cluster and sifted thru the resultant report and only found that it is complaining about us only having one network path. This has always been the case for our Exchange 2016 servers and the test passed before August 26th. Did a Best Practice for Exchange clustering change? or am I missing something?

    1. Bryan Clark

      After Running the cluster Validate the problem seems to have gone away.

  15. mohd khan

    Hi Paul,

    First I would like to appreciate your work and really most of the time we go through your article only in exchange issues. Appreciated your hard work and contribution.

    I want to use this script but when running it getting an error that- Hub transport server role service – failed.

    When executed- test-server health – found EdgeSync service is not running and service status is set automatically.

    When tried to run edge sync service manually getting the following error
    “The Microsoft exchange edge sync service on local computer started and then stopped. some services stop automatically if they are not in use by other services or programs.”

    We don’t have an edge sync server role.
    Please suggest something to skip edge sync service, so that we can get everything in green color in the report.

    Request you to please revert back ASAP, Thanking you in Advance.

  16. Jean-François Harry

    Hi,
    Mail Test Flow is Fail on the report or i have no problem with this.
    All others test are OK.
    My Exchange is in French.
    Is there an option to change ?

  17. Ken Harrell

    Hello. I have upgraded to Exchange 2016 CU 15 and the Activation Preference is no longer showing.

    The line in the script that gets the Activation Preference i is not getting the preference.

    $pref = ($database | Select-Object -ExpandProperty ActivationPreference | Where-Object {$_.Key -ieq $mailboxserver}).Value

    If I run the script using an Exchange 2010 shell is works but not when it is Exchange 2016. Can someone help me fix the script so I get the preference again.

  18. Radhey

    Hi Paul,

    Thanks for such a nice script and it is running fine. But have some queries, i want to skip Public folder checks from the report as we do not have Public folder in our environment.

    Could you please help me on it.

  19. alex

    Hello Thanks for your script i am trying to migrate exchange 2010 to 2016 i get an error that transport Queue fail on the 2016 server.
    Exchange Server Health Check Summary
    The following server errors and warnings were detected.
    • ICUMBXSVR01 – Unified Messaging Server Role required services not running.
    • ICUMBXSVR01 – Transport queue is above high threshold
    Database Availability Group Health Check Summary
    No Exchange DAG errors or warnings.
    Exchange Server Health
    Server Site Roles Version DNS Ping Uptime (hrs) Client Access Server Role Services Hub Transport Server Role Services Mailbox Server Role Services Unified Messaging Server Role Services Transport Queue PF DBs Mounted MB DBs Mounted MAPI Test Mail Flow Test
    EXCHANGE EvolveEast Mailbox, ClientAccess, HubTransport Exchange 2010 Pass Pass 2915 Pass Pass Pass n/a Pass (12) Pass Pass Success Pass
    ICUMBXSVR01 EvolveEast Mailbox Exchange 2016 Pass Pass 735 Pass Pass Pass Fail Fail (7913) n/a Pass Success Pass

  20. Alex

    Hi Paul / everyone,
    Thanks for this script. We’ve been using it on 2010 and it’s been faultless. Just wondering if you could shed some light on an issue with a test on one server:

    We’ve added some 2016 servers to our environment, and we’re now running in full coexistence. The checks on 2010 come back ok, but on the 2016 servers, everything shows as well PASS except for the mailflow check on our first 2016 server, which comes back with:

    Mail flow test: WARNING: Couldn’t perform the operation because the server “xxxx” isn’t a Mailbox server.

    The issue is that the server it references is a CAS server in the 2010 environment. All other 2016 servers pass the test ok.

    Any ideas what’s going on?

    1. Alex

      Found the issue – the internal powershell URL for that server in ECP was mistyped and was pointing to the old CAS server (only 1 letter difference in the name). Problem solved !!

  21. Rodney Huffaker

    Works great with 2016 and below.

    Added this for 2019.
    if ($ExVer -like “Version 15.2*”)
    {
    $version = “Exchange 2019”
    }

    Since indexes are internal, it shows indexes are failed when they just don’t exist externally anymore. Should be a fairly easy thing to change. I’m working through that now.

    1. Franck Ehret

      I’ve just started 2019 migration and noticed that as well… 🙂

      I’ll really appreciate the updated version !

      1. William

        Worked for our Exchange 2019 as well.

  22. Firman Khairul

    hi experts

    how send to multiple email address?

    1. Tim West

      A lot of people ask how to add multiple recipients to the SMTP settings. My advice is to use a distribution group, so that any time you need to modify the list of recipients you can simply change the distribution group membership instead of needing to modify the script code.

  23. Rajkumar

    Warning Occured: he term ‘Test-Mailflow’ is not recognized as the name of a cmdlet, in the exchange server version 2016. Below are the output result.

    [PS] C:\Windows\system32>C:\Scripts\Exchange_Health-Check.ps1
    Initializing…
    —— Checking EXCHANGE-2016
    DNS Check: Pass
    Ping Check: Pass
    Uptime (hrs): 74
    Server version: Exchange 2016
    Roles: Mailbox
    Mailbox Server Role Services: Pass
    Client Access Server Role Services: Pass
    Unified Messaging Server Role Services: Pass
    Hub Transport Server Role Services: Pass
    Total Queue: 23
    Mailbox databases mounted: Pass
    MAPI connectivity: Success
    Mail flow test: WARNING: The term ‘Test-Mailflow’ is not recognized as the name of a cmdlet, function, script file, or operable program. Check the spelling of the name, or if a path was inclu
    ded, verify that the path is correct and try again.
    Fail
    —— Finishing
    Done.

  24. Muralikrishna Reddy Tekari

    Thanks for the Great Script Paul.

    However I see that the Lagged copies are not properly getting captured and is not writing the correct value for $replaylag variable (I’m on Exchange 2016 CU12)

    I fixed it by editing the right property –
    Old Value – if ($replaylagcopy.Key -ieq $mailboxserver)
    New Value – if ($replaylagcopy.Key.Name -ieq $mailboxserver)

    I think the same applies for the $truncatelag as well.
    New Value – if ($truncationlagcopy.Key.Name -eq $mailboxserver)

  25. fish

    Hello Paul,

    Thanks for your the great script!

    I am using Chinese language in my Windows server 2012, and I don’t understand your script about “localization strings”, do you know how can I set my language?

    Could you please give some tips?

    Thank you!

    1. Raphl Gu

      Add chinese role name like below

      # The server roles must match the role names you see when you run Test-ServiceHealth.
      #英文名称 $casrole = “Client Access Server Role”
      $casrole = “客户端访问服务器角色”
      #英文名称 $htrole = “Hub Transport Server Role”
      $htrole = “集线器传输服务器角色”
      #英文名称 $mbrole = “Mailbox Server Role”
      $mbrole = “邮箱服务器角色”
      # $umrole = “Unified Messaging Server Role”

  26. Mahmoud Atallah

    Dear Paul,

    Thanks a lot for your valuable articles and tips, please can you update the Health Check Script to run with Exchange 2019…
    Current script is not detecting correct Exchange version, also showing warnings on DAG Databases health check as unhealthy content indexes.

    Regards.

  27. Mohan KV

    Hi Paul,

    I want to run the HealthCheck script for our Edge server and also want to provide input file for the list of server. Help me with this.

  28. Mohan KV

    Hi Paul,

    I was run the HealthCheck script for our Edge server and also want to provide input file for the list of server. Help me with this.

  29. Waylon Irons

    Fine way of telling, and good post to obtain data about my presentation topic, which i am going to convey in institution of higher education.

  30. Magnolia Carpentier

    Useful information. Fortunate me I found your website accidentally, and I
    am shocked why this coincidence didn’t came about in advance!

    I bookmarked it.

  31. Sumit Chaturvedi

    Hi Paul,

    I have below queries regarding script:

    • The script is for Exchange 2010 and up, but doesn’t account for the fact that ServerRole values has changed since 2010. This is why it’s showing Hub Transport as failed, although why it thinks Client Access is good is a bit of puzzle. We’ll either have to remove or alter that part of the script so it’s not showing false errors
    • The script PowerShell Logon section needs to be re-written to work as Automatic Task. How can this be done?
    • The script is showing a lot of Replay Queue errors, I believe these are caused by the Lag Copy databases we have. How to deal with this?

  32. haydar tekir

    Hello,

    nice script btw. However I get the following error when I execute the script:

    Mail flow test: WARNING: Connecting to remote server mail.hisolutions.com failed with the following error message : WinRM cannot
    process the request. The following error occurred while using Kerberos authentication: Cannot find the computer
    mail.hisolutions.com. Verify that the computer exists on the network and that the name provided is spelled correctly.
    For more information, see the about_Remote_Troubleshooting Help topic.
    WARNING: Cannot validate argument on parameter ‘Session’. The argument is null or empty. Provide an argument that is
    not null or empty, and then try the command again.
    Remove-PSSession : Cannot validate argument on parameter ‘Id’. The argument is null. Provide a valid value for the
    argument, and then try running the command again.
    At C:\org\exchange\Test-ExchangeServerHealth\Test-ExchangeServerHealth.ps1:452 char:22
    + Remove-PSSession $session.Id
    + ~~~~~~~~~~~
    + CategoryInfo : InvalidData: (:) [Remove-PSSession], ParameterBindingValidationException
    + FullyQualifiedErrorId : ParameterArgumentValidationError,Microsoft.PowerShell.Commands.RemovePSSessionCommand

    Fail

    I have a Exchange Server 2016 DAG with two servers. and a standalon server running Exchange 2013 running in the same organization. The OS of the exchange 2016 is Windows server 2016

    Rgds

    Haydar

    1. Nick

      Hey haydar, I had the same problem. However, as per suggestion from Mark before the past, if you comment out

      $url = ….. from (around) line 418

      does this solve your problem?

  33. Fred

    Hi Paul, many thanks for this very useful health check script, just had a quick question regarding the exclusion file.
    I have no issue listed servers that I want to exclude, however I have a challenge listing some databases to exclude, i.e I have some restore DBs which are unmounted and want to exclude them from a couple of servers but listing the database names don’t seem to work.
    Could you advise what is the correct format to allow this to work.

    Thanks, Fred

  34. Yasir Khan

    Paul this script has been very useful as have the other scripts which you have compiled. Thank you very much for the time taken to create this script

  35. Shannon

    Paul, this script is awesome, thank you so much… We have been having issues with our environment and this at least gives a heads up before the users report problems.

  36. shahin

    hi friend,
    but when i run this script , i have error
    Mail flow test: WARNING: Connecting to remote server srv-XX failed with the following error message : The WinRM client cannot proces
    s the request. The WinRM client tried to use Negotiate authentication mechanism, but the destination computer (SRV-XX:80) returned a
    n ‘access denied’ error.
    WARNING: Cannot validate argument on parameter ‘Session’. The argument is null or empty. Provide an argument that is not null or emp
    ty, and then try the command again.
    Remove-PSSession : Cannot validate argument on parameter ‘Id’. The argument is null. Provide a valid value for the argument, and
    then try running the command again.
    At C:\Users\aslaniadm\Desktop\Test-ExchangeServerHealth.ps1:452 char:22
    + Remove-PSSession $session.Id
    + ~~~~~~~~~~~
    + CategoryInfo : InvalidData: (:) [Remove-PSSession], ParameterBindingValidationException
    + FullyQualifiedErrorId : ParameterArgumentValidationError,Microsoft.PowerShell.Commands.RemovePSSessionCommand

    Fail
    —— Finishing

    why this occurred and what can i do ?

  37. DAA3805

    The script fails on the mail flow test with the following … any idea why?

    Mail flow test: WARNING: Connecting to remote server xxx.xxxxxx.com failed with the following error message : WS-Management cannot process the request. The
    operation failed because of an HTTP error. The HTTP error (12152) is: The server returned an invalid or unrecognized response . For more information, see
    the about_Remote_Troubleshooting Help topic.
    WARNING: Cannot validate argument on parameter ‘Session’. The argument is null or empty. Provide an argument that is not null or empty, and then try the
    command again.

  38. Chi

    Hi Paul,

    Good day!

    I was using this script and it works perfectly but after moving my mailbox database from the default path to drive D I kept on getting an error/warning “Could not test service health. ” I don’t want to ruin the script since I am new to exchange. But if I need to, can you please tell me where in the script should I change the path or directory.

    Thank you,
    Chi

  39. Daniel

    Hi, Paul:

    Very useful script thanks a lot.

  40. Arun

    my issue is in exchange server 2016 the default online search limitation is 250…but i need to increase the search limitation to 2000.

  41. metin

    Hi Paul;
    I wanted to add the following commands to the report but failed. Can you help me with this?

    Get-MailboxDatabase -Status | sort name | select name,@{Name=’DB Size (Gb)’;Expression={$_.DatabaseSize.ToGb()}},@{Name=’Available New Mbx Space Gb)’;Expression={$_.AvailableNewMailboxSpace.ToGb()}}

    Thank you for making the report. 🙂

  42. Stephan P

    Good morning Paul,

    thank you for the great script.
    Unfortunately I get 2 different results.
    The problem ist the mail flow test.
    The log says ‘Mail flow status is Erfolgreich’
    The html Check Report says Mail flow test failed. (in red)

    Any solution?

    Regards

    Stephan

  43. Mark F

    Hi Paul, we have been using this script daily to check on our environment. I am currently on Exchange 2016 / 2010 co-existence. I updated Exchange 2016 to CU11 this weekend and now the script is showing null value errors for
    “You cannot call a method on a null-valued expression.
    At D:\Scripts\Test-ExchangeServerHealth2\Test-ExchangeServerHealth.ps1:1575 char:17
    + $DagMemberVer = ($GetExchangeServerResults | Where-Object {$_.Na …”

    This was working fine with Exchange 2016 CU9. The printed report has no names under the server column in the DAG sections and the Exchange 2010 Dags show the “server locator service” Failed on every Exchange 2010 server. I reviewed each Exchange 2010 server using Test-Replicationhealth and the error does not show up there.

    Ideas?

    1. Mark V

      Curious if you ever solved your “no names under the server column” problem … we were a few CU’s behind and just installed CU12 … and are see the same now too. Also seeing blanks for “Preference” related columns … I assume it’s related.

      1. Mark V

        I was running the script from a management server … once I updated that server with CU12 the script started working properly again. Happy to see it working again.

  44. Paul

    Hi Paul

    Great article as always, but just came across an interesting issue in a test environment, when the server name isn’t all in upper case. This resulted in the script being unable to report on activation preferences of the database copies.

    The following line in your script was attempting to perform a case-insensitive comparison between server names, but if they weren’t exactly the same case, it wouldn’t return any results.
    $pref = ($database | Select-Object -ExpandProperty ActivationPreference | Where-Object {$_.Key -ieq $mailboxserver}).Value

    I needed to specify the “Name” property of the “Key” for this to work correctly:
    $pref = ($database | Select-Object -ExpandProperty ActivationPreference | Where-Object {$_.Key.Name -ieq $mailboxserver}).Value

    Cheers

    Another Paul

  45. Séb

    Hi Paul, thanks for this useful script.
    Have you already test it on Exchange 2019 ?
    Same question for the DAG Health check ? 🙂

    Thanks,
    Regards

  46. Ercan Ufuk GARGIN

    Hello Paul,

    I found the solution

    It is “Server Management” and “Remote Management Users” roles.

    Regards

  47. Ercan Ufuk GARGIN

    Hello Paul,
    When we try to run script it gives an error below;

    Mail flow test: WARNING: The term ‘Test-Mailflow’ is not recognized as the name of a cmdlet, function, script file, or operable program. Check the spelling of the name, or if a path was included, verify that the path is correct and try again.
    Fail

    It was working fine but we accidentilly remove running users groups.

    Can you help us to work again?

    Thank you for great script.

    Regards.

  48. Rob

    Terrific script! It has everything I need except disk space. Would that be a feature to add later? I’ve tried to add it myself, but broke many things within.

    Thanks for the awesome work!

  49. jd

    Hi Paul, great script, we have been using this for production use with Exchange 2016 CU9.

    After recently installing CU10, the Server name column under “Database Availability Group ‘DAG’ Member Health” is now coming up empty. All the other boxes still pass

    Do you have any idea why this would stop this working?

    Looking in the code that first row appears different to all the others:

    $htmltablerow += “$($line.”Server”)
    $htmltablerow += (New-DAGMemberHTMLTableCell “ClusterService”)
    $htmltablerow += (New-DAGMemberHTMLTableCell “ReplayService”)

    Thanks

  50. Steve Money

    Fantastic Script!!

    I am having 1 issue however.

    I am currently running a Exchange 2010-2016 co-existence environment. 1 of my Exchange 2016 servers shows a “Unable to Retrieve Uptime” message. All other servers are working fine.

    Any ideas on what is not working?

  51. Guillaume Roucou

    Hi,

    I would like to ignore a specific database but it doen’t work.
    How do I specify database in ignore.txt file ?

    database/server
    or
    database

    I try both but it doen’t work.

    Thx

  52. Michael Wawrzyniak

    For anyone who is running into problems making this script work with Task Scheduler, I got it to work. Initially using the author’s instructions, it did not work. Task Scheduler said that the task completed successfully almost instantly, but the script did not run.

    I’m running this on a Server 2016 / Exchange 2016 CU10 server.

    – Run As: (my domain Exchange Admin account)
    – Run whether user is logged on or not
    – Run with highest privileges
    – Configure for: Windows Server 2016

    – Start a program
    – Program/script: Powershell.exe
    – Add arguments (optional): -ExecutionPolicy Bypass C:\Scripts\Test-ExchangeServerHealth.ps1 -ReportMode -SendEmail
    – Start in (optional): blank

    I messed around with a bunch of the settings, but I believe the main issue I was having related to not having the ExecutionPolicy, plus trying to use -command “script path+name+params”. You don’t need any quotes in the “Add arguments” section.

    Hope this helps anyone else who wanted to schedule this awesome script! Thanks again for making it and maintaining it for us!

    1. Asela De Costa

      Thank you so much

  53. Bill Bowling

    Just a note: I have been using this script since it came out. I had 2010 and 2016 exchanges servers. I just finally removed my one exchange 2010 server. Everything went fine. My question is this script is still showing the removed exchange 2010 server in the results. Do I have to wait a day or so after removing DNS, AD, etc. related to the removed server?

    Thanks.
    Bill

  54. Darya

    C:\Program Files\Microsoft\Exchange Server\V15\TransportRoles\data\Queue>”C:\Pro
    gram Files (x86)\Log Parser 2.2\logparser.exe” “SELECT data as [Status Code],Cou
    nt(*) as Hits FROM *.log WHERE data LIKE ‘5%’ GROUP BY data ORDER BY Hits DESC”
    -i:CSV -nSkipLines:4 -rtp:-1
    Error: SELECT clause: Syntax Error: unknown field ‘data’

    To see valid fields for the CSV input format type:
    LogParser -h -i:CSV

  55. James Ledgard

    if anyone’s getting the mailflow test failure, check the servers NIC card has Register DNS Ticked (not normally set for a server with static address) as exchange mailflow requires this, you then get a clean bill of health

  56. John

    I finally got Email to work! However, the htmlreport does not generate when running with PowerShell directly or running a scheduled task. I have to run it in C:\Scripts by running .\Test-ExchangeServerHealth.ps1 -ReportMode -SendEmail. Any suggestions?

    ###########Define Variables########

    $fromaddress = “ExchangeReport@yourdomain.com”
    $toaddress = “username@yourdomain.com”
    $Subject = “Daily Exchange Server Report – $now”
    $attachment = “C:\scripts\Oakwood Exchange Server Health.html”
    $smtpserver = “smtp.yourdomain.com”

    ####################################

    $message = new-object System.Net.Mail.MailMessage
    $message.From = $fromaddress
    $message.To.Add($toaddress)
    $message.IsBodyHtml = $True
    $message.Subject = $Subject
    $attach = new-object Net.Mail.Attachment($attachment)
    $message.Attachments.Add($attach)
    $message.body = $body
    $smtp = new-object Net.Mail.SmtpClient($smtpserver)
    $smtp.Send($message)

    1. John

      I figured it out.

      I created a batch file and input:

      c:\windows\system32\WindowsPowerShell\v1.0\powershell.exe -ExecutionPolicy ByPass -command C:\Scripts\Test-ExchangeServerHealth.ps1 -ReportMode -SendEmail

      All working now

      Thanks Paul!!!

  57. Phil Brooks

    Great script! I’ve been using it for years on Exchange 2016. Any tips for getting this to work in Windows Server 2016 task scheduler for Exchange 2016?

    1. Avatar photo
      Paul Cunningham

      I don’t have any WS2016 servers to test it on right now I’m afraid.

  58. John

    Hi All,

    I have other DAG Servers which shows Green and Healthy for DB Copy Suspended DB Copy Failed DB Initializing DB Disconnected DB Log Copy Keeping Up DB Log Replay Keeping Up

    However, I have one Server that shows N/A but the Cluster Service Replay Service Active Manager Tasks RPC Listener TCP Listener Server Locator Service DAG Members UpCluster Network Quorum Group have passed.

    Does anyone know why It’s not checking DB Copy Suspended and etc and outputting N/A?

    Thanks!

    1. Avatar photo
      Paul Cunningham

      Some of the tests are n/a when the mailbox server has no active mailbox database copies on it. Basically the Test-ReplicationHealth cmdlet is what is returning those results, and if it doesn’t return a result for one of the items, the script lists it as “n/a” for “not applicable”.

  59. SANKARASUBRAMAN PARAMESWARAN

    it is not working for exchange 2016.

    This script does not find the DAG health summary for exchange 2016 and IP less DAG

  60. Jon DeSalvatore

    Thanks for this cool script Paul. Appying this to EXC2016 and its working . I set up 2 seperate task schedules for this. One runs at 7am daily and sends a report. Then I have a seperate one that runs every 30 minute and will only send an alert if something is amiss.

    The issue I am having is that I am getting email alerts about the reply queue being 9 or 12. Is there a way tone down the sensitivity of the replay queues so that I would only get notified when its lets say over 100? Thanks!

      1. Jon DeSalvatore

        Can you guide to where?

  61. Jeremy

    Love this script and would like to include a disk space check as well. Probably like most people, we use Volume Mount Points for each DB and LOG directory. Most monitoring tools are not able to check disk space on these, so I using the below in another script.

    Any suggestions?

    $TotalGB = @{Name=”Capacity(GB)”;expression={[math]::round(($_.Capacity/ 1073741824),2)}}
    $FreeGB = @{Name=”FreeSpace(GB)”;expression={[math]::round(($_.FreeSpace / 1073741824),2)}}
    $FreePerc = @{Name=”Free(%)”;expression={[math]::round(((($_.FreeSpace / 1073741824)/($_.Capacity / 1073741824)) * 100),0)}}

    function get-mountpoints {
    $volumes = Get-WmiObject -computer win32_volume | Where-object {$_.DriveLetter -eq $null}
    $volumes | Select SystemName, Label, $TotalGB, $FreeGB, $FreePerc | Format-Table -AutoSize
    }

    #$servers = (Get-Content .\servers.txt)

    #foreach ($server in $servers){
    get-mountpoints
    #}

  62. Andrew

    Hi Paul,

    Getting this error on our production Exchange 2016 servers when running the script

    DNS Check: Pass
    Ping Check: Pass
    Uptime (hrs): 36
    Server version: Exchange 2016
    Roles: Mailbox
    Mailbox Server Role Services: Pass
    Client Access Server Role Services: Pass
    Unified Messaging Server Role Services: Pass
    Hub Transport Server Role Services: Pass
    Total Queue: 0
    Mailbox databases mounted: Pass
    MAPI connectivity: Success
    Mail flow test: [Microsoft.Mapi.MapiExceptionSendAsDenied]: MapiExceptionSendAsDenied: Unable to submit message. (hr=0x80070005, ec=1244)
    Diagnostic context:
    Lid: 40487 EMSMDBMT.EcDoRpcExt2 called [length=46]
    Lid: 56871 EMSMDBMT.EcDoRpcExt2 returned [ec=0x0][length=400][latency=15]
    Lid: 52176 ClientVersion: 15.1.1261.39
    Lid: 50032 ServerVersion: 15.1.1261.39
    Lid: 35180
    Lid: 23226 — ROP Parse Start —
    Lid: 27962 ROP: ropSubmitMessage [50]
    Lid: 17082 ROP Error: 0x4DC
    Lid: 27745
    Lid: 21921 StoreEc: 0x4DC
    Lid: 27962 ROP: ropExtendedError [250]
    Lid: 1494 —- Remote Context Beg —-

    Seems to be related to the issue you mentioned for Exchange 2013 which I know was fixed. running the script from the local Exchange server against the local Exchange server works fine.

    1. Avatar photo
      Paul Cunningham

      Other people have reported the same error, but I can’t reproduce it so I don’t know why it is happening, sorry.

      1. Paul

        I’m getting the same message. I’m running this on an Exchange 2016 server that was hardened using CIS for a US government organization.

  63. Tom

    Hi Paul-

    Where does the script get the Exchange server list itself for the Server Health? I have an old server that has been decommissioned it is still looking for and I cant find where it is. Rather than use the ignore text file, I would like to know where it gets the server list from..

    Thank you! This is a great script, its part of our reporting every day.

    Tom

    1. Avatar photo
      Paul Cunningham

      It uses Get-ExchangeServer to retrieve the list of servers for the org. If you run Get-ExchangeServer and you still see your old server, then your old server was not properly decommissioned.

  64. Fang

    Hi Paul, after running this script & look at the report, most items look good but in DAG Member Health section, both my servers with *FAILED* in Database Availability column. Wondering what does it mean actually?

    Can you provide more guidance to me for further troubleshooting?

    Thanks in advance for your help & looking forward to your reply soon!

    1. Tino

      Ditto, i’m wondering what that means. Great script Paul!

  65. Gary

    Feature Request:

    Is it possible to put a quick error alert in the Subject line? For example, anything that is red just filters up a 1 to the subject of the email or 2 or maybe a “# errors”? Love the script!

    Thanks.
    Gary

  66. Mohsin

    Hi paul,

    i am not getting report on email. I have base platform on windows server 2012 R2. Please suggest. Thank You.

    Regards,
    -Mohsin

  67. Mauro

    Hello Paul,

    Thank you not only for this script, but for all your posts, information and experience you are sharing with us. you’re a time savior.

    I am facing a small problem, when i run the script manually, everything is fine and I receive the email, but when i run it from Task Scheduler, i receive nothing.

    I did the same Action and trigger mentioned above, also checked all the comments and errors but nothing helped me.

    when i run the task i can see in the history that action and task completed:
    – Action completed: Task Scheduler successfully completed task “\Exchange Health Report” , instance “{ID}” , action “powershell.exe” with return code 0.
    -Task Completed: Task Scheduler successfully finished “{ID}” instance of the “\Exchange Health Report” task for user “DOMAIN\administrator”.

    What do you suggest?

    once again, thank you!

  68. Christopher

    It seems to have been a while for a post. I’m recently running the script and kudos on it Paul.

    I want to add to show disk space on server drives

    Can you help with that?

    Regards,
    Christopher

  69. Morten Wiingreen

    Hi Paul,

    I am trying to get the script to run in scheduler on a Windows Server 2016 with Exchange 2016 CU7.
    When using -Log I can see the script gets stuck at “Loading the Exchange Server PowerShell snapin”.

    When I run the script in Powershell ISE it works perfektly.

    Any Idea how to get it up and running on a Windows Server 2016

    Best regards and thank you 🙂

    1. Hilario

      Hi Paul,
      Thanks for the script. We have been using it for a while and its great.
      I am having the same problem as Morten while adding 2016 servers.
      I noticed that “Get-ExchangeServer $server” in the script was not returning the 2016 servers so i tried adding :
      $Session = New-PSSession -ConfigurationName Microsoft.Exchange -ConnectionUri “http:///powershell” -Authentication Kerberos
      Import-PSSession -Session $Session | Out-Null
      But then the “Set-ADServerSettings -ViewEntireForest $true” throws an error

      Any ideas would be really appreciated.
      Thanks

  70. Kevin C.

    Hello Paul. Long term reader, first time “caller”. 😉

    We’ve been using your script for quite a while now big fans – Love it. We just got through updating to CU 19 along with 4.7.1 and coinciding with that the script no longer identifies the environment’s lag copy instances and so warnings are generated for the Replay Queues. We’ve confirmed that the lag copy configuration settings remained in tact. We checked and did not see where CU 19 for Exchange 2013 changed lag copy behavior.

    Any thoughts on what may be occurring?

    Thank you.

    1. Avatar photo
      Paul Cunningham

      Maybe that CU has introduced a new lag copy state that the script isn’t accounting for. I don’t have any 2013 servers in my lab to test though. If you have a look at the parts of the script code that deal with lagged copy status you might be able to work out what’s happening.

      1. Kevin C.

        Thank you for the suggestion Paul.

  71. Chris Smith

    Hey Paul – Love the script. Really awesome work. Problem I’m having is the mailflow test. It completes successfully on some of the servers but not all. Manually doing a “Test-Mailflow -targetmailboxserver ” works just fine & again it works fine on 3 of the 5. We are in a mixed mode of Exchange 2010 & 2016. The 2010 boxes work great, just 2 of the 5 2016’s don’t. Any ideas of where to begin?

    Thanks!!!

      1. Chris Smith

        I do get a “Access is denied” when I run the script in report mode. I looked at the administrators group in computer management & they match on all 5 of the servers. I have checked execution policy & all are set to “remote signed”.

        1. Avatar photo
          Paul Cunningham

          Where is that error appearing? In the report? In the console output?

          1. Chris Smith

            It is appearing in the report/log file.

            Thanks!!!

  72. Nolan

    Just wanted to take the time to say thank you for time and effort in putting this all together. It’s a great resource.

  73. Robert

    Great script Paul!
    Wanted to know what is the format of the ignorelist.txt?

    1. Avatar photo
      Paul Cunningham

      Just a list of names, one per line.

      SERVER1
      SERVER2
      DATABASE1

      etc

  74. Tyson

    Paul,

    Thank you for the script! I’m having issues with the ignorelist.txt file and have searched all of the comments looking for a solution to no avail. When executing the script I receive the following:

    WARNING: The file C:\ExchangeHealth\ignorelist.txt could not be found. No servers, DAGs or databases will be ignored.

    I have verified that the file is, in fact, in that exact location. I thought it might be a permissions issue so for testing I gave “everyone” read/write/modify permissions. Still no dice. Any recommendations?

    Thanks!

  75. Troy

    Report shows everything Green on our Exchange 2010 server.

    On our Exchange 2016 server it shows a Fail for “Client Access Server Role Services”. I looked in the Windows Services list, and I’m not seeing anything in a stopped state, except for “MS Exchange Notifications Broker”, and “MS Exchange Mailbox Replication”.

    Now I’m confused if anything is actually wrong.

    1. Avatar photo
      Paul Cunningham

      Run the Test-ServiceHealth cmdlet, it will show you which services it expects to be running.

      1. Troy

        Thanks. Turned out that it was the Exchange Mailbox Replication service that it was complaining about. Trying to figure out why it won’t start now. At the moment there’s only about 3 people on this new exchange server, and I haven’t noticed any end-user functionality problems with it.

  76. John Bales

    This is exactly what I was looking for. I can’t imagine the time it took to get this to where it is and I think we are ALL very appreciative of this! Thank you for not only creating this script, but also for sharing it as well.

  77. Dilip Sasikumar

    Hi Paul… First of thanks for all your contributions to the Exchange world. You are a life saver to may Exchange admins out there. Coming to my issue. I am running this health report in a mixed 2010 ,2016 environment and only 2010 servers are listed in the html report. If i check the logs , i can see 2016 servers are Tested successfully. Any suggestions?

    1. Dilip Sasikumar

      Paul, ignore my query. I was able to get it working after scheduling Task from the 2016 server instead of running from a 2010 server. Thanks!!

      1. Morten Wiingreen

        Hi Dilip, I am having problems getting scheduled task to run on my Server 2016 / exchange 2016.
        Could you share the settings you use?

  78. Andy B

    Hi Paul – did the test Mailflow command failure on remote servers ever get solved?

    Many Thanks

    A

    1. Mark

      I had the same issue. The mail flow part only works fine if Kerberos is configured correctly as Paul said before. You can also ‘fix’ it by commenting line 420. Put a ‘#’ in front of the line. Then it will fall back on the servername (Line 421-424) instead of the URL wich is configured in the virtualdirectory.

  79. Chetan

    Hi Paul,

    We have Exchange server 2013 environment across 3 sites.
    When we execute script, it gives output for all 3 sites located servers.
    We need to execute for each site individually & report should show report for only that site not for all.

    What changes need to be done in script & where it need to be done ? Please Suggest.

  80. Joseph Agius

    Paul

    I very much like your script, thanks. I am trying to run this script and I get the following warning.

    —————————————————————————————————–
    WARNING: No snap-ins have been registered for Windows PowerShell version 5.
    —————————————————————————————————–

    I am running this script on a Windows 10 Machine that has a PSSession to our exchange server.

    What am I missing here?

    Many thanks

    1. Avatar photo
      Paul Cunningham

      The script needs to be run using the Exchange Management Shell, not a remoting session.

      1. Joseph Agius

        Many thanks! How did I overlook that! Sometimes thinking too hard can be your undoing! Thanks for taking the time to respond

        Joseph

  81. Amaro Maguni

    Ok! Great!
    Thanks

  82. Amaro Maguni

    Hi Paul,

    Great Script! Thanks for sharing and for having your blog that helps a lot newbies like me.
    I am having this error when trying to send mails with the report (The Powershell version is 2.0),
    can you assist!?
    Thanks in advance!

    “PS C:\> .\Test-ExchangeServerHealth.ps1

    cmdlet Test-ExchangeServerHealth.ps1 at command pipeline position 1
    Supply values for the following parameters:
    ReportFile: Exchange_Report_24102017.html
    SendEmail: $True
    C:\Test-ExchangeServerHealth.ps1 : Cannot bind argument to parameter ‘ReportFile’ because it is an empty string.
    At line:1 char:32
    + .\Test-ExchangeServerHealth.ps1 <<<<
    + CategoryInfo : InvalidData: (:) [Test-ExchangeServerHealth.ps1], ParameterBindingValidationException
    + FullyQualifiedErrorId : ParameterArgumentValidationErrorEmptyStringNotAllowed,Test-ExchangeServerHealth.ps1"

    Best Regards
    Amaro Maguni

    1. Mark

      If you add the parameter -ReportFile you should define a reportfile, something like:

      Test-ExchangeServerHealth.ps1 -ReportFile “HealthReport.html”

      The desciption in the help is:

      .PARAMETER ReportFile
      Allows you to specify a different HTML report file name than the default.

      The paramter is optional, you don’t have to use it.

      1. Amaro Maguni

        Hi Mark,

        I am struggling with the “SendEmail” parameter, not the “Report File”.
        If I don’t use the “Send mail” the script works fine!
        Thanks for the tip, anyway!

        1. Mark

          Ah, the error you gave is:

          ‘Cannot bind argument to parameter ‘ReportFile’ because it is an empty string.’

          When you use the e-mail paramter you probably have to define the -ReportFile parameter i think because this is the description: ‘Sends the HTML report’.

          .PARAMETER ReportFile
          Allows you to specify a different HTML report file name than the default.

          .PARAMETER SendEmail
          Sends the HTML report via email using the SMTP configuration within the script.

          1. Amaro Maguni

            I am running “.\Test-ExchangeServerHealth.ps1” command.
            with this changes in the script, below:

            “[Parameter( Mandatory=$True)]
            [string]$ReportFile=”exchangeserverhealth.html”,

            [Parameter( Mandatory=$True)]
            [switch]$SendEmail,”

          2. Avatar photo
            Paul Cunningham

            Setting the parameters to mandatory means you must use those parameters. So if you’re then running the script without parameters, it will throw an error and not run.

            I suggest you revert the changes you made to the script code itself, and just run the script with the desired parameters.

  83. Andi

    cool script, but can you put the
    Get-ServerComponentState
    in the script?
    thx Andi
    from Germany

  84. misterht

    There is another script by Paul for All Mailboxes in the Organization called Get-MailboxReport.ps1. BTW, if you put in the correct parameters the Test-ExchangeServerHealth works beautifully. Just need to be a little bit savvy about your own site and entries.

  85. Rajeesh

    Hi Paul,

    Thanks for this wonderful script!

    How can i add mailbox count per server or DB in this report? can you guide?

    Thanks!

    Rajeesh

  86. prasant

    Hi Paul,

    Thanks for the script, I have been using your script for a while successfuly. Now I am using your script in new organization where I have second DAG member on offsite connected through 100 mb / for both upstream and downstream connection.
    I do get yellow flag on “quorum group” and “database availability group”. Though, it appears to be failing over on shutdown and does show OK on get-databasecopystatus * or test. I would presume the remote server reporting as “unable to retrieve uptime” and “could not test service health” is because of slow pipe

  87. geots

    Hi Paul,

    is it possible to fix the issue on the script with Mail Flow Test failing on remote Exchange 2016 servers?

    Thanks

  88. misterht

    Sir Paul,
    Have the script been updated with all the little things you mentioned in the comments, lately?
    Thanks.

      1. misterht

        Like DAG Copy Status check and to only email when alerts are detected. Those are old comments and I’m thinking you may already have updated those. Thank you very much for a great script that makes and Exchange Admin’s life easier.

        1. Avatar photo
          Paul Cunningham

          Yes, both those features are in the script. You can download the latest version and try it.

          1. John

            Thanks!

            I have one other thing that is having issues. I am able to generate an HTML report. However,

            #……………………………..
            # Modify these Email Settings
            #……………………………..

            $smtpsettings = @{
            To = “administrator@exchangeserverpro.net”
            From = “exchangeserver@exchangeserverpro.net”
            Subject = “Exchange Server Health Report – $now”
            SmtpServer = “smtp.exchangeserverpro.net”
            }

            Does not seem to work for me. When I use:

            param(
            [string]$to,
            [string]$subject,
            [string]$body
            )

            $smtpServer = removed
            $smtpFrom = removed
            $smtpTo = removed
            $messageSubject = “test”
            $messageBody = “test”

            $smtp = New-Object Net.Mail.SmtpClient($smtpServer)
            $smtp.Send($smtpFrom,$smtpTo,$messagesubject,$messagebody)

            I get a test Email. Is there something I’m missing that I am not able to get the report? I am on the highest Server with admin rights.

            .\Test-ExchangeServerHealth.ps1 -ReportMode -SendEmail

            Seems to generate only the report. Scheduled tasks shows completed but does not generate a report or email.

            Thanks!!!!!!!!

          2. Avatar photo
            Paul Cunningham

            John, run the script in the Exchange Management Shell and look for errors in the output when the mail sends. There’s also a -Log parameter for the script which might capture some useful info.

            You can also look at the protocol logs on the SMTP server you’re using to see if/why it’s rejecting the mail.

  89. Tony

    Hi Paul,

    Just come across your script on one of our servers and am running it against a 3 node Exchange 2013 cluster.

    In the email I am getting 3 ‘Exchange Server Health’ sections each with all three Servers listed which is confusing. Is this normal?

    Thanks
    Tony

    1. Avatar photo
      Paul Cunningham

      No that’s not normal, but without seeing the report and log file there’s not much else I can say.

      1. Tony

        Thanks Paul,
        Ran the report again this morning and it worked as expected. Didn’t have a log file from previous attempts so couldn’t send you one (ran with -log this morning).

  90. Yogesh

    Hi Paul,

    I have run the script, and it’s running well, But I am not getting output on mail.

    Could you please send me the correct script with required change.

  91. Allen

    HI Paul,
    My system environment is in Chinese version, running script error

    Add-Member : Cannot bind argument to parameter ‘Name’ because it is null.
    At D:\Test-ExchangeServerHealth\Test-ExchangeServerHealth.ps1:893 char:75
    + $serverObj | Add-Member NoteProperty -Name <<<< $serverinfoservices -Value $svchealth -Force
    + CategoryInfo : InvalidData: (:) [Add-Member], ParameterBindingValidationException
    + FullyQualifiedErrorId : ParameterArgumentValidationErrorNullNotAllowed,Microsoft.PowerShell.Commands.AddMemberCommand

  92. Allen

    Hi Paul
    Add-Member : 无法将参数绑定到参数“Name”,因为该参数是空值。
    所在位置 D:\Test-ExchangeServerHealth\Test-ExchangeServerHealth12.ps1:893 字符: 75
    + $serverObj | Add-Member NoteProperty -Name <<<< $serverinfoservices -Value $svchealth -Force
    + CategoryInfo : InvalidData: (:) [Add-Member], ParameterBindingValidationException
    + FullyQualifiedErrorId : ParameterArgumentValidationErrorNullNotAllowed,Microsoft.PowerShell.Commands.AddMemberCommand

    1. Allen

      if ($Log) {Write-Logfile “$serverinfoservices status is $svchealth”}
      $serverObj | Add-Member NoteProperty -Name $serverinfoservices -Value $svchealth -Force

  93. Amit

    Hello Paul,

    Did you get a chance to look the test-mailflow error what i pasted in detail, can you suggest what best can be done here.

    1. Avatar photo
      Paul Cunningham

      The error doesn’t occur in my test environment, so there’s not much I can do to troubleshoot it. I suggest you try manually running the Test-Mailflow command and see if that reveals any hints for you.

      1. Mark Bolten

        Paul,

        i receive the same error. Some short investigation tells me this:

        The script does this:
        Connect-ExchangeServer -auto -AllowClobber

        I changed it to connect to ‘Server1’ than i receive a mail flow test failure on ‘Server2’. When i connect to ‘Server2’ i recive a mail flow test failure on ‘Server1’. Not sure wich IP is used to send the e-mail from but it might that it is not possible to send an e-mail between the exchange servers? I will try to invstigate this issue to give some more details.

        1. Mark Bolten

          When i run this manualy, i get ‘Success’ as a result. I run the script from a non exchange server with only the management tools installed.

          $url = “http://Server1/powershell”
          OR
          $url = “http://Server2/powershell”

          $session = New-PSSession -ConfigurationName Microsoft.Exchange -ConnectionUri $url -ErrorAction STOP

          $result = Invoke-Command -Session $session {Test-Mailflow} -ErrorAction STOP

          $e15mailflowresult = $result.TestMailflowResult

          $e15mailflowresult

          —–

          When i run this directly on both exchange servers, i get succes as well.
          Test-Mailflow -TargetMailboxServer Server1
          Test-Mailflow -TargetMailboxServer Server2

          Any clues?

          1. Mark Bolten

            Running the Test-ExchangeServerHealth directly on the Exchange servers generates the same error ‘Mail flow test: [Microsoft.Mapi.MapiExceptionSendAsDenied]: MapiExceptionSendAsDenied: Unable to submit message. (hr=0x80070005, ec=1244)’

  94. aKSHAY bAHIRAM

    hello Paul,
    We have changed the details suggested by you & I have put my email address in the from field. I am not sure whats wrong with the report or whats mistaken from my end but I do not receive output email

    1. Avatar photo
      Paul Cunningham

      Use the -Log parameter to output a log file when the script runs. The log file might have some clues why the SMTP send at the end is not working.

  95. Amit

    Hello Paul,

    While running the script getting the below error during the Test- Mail flow , is any can be done to get rid of this issue and get a successful result.

    DNS Check: Pass
    Ping Check: Pass
    Uptime (hrs): 186
    Server version: Exchange 2013
    Roles: Mailbox, ClientAccess
    Mailbox Server Role Services: Pass
    Client Access Server Role Services: Pass
    Unified Messaging Server Role Services: Pass
    Hub Transport Server Role Services: Pass
    Total Queue: 0
    Mailbox databases mounted: Pass
    MAPI connectivity: Success
    Mail flow test: [Microsoft.Mapi.MapiExceptionSendAsDenied]: MapiExceptionSendAsDenied: Unable to submit message. (hr=0x8
    0070005, ec=1244)
    Diagnostic context:
    Lid: 40487 EMSMDBMT.EcDoRpcExt2 called [length=46]
    Lid: 56871 EMSMDBMT.EcDoRpcExt2 returned [ec=0x0][length=304][latency=296]
    Lid: 52176 ClientVersion: 15.0.1320.4
    Lid: 50032 ServerVersion: 15.0.1320.4
    Lid: 23226 — ROP Parse Start —
    Lid: 27962 ROP: ropSubmitMessage [50]
    Lid: 17082 ROP Error: 0x4DC
    Lid: 27745
    Lid: 21921 StoreEc: 0x4DC
    Lid: 27962 ROP: ropExtendedError [250]
    Lid: 1494 —- Remote Context Beg —-
    Lid: 41788
    Lid: 44092
    Lid: 41232
    Lid: 60208
    Lid: 37136
    Lid: 34608
    Lid: 55056
    Lid: 42768
    Lid: 56112
    Lid: 33016 StoreEc: 0x4DC
    Lid: 63016 dwParam: 0x32
    Lid: 39640 StoreEc: 0x4DC
    Lid: 10786 dwParam: 0x0 Msg: 15.00.1320.000:EXCSRV13PRDN01
    Lid: 1750 —- Remote Context End —-
    Lid: 26849
    Lid: 21817 ROP Failure: 0x4DC
    Lid: 60547 StoreEc: 0x4DC
    Lid: 21966
    Lid: 30158 StoreEc: 0x4DC
    —— Finishing
    Done.

    1. mario

      have you had any success with this?

  96. ajit

    Hello Paul,

    Thank you for the excellent script
    I am adding the list of servers which should be excluded in the health checks in ignorelist.txt

    However it is not working
    The script is modified
    ignorelistfile = “$myDir\ignorelist.txt”

    It is replaced with
    gnorelistfile = “e:\scripts\ignorelist.txt”

  97. David McCarthy

    Yes, running the V1.16, 13/04/2017. We did find recently that our AD replication was slow and causing trouble with our lagged copies but that has been resolved. In about 10-12 days we’ll be patching and rebooting again so that may change the situation. I did sort of fix the Preference column but the rest still eludes me.

    Thanks!

    1. David McCarthy

      Hi Paul, is there a way to check the health of our lagged copies, short of forcing them to play down the logs?

      1. Avatar photo
        Paul Cunningham

        Exchange checks that for you. You can see their health in the Get-MailboxDatabaseCopyStatus output.

  98. David McCarthy

    Hi Paul, your generous postings have helped us many times over the last couple years, thank you! A recent issue I have noticed since we installed CU5 on our E2016 on premise is this health report output has changed for us. It could be our environment but I thought I’d mention it although I am attempting some modifications to the script as an exercise in learning powershell better. Under the health summary section, the Preferences column is empty and the Lagged Queues column shows 0 instead of 1 for us. Likewise under Health Details the Activation Preference has no entries, and under Member Health the Server column is now empty.

    It seems to be having trouble with lagged copies now, but again it may be just us and not the script. It shows as:
    Database Availability Group Health Check Summary
    The following DAG errors and warnings were detected.
    • DB101 – healthy copy/replay queue count is 3 (of 4 )
    • DB102 – healthy copy/replay queue count is 3 (of 4 )
    • DB103 – healthy copy/replay queue count is 3 (of 4 )
    • DB104 – healthy copy/replay queue count is 3 (of 4 )
    etc.

    Thanks again for such a helpful blog!
    Best Regards,
    David

  99. Matt White

    I’m not sure if this has already been commented on in the previous 800+ posts but I was having issue with the script executing via Scheduled Task. I believe it was due to the execution policy on the local machine, even though I have “Run with the highest privileges” checked and running with domain admin/local admin credentials.

    Try running the argument with the following switches:

    -noprofile -executionpolicy bypass -file C:\LocationsOfFileTest-ExchangeServerHealth.ps1 -Log -SendEmail

    Works fine for me now.

    Hope that helps anyone experiencing the same issue.

  100. Jason

    Hi Paul

    Thanks for this useful script

    We were experiencing Event ID 9045 “Service MSExchangeMailboxAssistants. The assistant Junk E-mail Options Assistant stopped processing database DAG Mailbox Database 1 (855a438f-30d4-4615-b074-3e1e7a669935) because the database is in an unhealthy state.” errors every 15 mins – when checking the DAG it appeared to be healthy however and test replication health returned success for both mail nodes. I ran your script and whilst it did error in a couple of places it seemed to test everything ok – the next morning however users were met with a message ‘your administrator has made changes that require you to restart outlook’

    I don’t think the maibox moved between DAG/nodes or anything – have you seen this happen before?

    Many thanks in advance, Jason

    1. Avatar photo
      Paul Cunningham

      Database replication might be healthy but the database itself might have some problems. You should open a support case with Microsoft for advice n that one, or if it’s confined to a single database you could also create a new DB and evacuate that suspect DB and get rid of it.

      The restart message in Outlook is possibly due to a DB failover between DAG notes. If any of your CAS namespaces or other vdir settings are inconsistent then clients might see those types of messages. Run https://exchangeanalyzer.com/ if you want to quickly check for obvious issues.

      1. Jason

        Hi Paul

        Many thanks for taking the time to reply. I’ll check this out

        Regards

        Jason

  101. Preston

    I run this script in both my Exchange 2010 environment and my 2016 environment.

    I am seeing errors in my 2016 environment:
    Starting a command on the remote server failed with the following error message: The I/O operation has been aborted because of either a threat exit or an application request.

    Also:
    The request fro the WIndows Remote Shell with Shell ID *** failed because the shell was not found on the server. Possible causes are: the specified ShellID is inccorect or the shell no longer exists on the server.

  102. chris

    Hello Paul
    we use your script exchange-server-health. A great Code and great tool.
    we use it with -SendEMail -AlertsOnly Parameter.

    Is it posible that change the warning limits, because now we become to many Mail with warnings?
    Example – today:
    yellow Healthy Queues Unhealthy Queues 1
    and
    yellow Replay Queue = 21
    I think thats to small limit für 2 Exchange with 1000 Users

    great tool – thanks to all

  103. Kamal

    Is there is a way to include the following information to the part of the report.
    Mailbox server hosting active copy
    Database Size and whitespace
    Mailbox Count on each database
    Mailbox Average Sizes
    Database and log disk free space
    Last Full Backup
    Mailbox database Queue status
    Mail Queue status on HUB server

  104. Aftab

    Hi Paul,

    is there a way to convert the report to pdf? and then mail it out as an attachment?

    Thanks.

    1. Avatar photo
      Paul Cunningham

      I haven’t looked into it. Perhaps there is some PowerShell modules that can handle that. Sounds like an interesting customization for you to try out, but I won’t be adding it myself.

  105. Aftab Mohammed

    Hi Paul,
    I seem to get the below error but am not sure how I can resolve this:
    Mail flow test: WARNING: Connecting to remote server uk.olayan.net failed with the following error message : WinRM cannot process the
    request. The following error occurred while using Kerberos authentication: Cannot find the computer uk.xxxx.net.
    Verify that the computer exists on the network and that the name provided is spelled correctly. For more information,
    see the about_Remote_Troubleshooting Help topic.
    WARNING: Cannot validate argument on parameter ‘Session’. The argument is null or empty. Provide an argument that is
    not null or empty, and then try the command again.
    Remove-PSSession : Cannot validate argument on parameter ‘Id’. The argument is null. Provide a valid value for the
    argument, and then try running the command again.
    At C:\support\ExchangeServerHealth\Test-ExchangeServerHealth.ps1:452 char:22
    + Remove-PSSession $session.Id
    + ~~~~~~~~~~~
    + CategoryInfo : InvalidData: (:) [Remove-PSSession], ParameterBindingValidationException
    + FullyQualifiedErrorId : ParameterArgumentValidationError,Microsoft.PowerShell.Commands.RemovePSSessionCommand

    Fail

  106. Hans Kristian

    Thanks for a great script Paul,

    Have you considered adding a check for inactive component states?
    I ended up running a modified version of Mr Loeber’s Get-Exchange2013ComponentStateHistory script alongside your health check script since my HLB didnt pick up on the inactive states.

  107. Alex

    Paul,

    Can you implement what Rosario did in future releases?

    – local Drives: Capacity, Used, Free Space

    – Mount Points: our DBs are directly attached via SAN now, so again, MountPoint Name, Capacity, Used, Free Space

    – DB statistics: DB Size, Number of Mailboxes, Mailbox Average Size, WhiteSpace in DB, Date of last FullBackup

    1. Rafal

      Paul,

      Same here, if possible can you please add?

      Especially the DB size can be useful as DAG will only failover if the DB is less than 1TB in Standard edition.

      Thanks for considering Paul.

  108. Csaba Papp

    Hi Paul,
    It is nice and healthful script. Many of the interested information is there. What I would add is: DB backup status (warning if the backup is older than 7 days), certificate expiration (warning if they expired or going to expire in X days), disk space issue (specially useful for LOG partion). Also, it would be nice to be able to exclude one or more counters from the report (adding “#” ..)
    Thank you.

  109. sean daly

    Hi
    ignorelist.txt is being ignored for me, it is stored in the same folder as the PS script
    Any ideas ?

    1. Avatar photo
      Paul Cunningham

      What do you see in the console or in the log when you run the script?

  110. Eric

    What does the result total queue mean? I have 598

    1. Avatar photo
      Paul Cunningham

      I don’t have a column named total queue in my report. Which section are you seeing that in? Are you using the latest script?

      1. Eric

        I should be, script Updated 4/13/2017

        Here’s a part of what I see when I run the powershell script:
        DNS Check: Pass
        Ping Check: Pass
        Uptime: 2717
        Server version: Exchange 2010
        Roles: ClientAccess, HubTrasport
        Client Access Server Role Services: Pass
        Hub Transport Server Role Services: Pass
        Total queue: 601 (This number is in red)

        Am I using the wrong one?

        1. Avatar photo
          Paul Cunningham

          No it just wasn’t clear that you were referring to the console output instead of the HTML report.

          Total queue is the number of messages in your transport queues. You can investigate that further by running the Get-Queue cmdlet.

  111. Patrick Tchuitio

    Paul,
    I just wanted to take a moment to say thanks for your work on this. Just brilliant! Works like a charm. Keep up the great work.

  112. Sukumar Reddy

    Hi Paul,

    I would like to run the health check on Edge Server alone. I have tried removing if from the line
    #Skipping Edge Transports for the general health check, as firewalls usually get
    #in the way. If you want to include them, remove this If.
    if ($IsEdge -ne $true)

    and also tried by changing the value to if ($IsEdge -ne $true) to if ($IsEdge -eq $true) but didn’t work.

    Coud you please help me with it?

    1. Avatar photo
      Paul Cunningham

      I haven’t written any test logic for Edge Transport servers, so I wouldn’t expect that to work at all.

  113. TonyD

    Hi Paul.
    Can anyone help with this issue

    Mail flow test: WARNING: Connecting to remote server mbox-2 failed with the following error message : The WinRM client c
    annot process
    the request. It cannot determine the content type of the HTTP response from the destination computer. The content type
    is absent or invalid. For more information, see the about_Remote_Troubleshooting Help topic.
    WARNING: Cannot validate argument on parameter ‘Session’. The argument is null or empty. Provide an argument that is
    not null or empty, and then try the command again.
    Remove-PSSession : Cannot validate argument on parameter ‘Id’. The argument is null. Provide a valid value for the
    argument, and then try running the command again.
    At C:\Scripts\Test-ExchangeServerHealth\Test-ExchangeServerHealth.ps1:450 char:22
    + Remove-PSSession $session.Id
    + ~~~~~~~~~~~
    + CategoryInfo : InvalidData: (:) [Remove-PSSession], ParameterBindingValidationException
    + FullyQualifiedErrorId : ParameterArgumentValidationError,Microsoft.PowerShell.Commands.RemovePSSessionCommand

    Fail

    Thank you

    1. Avatar photo
      Paul Cunningham

      Check whether you can create a PS remote session to that Exchange server manually. Might be something wrong with the WinRM config.

  114. Akash

    Paul, I am getting the error as below:

    —— Checking EXC02
    DNS Check: Pass
    Ping Check: Pass
    Uptime (hrs): 105
    Server version: Exchange 2016
    Roles: Mailbox
    Mailbox Server Role Services: Pass
    Client Access Server Role Services: Pass
    Unified Messaging Server Role Services: Pass
    Hub Transport Server Role Services: Pass
    Total Queue: 0
    Mailbox databases mounted: Pass
    MAPI connectivity: Success
    Mail flow test: WARNING: Connecting to remote server mail.cam.net.in failed with the following error message : WinRM cannot process the request. The following error occurred while using Kerberos authentication: Cannot find the computer mail.cam.net.in. Verify that the computer exists on the network and that the name provided is spelled correctly. For more information, see the abo
    ut_Remote_Troubleshooting Help topic.
    WARNING: Cannot validate argument on parameter ‘Session’. The argument is null or empty. Provide an argument that is not null or empty, and then try the command again.
    Remove-PSSession : Cannot validate argument on parameter ‘Id’. The argument is null. Provide a valid value for the argument, and then try running the command again.
    At C:\Users\admin\Downloads\Test-ExchangeServerHealth.ps1:450 char:22
    + Remove-PSSession $session.Id
    + ~~~~~~~~~~~
    + CategoryInfo : InvalidData: (:) [Remove-PSSession], ParameterBindingValidationException
    + FullyQualifiedErrorId : ParameterArgumentValidationError,Microsoft.PowerShell.Commands.RemovePSSessionCommand

    Fail
    —— Checking EXC50
    DNS Check: Pass
    Ping Check: Pass
    Uptime (hrs): 1231
    Server version: Exchange 2016
    Roles: Mailbox
    Mailbox Server Role Services: Pass
    Client Access Server Role Services: Pass
    Unified Messaging Server Role Services: Pass
    Hub Transport Server Role Services: Pass
    Total Queue: 0
    Mailbox databases mounted: Pass
    Mail flow test: No active mailbox databases
    —— Finishing
    Done.

    1. Avatar photo
      Paul Cunningham

      That error occurs when the PowerShell virtual directory has been configure with an alias for the URL.

  115. Kaan

    Mail flow test: *FAILURE*

    Only Exchange Server 1 is giving this error. I am checking queue viewer ;
    Last Error: 421 4.4.2 Connection dropped due to ConnectionReset

    I disabled Windows firewall and psychical firewall for exchange ip address. but problem still is continuing

    Malware agent status disable.

    can you help me ? Thanks.

  116. Mohammad Ajan

    power shell script output to HTM or CSV
    how we can add output method to the script

    1. Avatar photo
      Paul Cunningham

      The script already supports outputting to a HTML file.

      Output to CSV file is not included in the script. The structure of the data is not suitable for CSV format. If you need CSV output, you’ll need to customize the script to meet your requirements.

  117. Alex Graham

    I’ve just tried to run via scheduled task to send an email and no joy – ive even changed to run via the exchange management shell and then does send email but then just the headers and nothing else…

    To save me any time and changing all the code – is there a way we can just make the script to be persistent to just always send the email to the smtp settings?

    1. Avatar photo
      Paul Cunningham

      You can change the code around the Send-MailMessage commands so that it always sends the email, but it doesn’t sound like that will solve your problem. You can also output the report to HTML file to see whether the problem is with the data collection or the sending of the email itself. If the HTML report looks fine, then it’s an SMTP problem of some kind. If the HTML report is broken, then something else is wrong. There’s also the -Log switch which might help you with visibility into what’s going wrong.

      1. Mohammad Ajan

        Mohammad Ajan

        how we can get output of power shell script to HTM,CSV we want to click on this file and give me result in htm,or CSV how we can include htm output
        plese write here the method of output in the script

  118. Sithandiwe

    When I run the script (-sendemail), it does not output the DAG HEALTH SUMMARY and DAG HEALTH DETAILS, it only output Server Health check and DAG health member checks.

    1. Avatar photo
      Paul Cunningham

      Run the script in your Exchange Management Shell with the -Log parameter. Watch for errors on screen, or review the log file to see if there’s any issues. Make sure you haven’t added the DAG name to the ignorelist.txt file.

  119. none

    Version 1.15
    Line 424 references variable $testresult that does not exist anywhere else in the script… ??

  120. ajit

    Sending email.
    Send-MailMessage : Cannot validate argument on parameter ‘To’. The argument is null or empty. Supply an argument that i
    s not null or empty and then try the command again.
    At H:\Test-ExchangeServerHealth.ps1:2103 char:20
    + Send-MailMessage <<<< @smtpsettings -Body $htmlreport -BodyAsHtml -Encoding ([System.Text.Encoding]::UTF
    8)
    + CategoryInfo : InvalidData: (:) [Send-MailMessage], ParameterBindingValidationException
    + FullyQualifiedErrorId : ParameterArgumentValidationError,Microsoft.PowerShell.Commands.SendMailMessage

  121. ajit

    When script is run it show below error

    Sending email.
    Send-MailMessage : Cannot validate argument on parameter ‘To’. The argument is null or empty. Supply an argument that i
    s not null or empty and then try the command again.
    At H:\Test-ExchangeServerHealth.ps1:2103 char:20
    + Send-MailMessage <<<< @smtpsettings -Body $htmlreport -BodyAsHtml -Encoding ([System.Text.Encoding]::UTF
    8)
    + CategoryInfo : InvalidData: (:) [Send-MailMessage], ParameterBindingValidationException
    + FullyQualifiedErrorId : ParameterArgumentValidationError,Microsoft.PowerShell.Commands.SendMailMessage

  122. Parag

    While executing script in our environment it fails with below errors.

    [PS] C:\script>.\Test-ExchangeServerHealth.ps1
    Initializing…
    WARNING: The file C:\script\ignorelist.txt could not be found. No servers, DAGs or databases will be ignored.
    —— Checking EXSVR16A
    DNS Check: Pass
    Ping Check: Pass
    Uptime (hrs): 359
    Server version: Exchange 2016
    Roles: Mailbox
    Mailbox Server Role Services: Pass
    Client Access Server Role Services: Pass
    Unified Messaging Server Role Services: Pass
    Hub Transport Server Role Services: Pass
    Total Queue: 1
    Mailbox databases mounted: Pass
    MAPI connectivity: Success
    Mail flow test: WARNING: Cannot validate argument on parameter ‘Session’. The argument is null or empty. Provide an argu
    ment that is
    not null or empty, and then try the command again.
    Remove-PSSession : Cannot validate argument on parameter ‘Id’. The argument is null. Provide a valid value for the
    argument, and then try running the command again.
    At C:\script\Test-ExchangeServerHealth.ps1:426 char:19
    + Remove-PSSession $session.Id
    + ~~~~~~~~~~~
    + CategoryInfo : InvalidData: (:) [Remove-PSSession], ParameterBindingValidationException
    + FullyQualifiedErrorId : ParameterArgumentValidationError,Microsoft.PowerShell.Commands.RemovePSSessionCommand

    Fail
    —— Checking EXSVR16B
    DNS Check: Pass
    Ping Check: Pass
    Uptime (hrs): 359
    Server version: Exchange 2016
    Roles: Mailbox
    Mailbox Server Role Services: Pass
    Client Access Server Role Services: Pass
    Unified Messaging Server Role Services: Pass
    Hub Transport Server Role Services: Pass
    Total Queue: 4
    Mailbox databases mounted: Pass
    MAPI connectivity: Success
    Mail flow test: WARNING: Cannot validate argument on parameter ‘Session’. The argument is null or empty. Provide an argu
    ment that is
    not null or empty, and then try the command again.
    Remove-PSSession : Cannot validate argument on parameter ‘Id’. The argument is null. Provide a valid value for the
    argument, and then try running the command again.
    At C:\script\Test-ExchangeServerHealth.ps1:426 char:19
    + Remove-PSSession $session.Id
    + ~~~~~~~~~~~
    + CategoryInfo : InvalidData: (:) [Remove-PSSession], ParameterBindingValidationException
    + FullyQualifiedErrorId : ParameterArgumentValidationError,Microsoft.PowerShell.Commands.RemovePSSessionCommand

    Fail
    —— Finishing
    Done.
    We are using Exchange 2016

    1. Avatar photo
      Paul Cunningham

      See comment above. I’ll try and fix this as it seems to be impacting so many people.

    2. Ron

      We had the same error. It turned out that we had inadvertently changed our Powershell virtual directory URLs to use https and our load balancer name, so this script was failing to create a remote powershell session. We reverted the URLs back to the defaults (http://servername.domain.tld/powershell) and the error is gone.

  123. Joseph Liu

    I am using Exchange 2013 and have 4 mailbox servers in a DAG – three in primary site and one in DR site. I tried running the script in the three mailbox servers in the primary site and notice that the mail flow test always fails only in the server running the script while the mail flow test for other servers are OK. The error is shown below.

    **** Error begins ****
    Mail flow test: WARNING: Connecting to remote server tvm-exdb03 failed with the following error message : The WinRM client cannot process the request. It cannot determine the content type of the HTTP response from the destination computer. The content type is absent or invalid. For more information, see the about_Remote_Troubleshooting Help topic.
    WARNING: Cannot validate argument on parameter ‘Session’. The argument is null or empty. Supply an argument that is not null or empty and then try the command again.
    Remove-PSSession : Cannot validate argument on parameter ‘Id’. The argument is null. Supply a non-null argument and try the command again.
    At C:\work\Test-ExchangeServerHealth.ps1:426 char:19
    + Remove-PSSession $session.Id
    + ~~~~~~~~~~~
    + CategoryInfo : InvalidData: (:) [Remove-PSSession], ParameterBindingValidationException
    + FullyQualifiedErrorId : ParameterArgumentValidationError,Microsoft.PowerShell.Commands.RemovePSSessionCommand

    Fail
    **** Error ends ****

    Please kindly help.

    Exchange: 2013
    Windows: 2012 Standard
    Powershell: 3.0

    BTW, I think this script is great and very useful for doing health check of Exchange environment.

    Thanks and regards,

    Joseph Liu

    1. Avatar photo
      Paul Cunningham

      Seems a lot of people get that error, but I don’t have an immediate solution for you. I will try and fix it, since it seems to be such a widespread problem.

  124. Jeff Levin

    I spoke too quickly. Even though I got the script to run from the task scheduler and send email, the main data line in the report was blank. The log file reports “No DAGs found.”

    So I revised my batch file to include the server parameter:

    powershell.exe -PSConsoleFile “C:\Program Files\Microsoft\Exchange Server\V14\Bin\ExShell.psc1” -command “C:\scripts\Test-ExchangeServerHealth.ps1 -server myexchgsrv.mydomain.local -log -ReportMode -SendEmail”

    But that produces the produces a log file that terminates with the line, “could not find the server myexchgsrv.mydomain.local

    Both versions of the batch file work fine from the command line. Any idea of what could be causing the server to be unfindable when running from task scheduler?

  125. Prasad Jahagirdar

    Hi Paul, Thanks for your script but I am getting below error and mail flow Test is failing on one server “Jet-MBX1” only regularly with script whereas if I Test -mailflow on server manually it shows result as “success” so script is showing False result.
    How can we correct this, Please suggest. My email address is as shown below.

    Prasad.jahagirdar81@gmail.com

    mail flow test: WARNING: Connecting to remote server jet-mbx2 failed with the following error message : The WinRM client
    cannot proces
    the request. It cannot determine the content type of the HTTP response from the destination computer. The content type
    is absent or invalid. For more information, see the about_Remote_Troubleshooting Help topic.
    ARNING: Cannot validate argument on parameter ‘Session’. The argument is null or empty. Provide an argument that is
    ot null or empty, and then try the command again.

    The WinRM client cannot proces the request. It cannot determine the content type of the HTTP response from the destination computer

  126. Padmaraj Vykundam

    Thank you Paul, Great work…

    I would like to schedule this report on daily basis How can i write ? Can you please help on this.

    Thank you

  127. Ketz

    Thank you Paul. great script.

    we have ben running this since few months and since yesterday we are getting error

    Could not test service health. : System.Management.Automation.RemoteException: Couldn’t get information about the Excha
    nge services using Windows Management Instrumentation (WMI) due to error: WMI exception occurred on server Access is denied. (Exception from HRESULT: 0x80070005 (E_ACCESSDENIED)).

    trying to figure it out but no clue.

      1. Ketan

        Now we sre getting access denied for all servers in the domain.

  128. Phil

    $unhealthyindexes = @($copies | Where-Object { ($_.”Content Index” -ne “Healthy” -and $_.”Content Index” -ne “Disabled” -or $_.”Content Index” -ne “AutoSuspended”) }).Count

    Ignore autosuspended for $unhealthyindexes since those are no unhealthy.. they are autosuspended 🙂

    1. Phil

      -and not -or.. argh! sorry

      $unhealthyindexes = @($copies | Where-Object { ($_.”Content Index” -ne “Healthy” -and $_.”Content Index” -ne “Disabled” -and $_.”Content Index” -ne “AutoSuspended”) }).Count

    2. Aikiox

      I confirm, I also modified the script to ignore the AutoSuspended. I’ve added it to the Git but Paul Cunningham has not yet accepted the Pull. https://github.com/cunninghamp/Test-ExchangeServerHealth.ps1/commit/576d5d41f8e7b32225f079f5df155ca8ef41be6b

      I have added a control of the space of the partitions of the servers as well as the location of the bases. I also added a ratio between the size of the base and the free space of it in order not to save space for nothing (if there is backup) : https://github.com/aikiox/Test-ExchangeServerHealth.ps1/tree/patch-1

  129. Ranjith

    Thanks for such a good Script.
    We were trying to customize it to our requirement so was trying to understand the script, we are not a full time programmer.
    Could you please explain how the following commands works, because these variables were not declared in Param, please help us understand.

    Function New-DAGMemberHTMLTableCell()
    {
    param( $lineitem ) –> What is the value of this, what it does?
    $htmltablecell = $null
    switch ($($line.”$lineitem”)) –> What is $($line.”$lineitem”)? please help me understand?
    {
    $null { $htmltablecell = “n/a” }
    “Passed” { $htmltablecell = “$($line.”$lineitem”)” }
    default { $htmltablecell = “$($line.”$lineitem”)” }
    }
    return $htmltablecell
    }

    Like wise,
    param( $logentry )
    param ( $e15cas )
    param ( $e15cas )
    param ( $e15mailboxserver )
    param ( $e14mailboxserver )
    None of the above are declared in Param command, but still it works, how?

    1. Avatar photo
      Paul Cunningham

      Short answer, variables don’t need to be declared in param. Param is for script/function parameters.

  130. Aikiox

    Hello,
    I made a pull request on the Git to integrate the basic notion laggued with the status “AutoSuspended”. From the CU4, this new status allows to automatically pause the lagged bases to avoid overconsumption of the bandwidth. I opened a ticket at Microsoft to learn more about this status that is not documented. Here is the answer :
    I confirm that the Autosuspend of the passive bases lag is a normal behavior.
    We reproduce it and I have identified the change in the voluntary code.
    I guess the reason could be a gain in terms of CPU.
    In spec it appears that this change was made in order to reduce the consumed bandwidth to index the active database.
    I recommend you to keep it in autosuspend but you have the command if you want to reactivate the index as in CU1.

    Here is the command to disable this status:
    New-SettingOverride -Name DisableSkipLagCopy -Component Search -Section SkipLagCopy -Parameters @(“Enabled=false”) -Reason “Disable SkipLagCopy”
    The parameter is not taken into account dynamically, it is necessary to plan a reboot.
    After restarting, probably a reseed is necessary because the index is not up to date: Update-MailboxDatabaseCopy nomdelabase -CatalogOnly
    We have reproduced and checked on our DAG this procedure successfully to reactivate the index.

    In the Pull Request, I also added the exact version of the Exchange. It’s always nice to know which CU we have on which server.

    I also put the part “Queue” in function to try repeatedly if one is above the threshold. This is to avoid having alerts when we have just received an enormous amount of email at once.

    Romain

  131. Shaik Jahangir

    Hello Paul,

    I’m getting the below error when I run the script, Kindly help on this.

    WARNING: Connecting to remote server failed with the following error message : WinRM cannot
    process the
    request. The following error occurred while using Kerberos authentication: Cannot find the computer . Verify
    that the computer exists on the network and that the name provided is spelled correctly. For more information, see the
    about_Remote_Troubleshooting Help topic.
    WARNING: Cannot validate argument on parameter ‘Session’. The argument is null or empty. Provide an argument that is
    not null or empty, and then try the command again.
    Remove-PSSession : Cannot validate argument on parameter ‘Id’. The argument is null. Provide a valid value for the
    argument, and then try running the command again.
    At C:\temp\Test-ExchangeServerHealth.ps1:426 char:19
    + Remove-PSSession $session.Id
    + ~~~~~~~~~~~
    + CategoryInfo : InvalidData: (:) [Remove-PSSession], ParameterBindingValidationException
    + FullyQualifiedErrorId : ParameterArgumentValidationError,Microsoft.PowerShell.Commands.RemovePSSessionCommandFail

  132. Kumar

    Hi All

    Can we add oldest log files (Text files) info (Time stamp) with number of days old to the script as another column? Can you please help?

    Thanks

  133. Jeff Levin

    I’m another user who simply cannot get your script to run as a scheduled task. I’ve followed your instructions to the letter and experimented with modifications. Nothing works — the task scheduler just shows it running endlessly. The history hangs on event 110, “task triggered by user.” It stays there until you manually terminate.

    This command works perfectly in an administrative CMD shell:
    powershell.exe -command “C:\scripts\Test-ExchangeServerHealth.ps1 -Server myserver.mydomain.local -ReportMode -SendEmail”

    When you try to set it up as a scheduled task as follows:

    Run whether user is logged in or not
    Do not store password
    Run with highest privileges
    Action: start a program
    Program/script: powershell.exe
    Add arguments: -command “C:\scripts\Test-ExchangeServerHealth.ps1 -Server myexchange.mydomain.local -log -ReportMode -SendEmail”
    Allow task to be run on demand
    Stop the task if it runs longer than 1 hour
    If the running task does not end when requested, force it to stop

    it simply will not run. Can you tell me what I’m doing wrong? I don’t have any problem running a WSUS maintenance script in the same fashion.

    1. Avatar photo
      Paul Cunningham

      Use -Log and see if the log gives you any clues.

      But I would also suggest that “Do not store password” is going to cause a problem.

      1. Jeff Levin

        The log just says
        17 17:03:51 =====================================
        01/26/2017 17:03:51 Exchange Server Health Check
        01/26/2017 17:03:51 01/26/2017 17:03:51
        01/26/2017 17:03:51 =====================================
        01/26/2017 17:03:51 Initializing…
        01/26/2017 17:03:51 Loading the Exchange Server PowerShell snapin

        Is there a way to get task scheduler to use the special Exchange powershell? Or what needs to be added to your script to get the regular powershell to add the Exchange add-in?

        1. Avatar photo
          Paul Cunningham

          If you login with the creds that the scheduled task is running as, does the script work?

          1. Jeff Levin

            Yes, in both instances, it’s the domain administrator. Isn’t the problem one of being able to access the Exchange functionality? All sessions are being run on the Exchange server.

          2. Jeff Levin

            Is there something that needs to be in your profile so that the Exchange Server Powershell snapin is already loaded before the script begins executing?

          3. Avatar photo
            Paul Cunningham

            The script loads what it needs automatically, unless it can’t (e.g. due to permissions). I haven’t been able to repro your issue. I’d suggest creating a new service account and trying a different set of creds for the scheduled task.

          4. Jeff Levin

            Doesn’t the domain administrator have all of the permissions required? What is different (besides screen output) between running it in an administrative command shell and running it with the same account and full permissions from the task scheduler?

            It’s just a standard off-the-shelf Dell server with Server 2012 R2 and Exchange Server 2010 running on it. If you’re curious and would like to examine this mystery firsthand, that can be easily arranged.

          5. Avatar photo
            Paul Cunningham

            Depends what you think the “domain administrator” is. Members of Domain Admins or Administrators don’t get any Exchange admin permissions by default. Exchange has its own permissions model.

            This is your first mention of trying to run it on Exchange 2010. I’ll test on a 2010 box next chance I get. It should work, but I don’t recall the last time I tried it.

          6. Jeff Levin

            Thanks. If it works, please let me know the permissions that the account you use in task scheduler has. Meanwhile, I’ll continue to experiment on my end with permissions and let you know if I find anything.

        2. Jeff Levin

          JSYK: The domain administrator account that I’m using for both the command line and the scheduled task is also a member of the organization management group for the Exchange server.

        3. Avatar photo
          Paul Cunningham

          On an Exchange 2010 server this command is working fine (from cmd.exe and from task scheduler)

          powershell.exe -command “. C:\Scripts\ExchangeServerHealth\Test-ExchangeServerHealth.ps1 -Log -SendEmail”

          The scheduled task has “Run with highest privileges” ticked per my article above. Without that box being ticked the script stalls on “Loading the Exchange Server PowerShell snapin” in the log file.

          1. Jeff Levin

            Funny … if I modify my path for yours and paste this into an administrative command prompt

            powershell.exe -command “. C:\Scripts\Test-ExchangeServerHealth.ps1 -Log -SendEmail”

            All it does is display what’s between the quotes on the next line. If I remove the quotes and the period, it runs correctly from the command prompt. But as always happens — when I put a working command line into task scheduler with the highest privileges (as always), all I get is a neverending “running.” Could you please cut and paste what you have in the “program/script” and “add arguments” boxes of your working scheduled task?

        4. Avatar photo
          Paul Cunningham

          The program is powershell.exe and the arguments are

          -command “. C:\Scripts\ExchangeServerHealth\Test-ExchangeServerHealth.ps1 -Log -SendEmail”

          I’ve got Exchange 2010 running on WS2008R2, so if you’re on a different OS maybe there’s a PowerShell version thing that needs a different approach.

          1. Jeff Levin

            Hmmm … this is Exchange 2010 running on WS2012R2. Do you know of anyone successfully scheduling it on a similar platform that you can get the arguments from?

        5. Avatar photo
          Paul Cunningham

          Exchange 2010 isn’t supported to run on WS2012R2, so I don’t think you’ll find many people with that scenario.

          You could install the management tools on another server or workstation and run the scheduled task from there.

          1. Jeff Levin

            But it executes perfectly from the command line, so it should execute in the task scheduler as well. Regardless of the Exchange version, could you give me the entry in the parameters box in the task scheduler for a Server 2012 machine where scheduling works? And does installing the management tools on a server require installing Exchange Server 2010 as well? The only instructions I can find seem to say so. https://www.petri.com/install-exchange-2010-management-tools-windows-8

          2. Avatar photo
            Paul Cunningham

            The scheduled task settings I use are in the blog post above.

            The management tools can be installed on a workstation or server without installing the full Exchange server application itself. The tools are a separate role in setup as that blog you link to shows.

          3. Jeff Levin

            Yes, but those scheduled task settings are for WS2008 — they don’t work in WS2012 either as a scheduled task or as a command line. Do you (or anyone else) have the settings for the script working as a scheduled task in WS2012?

        6. Avatar photo
          Paul Cunningham

          I’ve given you what works for me with Exchange 2013 running on WS2012R2 (it’s in the blog post) and what works for me with Exchange 2010 running on WS2008R2 (in comments above).

          That’s all I’ve got I’m afraid. Looking around on Google there seems to be a variety of ways of “running PS scripts in task scheduler” that might have some version-specific nuances but all I can say is what works for me.

          1. Jeff Levin

            I found a solution:

            powershell.exe -PSConsoleFile “C:\Program Files\Microsoft\Exchange Server\V14\Bin\ExShell.psc1” -command “C:\scripts\Test-ExchangeServerHealth.ps1 -log -ReportMode -SendEmail”

            I put it in a BAT file, and it executes from task scheduler now. The console file makes all the difference.

  134. Michael Hart

    Paul,

    Great Script. VERY helpful. I do have a question that I am sure shows how much of a noob I am in Powershell. I am trying to figure out a way for the report name to automatically update with the date of the day it is run.

    Example: 022617.ESH.html instead of exchangeserverhealth.html

    1. Avatar photo
      Paul Cunningham

      There’s a variable in the script that sets the output file name. Just change that to whatever suits your needs.

  135. Anderson Hinojosa

    Paul consulta en mi reporte que me genera , en la columna UPTime me sale este mensaje: Unable to retrieve uptime y se sombrea de amarillo, esto es normal o a que se debe

  136. Martin Hughes

    Hi Paul, Awesome script, I use it to check the health of Exchange 2010 each mornning. I am experiencing a strange issue. I have 2 sites with 2 mailbox servers in each site, the main site has 3 client access\hub transport servers and the other site has 2 client access\hub transport servers. When I run the script as a scheduled task from the main site the report emails however 1 of the CA\HUB servers has the message “Unable to retrive uptime” for uptime hours & “could not test service health” for CAS, HUB, MB & UM. DNS, Ping & Transport queue pass. This only happens on one of the CAS servers on that subnet but I can run the test-servicehealth manually from the EMS.
    When I run the script from a schedule task from the secondary site 2 of the CAS\HUB servers in the main site have the same problem.
    Really hope you can help with this.
    Cheers
    Martin

  137. ErikL

    Paul, I reviewed the comments for this script spanning the last 4 years. I’m impressed with your on-going support. No problems to report, just wanted to drop a line to commend your efforts.

  138. ChrisH

    Paul,
    I commend you on all of the work and scripts you have for Exchange. I have used your resources countless times.
    I have recently implemented Exchange 2013 coexistence with Exchange 2010. No mailboxes have been moved to 2013 as of yet.
    When I run this script from 2013MB5 , I get three failures on mailboxes.
    Exchange 2010MB1, Exch2010MB2 and Exch2013MB5 – access denied
    12/12/2016 09:50:30 Initializing…
    12/12/2016 09:50:31 Loading the Exchange Server PowerShell snapin
    12/12/2016 09:50:37 Setting scope to entire forest
    12/12/2016 09:50:46 You have specified a single server to check
    12/12/2016 09:50:49 Beginning the server health checks
    12/12/2016 09:50:49 —— Checking Exch2010MB1
    12/12/2016 09:50:50 Checking DNS
    12/12/2016 09:50:51 DNS check passed
    12/12/2016 09:50:51 Checking ping
    12/12/2016 09:50:56 Ping test passed
    12/12/2016 09:50:56 Checking uptime
    12/12/2016 09:50:57 Uptime is 858 hours
    12/12/2016 09:50:57 Server is running Exchange 2010
    12/12/2016 09:50:57 Server roles: Mailbox
    12/12/2016 09:50:57 Checking service health
    12/12/2016 09:51:04 Mailbox Server Role Services status is Pass
    12/12/2016 09:51:04 Checking Mailbox Server
    12/12/2016 09:51:09 Checking public folder database
    12/12/2016 09:51:09 Public folder database status is Pass
    12/12/2016 09:51:09 Checking mailbox databases
    12/12/2016 09:51:09 Mailbox database status is Pass
    12/12/2016 09:51:09 Checking MAPI connectivity
    12/12/2016 09:51:16 MAPI connectivity status is Success
    12/12/2016 09:51:16 Checking mail flow
    12/12/2016 09:51:17 Processing data from remote server Exch2010MB1 failed with the following error message: Access is denied. For more information, see the about_Remote_Troubleshooting Help topic.
    12/12/2016 09:51:17 Cannot validate argument on parameter ‘Session’. The argument is null or empty. Provide an argument that is not null or empty, and then try the command again.
    12/12/2016 09:51:17 Mail flow status is Fail

    Exch2010MB3 and Exch2010MB4 pass with no errors

    If I run the script from a 2010MB, I get no errors and all tests pass.
    Any suggestions?

    1. Avatar photo
      Paul Cunningham

      The mail flow test tries to do a remoting session to the other servers as a hacky workaround for changes in the Test-MailFlow cmdlet when 2013 was released. It throws errors if the remoting session can’t be established. It’s not a great way of doing it, unfortunately.

  139. Jay

    Is there a specific way to setup the ignore list? No matter what I try, it never ignores the servers or DB’s I put in it. I have each one on a single line, no header, no quotes, but I’ve tried it every other way as well and still the report comes with every server that it shouldn’t be checking.

    I currently have 58 servers, 22 of which are 2010 in coexistance with Exchange 2013. I’m on the final stages of the 2010 before I decommission it so I don’t want these to clutter the report, but for the life of me I can’t get the script to ignore these.

    Any suggestions?

    Thanks!

    1. Jay

      NM, think I figured it out. It was ignoring the servers, but I didn’t put in the DB’s and DAG’s for all of those servers.
      Now I am getting only the 2013 servers as I wanted.

      Cheers!

      Now if I can just figure out how to get the scheduled task to work.

  140. stubbo

    Hello Paul –

    Thanks for the great scripts, we’ve been using the DAG health & backup status reports for several years.

    In case anybody’s wondering about the Kerberos error some correspondents have reported…

    The same thing cropped up in our environment with newly deployed Exchange 2016 servers and the latest version of Test-ExchangeServerHealth.ps1

    Mail flow test: WARNING: Connecting to remote server mail.DOMAIN.COM failed with the following error message : WinRM cannot process the request. The following error occurred while using Kerberos authentication: Cannot find the computer mail.DOMAIN.COM. Verify that the computer exists on the network and that the name provided is spelled correctly…

    During the initial server configuration we had set the virtual directories for Powershell on each Exchange server to use the load-balanced name…

    Set-PowerShellVirtualDirectory “$HostNamePowerShell (Default Web Site)” -InternalUrl “https://mail.DOMAIN.COM/Powershell”

    But this isn’t going to work here, so a crude workaround is to #REM out the IF construct around the line…

    $url = “http://$e15mailboxserver/powershell”

    i.e. forcing the script to use a URL incorporating the Exchange server name each time in the New-PSSession command

    Thanks again

    1. Adrian

      Test-mailflow always failed on mbx server hold passive copy DB. Any idea? Error message is same as what mentioned above.
      “WinRM…”

      1. peefee

        I tried the edit recommended by Stubbo but I’m having the same issue. Exchange 2016 with load balancer…

  141. avi

    Hi Paul,

    Love your script – I am new to powershells and this is wow.
    I follow the comments and having a problem running this scripts from the task scheduler.

    Its status is Running but its stays on like that until I end the task.

    my action is: start a program
    Program/script : C:WindowsSystem32WindowsPowerShellv1.0powershell.exe
    arguments : -ExecutionPolicy Bypass -NonInteractive -Command “& ‘C:PowershellscriptExchangeHealthTest-ExchangeServerHealth.ps1’ -ReportMode -SendEmail”

    If anyone made this work it would be great to know how

  142. Venkat

    Hi Paul,

    Could you help me on my request.

    ” have ran this report in my lab everything is perfect very perfect. but i personally feel if you help me to include Diskspace report that would be really helpful for us to understand the Logs drive space and DB drive space”

  143. Royal Wang

    sorry, it is fixed

  144. Royal Wang

    Hi Paul,

    thx 4 ur script, but i have one small problem. why not send one email ro my mailbox even i edit relative settings for SMTP?

  145. Venkat

    Hi Paul,

    i have ran this report in my lab everything is perfect very perfect. but i personally feel if you help me to include Diskspace report that would be really helpful for us to understand the Logs drive space and DB drive space.

  146. Asem Mahmoud

    Dear Paul ,

    when i try to execute your script its working but with the below error

    Script : The term ‘Script’ is not recognized as the name of a cmdlet, function, script file, or operable program. Check the spelling of the name, or
    if a path was included, verify that the path is correct and try again.
    At C:scriptsTest-ExchangeServerHealth.ps1:1 char:1
    + Script Içerigimiz:
    + ~~~~~~
    + CategoryInfo : ObjectNotFound: (Script:String) [], CommandNotFoundException
    + FullyQualifiedErrorId : CommandNotFoundException

    Initializing…
    Creating a new session for implicit remoting of “Get-ADServerSettings” command…
    The file C:ScriptsExchangeServerHealthignorelist.txt could not be found. No servers will be ignored.

  147. Christ

    Hello Paul,

    Hope you are doing well and thanks for the great work.

    I would like to know the syntax or how to create the ignorelist? when runing this script and get-daghealth also.

    Thanks again

  148. Steve Pasikowski

    Thanks for a great tool Paul.

    Our enviroment has Trend Micro ScanMail installed on the Exchange servers. As a result, there is an unmounted database on each server called “EUQ_ReportDatabase_” that is always in an unmounted status. Since the database is not mounted, it reports as a failure in the section “Exchange Server Health” for the column “MB DBs Mounted”.

    Adding these databases to the ignorelist cleans up the noise about them later in the report, but it appears that the ignorelist is not used in the first part of the report that generates the per-server health. They were also causing the MAPI test to fail but I was able to get around that by tweaking the code to only attempt a MAPI test for mounted databases.

    Any thoughts about incorporating the ignorelist into the earlier part of the script?

    Also, during the MAPI checks it looks like the line
    foreach ($db in $mbdbs)
    should probably be
    foreach ($db in $activedbs)

    1. Avatar photo
      Paul Cunningham

      Seems to be a bug. One of many that’s crept in over the years. I’ll see what I can do, but yeah if you spot fixes like that by all means update your copy of the script. Always happy to have bugs/issues and their fixes reported on Github as well where I don’t lose track of them.

  149. Adrian Jackson

    Hi,
    firstly great script, thank you.
    Recently the emailed reports have come through as horrible looking txt, rather than pretty HTML – I suspect after installing the last lot of MS Critical patches to both server 2012 r2 and server 2008 r2.

    Does anyone have an idea either which one, or what it is and how to fix it please ?

    Thanks.

  150. Ihtesham

    Great work…!!! thanks

  151. Fergus Strachan

    Jesus, Paul you must have the patience of a saint replying to some of these comments! (“Please make it PS1.0 compatible” – my reply would be much less measured. 😉 )

    Let me add my thanks for making this.

  152. MikaelJones

    Excellent script. In one environment I get a lot of “Quota violation” (like on the ping check) and “WARNING: Call cancelled”. Next time I run it it works so it seems pretty random. Any ideas?

      1. MikaelJones

        I suspect not since I run the check against 4 servers. I tried narrowing it down to only run it against 1 server and every time I get:
        —— Checking SERVER01
        DNS Check: Pass
        Ping Check: Pass
        Uptime (hrs): 2563
        Server version: Exchange 2013
        Roles: ClientAccess
        WARNING: Call cancelled
        Client Access Server Role Services : Fail
        —— Finishing

        Running CU12 and 2012 R2. Let me know if there are any manual tests you want me to perform to troubleshoot.

        1. MikaelJones

          Doing a manual Test-Connection SERVER01 works fine.

        2. MikaelJones

          I did a restart of the Exchange server in question and it seems like this solved the problem. I will do the same with the other servers to see if this solves the problem. So maybe the 100+ days uptime is the cause 🙂

  153. Pierre-Yves PAVAGEAU

    Hello,

    Still amazing your script. I have just add a modification a long time ago and just reported it to your last version because we are in 2010/2013 cohabitation now, so I need to run your script on the 2013 server instead of the 2010 like said in your documentation.

    I just wanted to put this modification here. The goal of my modificaiton is to have the script running every 15 min and send an e-mail only if necessary :

    ##### ADDED by Pierre-Yves Pavageau
    ##### This part is added at the line 175 (after the SMTP parameters)
    ##### Script is started every 15 min by a scheduled task
    ##### Every 24h an e-mail is sent just to inform that the script is still working
    ##### If i do not receive this e-mail i check the script or the Scheduled task to see what could be wrong

    $ErrorFile = “$myDirerror.txt” # # I am using a file to write error or OK in it (see below the second part of my modification)
    $ErrorValue = Get-Content $ErrorFile

    $compteurFile = “$myDircompteur.txt” I am using a file to increment a value in it (15min * 96 = 24H)
    [INT]$cptDay = Get-Content $compteurFile
    if($cptDay -eq 96) # (15min * 96 = 24H)
    {
    $cptDay = 1
    $cptDay | Out-File $compteurFile ## Setting back to 1 the value in the file compteur.txt

    $SmtpClient = New-Object system.net.mail.smtpClient
    $SmtpClient.host = $smtpsettings.SmtpServer

    ## Generate the report and email it as a HTML body of an email
    $emailContent = “This e-mail is sent just to confirm that the Script which monitors Exchange functionnality is still working. Next e-mail in 24H.”

    $MailMessage2 = New-Object system.net.mail.mailmessage
    $MailMessage2.from = $smtpsettings.From
    foreach ($smtpsetting in $smtpsettings.To)
    {
    $MailMessage2.To.add($smtpsetting) ## Email recipient
    }
    $MailMessage2.Subject = “[EXCHANGE] MONITORING WORKING FINE” ## Objet du mail
    $MailMessage2.IsBodyHtml = 1
    $MailMessage2.Body = $emailContent
    $SmtpClient.Send($MailMessage2)
    }
    elseif($cptDay -lt 96)
    {
    $cptDay +=1
    $cptDay | Out-File $compteurFile
    }

    ##### ADDED by Pierre-Yves Pavageau
    ##### This part is added at the line 2090
    ##### If no issue is found, then no e-mail is sent
    ##### If no issue if found but we had an issue at the last scan we send an e-mail to inform that is back to normal status
    ##### If issue is found, then an e-mail is sent

    I changed this :
    if ($SendEmail)
    {
    if ($alerts -eq $false -and $AlertsOnly -eq $true)
    {
    #Do not send email message
    Write-Host $string19
    if ($Log) {Write-Logfile $string19}
    }
    else
    {
    #Send email message
    Write-Host $string14
    Send-MailMessage @smtpsettings -Body $htmlreport -BodyAsHtml -Encoding ([System.Text.Encoding]::UTF8)
    }
    }

    To this

    if ($SendEmail)
    {
    write-host “We will send an e-mail”
    if ($alerts -eq $false -and $AlertsOnly -eq $true)
    #if ($alerts -eq $false)
    {
    #Do not send email message Except if ErrorValue is set to Error
    Write-Host $string19
    if ($Log) {Write-Logfile $string19}
    write-host “Display the error value $($ErrorValue)”
    if ($ErrorValue -like “Error”)
    {
    Write-host “There is no more errors or warning”
    $SmtpClient = New-Object system.net.mail.smtpClient
    $SmtpClient.host = $smtpsettings.SmtpServer
    ## Generate the report and email it as a HTML body of an email
    $emailContent = “This e-mail is sent just to inform you that the EXCHANGE infrastructure is back in normal status.”
    $MailMessage2 = New-Object system.net.mail.mailmessage
    $MailMessage2.from = $smtpsettings.From
    foreach($smtpsetting in $smtpsettings.To)
    {
    $MailMessage2.To.add($smtpsetting) ## Email recipient
    }
    $MailMessage2.Subject = “[EXCHANGE-MONITORING] BACK IN NORMAL STATE” ## Objet du mail
    $MailMessage2.IsBodyHtml = 1
    $MailMessage2.Body = $emailContent
    $SmtpClient.Send($MailMessage2)

    # Writing OK to error file
    $temp1 = “OK”
    $temp1 | out-file $ErrorFile
    }
    }
    else
    {
    #Send email message
    Write-Host $string14
    Write-host “We found a warning or a fail in the report, so we send the e-mail”
    Send-MailMessage @smtpsettings -Body $htmlreport -BodyAsHtml -Encoding ([System.Text.Encoding]::UTF8)
    # Writing Error to error file
    $temp = “error”
    $temp | out-file $ErrorFile
    }
    }

  154. Jeff Cothern

    We have a large environment for a customer that has some other business units that have a separate contract for their Exchange servers that are part of the same Exchange Org. We do not manage or have access to those servers.

    I am looking for the best way to use your script to only report for our servers.

    I have attempted to use the -serverlist switch but it only reports on the servers and not the DAG and database information on those server. Using the ignorelist.txt is a little impractical because its a very long list and new servers don’t necessarily get communicated to us.

    Also we have to run the script multiple times to split up our servers and DAGs just to keep the report to a manageable small size.

    So wanted to see options before I delve into modification of the script.

    1. Pierre-Yves PAVAGEAU

      @Jeff

      If you are in the same Exchange Org, isn’t it possible to do this :
      Get all the servers in the Org,
      Filter the list to keep only the one you have under monitoring
      Add the servers not managed by your self to the ignorelist.txt

      Let me know if it helps ?

  155. MetaFR

    Hello,

    Firstly thanks for the code.
    As localised exchange /powershell are, there are some glitch with french version. (Or french a glitch on it’s own ? 😉

    The mailflow routine return “Réussite” and not “Success” , while it’s OK in the case of a “fail” , because anything different than “Réussite” or “Success” is either and error or a fail.

    so for exchange 2013 french localized modify as is :

    line 1141 :
    if ($e15mailflowresult -eq “Réussite” -or $testmailflowresult -eq $success )

    line 1176 :
    if ($testmailflowresult -eq “Réussite” -or $testmailflowresult -eq $success)

    and then script will return correct value in the report

    1. Avatar photo
      Paul Cunningham

      In the blog post above there’s instructions for how to use the existing variables in the script to handle language issues.

      1. MetaFR

        I agree. I partially did but for $success , I was not sure it needed to be edited or not because of being used to partially localized command return ..so I went ahead only editing smtp.
        then got error for the mailflow.
        So , looking closely on line 1176 and 1141, I found that one (1141) as a -eq test with $success and the other one with -eq “success” -or -eq $success and since I initialy dit not localized $success at all and powershell wont return “success” anyway , that’s why I had a wrong return here.
        but I forgot about that $success declaration of you.
        goldfish mode 🙂
        thank you

  156. Elmer

    Hi Paul, first of all thank you for this script that is useful.

    I would like your comment with the following drawback: I have the Escript in scheduled tasks and run it does not show me the following information:

    Database Information
    Exchange Server Exchange Exchange DB DB (GB) Number of Users

    Backup Exchagne Details
    Database Server Name Last Name Last Full Backup Incremental Backup

    But if I run without the Task Scheduler if you show me the entire report.

    First of all thanks

  157. Mahalakshmi

    Thanks for the script. Its very much helpful for us. Can you please advise how to get only “Database Availability Group Health Details” table on the email, since we have planned to send this report alone to all L1 and L2 support guys and we do not wish to send them all other details.

  158. rino19ny

    almost done then got this:

    Mail flow test: WARNING: Connecting to remote server mb2 failed with the following error message : The WinRM client
    cannot process
    the request. It cannot determine the content type of the HTTP response from the destination computer. The content type
    is absent or invalid. For more information, see the about_Remote_Troubleshooting Help topic.
    WARNING: Cannot validate argument on parameter ‘Session’. The argument is null or empty. Provide an argument that is
    not null or empty, and then try the command again.

  159. Jason

    Hi Paul,
    Excellent script.

    I’ve been having problems with it not detecting my lagged copies propery. There are 4x copies that are lagged at 2 days. The script does not report them as a lagged copy and errors against the given DAG copy, as the replay queue is quite high.

    It seems the script is not returning the lagged copies under variable $replaylagcopies
    When I echo the command to the console with the “Where-Object {$_.Value -gt 0}” filter it returns no copies. When I run the command without the filter it returns all copies:

    $database | Select -ExpandProperty ReplayLagTimes

    [DCA-EXCH-MBX01, 00:00:00]
    [DCA-EXCH-MBX02, 00:00:00]
    [DCB-EXCH-MBX03, 00:00:00]
    [ADLHB-EXCH-MBX4, 2.00:00:00]

    Given this it seems the filter is not matching correcty.

    I’m running Exchange 2013 SP1 CU13 (current) on Server 2012 R2.
    I did try this script out in January with CU11 and had the same issue, so I don’t think it’s been caused by a recent CU.

    Would much appreciate your insights.
    Jason

    1. Jason

      Hi Paul / All,
      I solved this after also discovering that it was returning a null value for the activation preference. I noted that Sanju (December 29, 2015 at 4:31 pm) provided a fix for the null preference value above.

      Applying the same logic to the lagged copy checks works. It’s probably a little messy but it works.
      Would like to hear of a ‘correct’ fix!

      Old:
      $replaylagcopies = @($database | Select -ExpandProperty ReplayLagTimes | Where-Object {$_.Value -gt 0})

      New:
      if ($database.AdminDisplayVersion -like “Version 14.*”)
      {
      $replaylagcopies = @($database | Select -ExpandProperty ReplayLagTimes | Where-Object {$_.Value -gt 0})
      }
      else
      {
      $replaylagcopies = $dbcopy.ReplayLagStatus
      }
      #End New commands
      if ($($replaylagcopies) -match “True”)
      {
      [bool]$replaylag = $false
      foreach ($replaylagcopy in $replaylagcopies)
      {
      $tmpstring = “$database is replay lagged on $mailboxserver”
      Write-Verbose $tmpstring
      if ($Log) {Write-Logfile $tmpstring}
      [bool]$replaylag = $true
      }
      }

      1. Adam Borders

        I have seen this issue since at least CU 11 and maybe on CU 10. My fix has always been to update the scripting machine to the same CU as the exchange servers.

  160. Stu Cousins

    Hi Paul,

    Thanks very much for the script. Works really well. We had it running on an Exchange 2010 box fine then and moved it to a box on a different subnet. The script runs fine on the new box and all status data is returned. All apart from it says the “File Share Quorum = Failed” for all of the mailbox servers in the cluster. I ran the Test-ReplicationHealth cmdlet from the new server hosting the script and all comes back green. I’ve checked the firewall rules and nothing appears to be getting blocked. Any ideas please and thanks in advance.

    1. Avatar photo
      Paul Cunningham

      Apart from the different subnet, what is different about the server you’re running it from now?

      1. Stu Cousins

        Thanks for your quick response. The server I’m running it from now is a non-Exchange 2010 server. Thats the only difference really. This new server is on the same subnet as the server hosting the file share quorum so its not a firewall issue.

        I fully appreciate its probably an issue with our environment, but I just found it odd that the 99.9% of the health check is successful and the only thing that fails in the ‘File Share Quorum’ check. I’ve checked permissions from our new server to the Quorum and those seem OK.

        I’d be happy to continue running the script on an Exchange server, but our monitoring reports high ‘RPC Requests Outstanding’ alerts when the report runs and these don’t reduce even after the script runs. To clear this we need to reboot the server.

        1. Avatar photo
          Paul Cunningham

          Basically the script is running (or should be running) Test-ReplicationHealth against each DAG member.

          E.g. if you have DAG members named SERVER1 and SERVER2, the script is running…

          Test-ReplicationHealth -Server SERVER1
          Test-ReplicationHealth -Server SERVER2

          …and including the results in the report.

          Now, if you’re seeing those commands running manually and returning a pass, while the report still shows a fail, that is odd behavior. In which case, run the script with the -Log parameter and send me the log file and HTML report file to feedback at practical365.com and I will take a look at it.

  161. Phani Chennakesavula

    Hi Paul,

    Thanks for the great script.

    I’m running through an issue when sending the report through e-mail.

    ==========================
    VERBOSE: Sending email report
    WARNING: The SMTP server requires a secure connection or the client was not authenticated. The server response was: 5.7.1 Client was not authenticated
    ==========================
    All the instances I’m running the script on Exchange server (2013; CAS & MBX roles on same box) itself.

    When I run this script with an account that has “Organization management” permissions it executes well and sends e-mail to both external and internal recipients.

    Here we would like to get this done with a non-admin account with less privileges.

    So, Created a new account with mail box “svc-testhealth”

    Added the account to “View-Only Organization Management” Group

    Added the account to local admin group on all exchange servers.

    It runs successfully on the exchange server and logs the information both on shell as well to file, but when it tries to send a mail it fails with above error.

    Can you help me on this?

    Regards,
    PC

  162. Justin Durlewanger

    Paul,

    Thanks for this script. I’ve been using for some time now in our 2010 environment and its beautiful. I noticed when we moved to 2013 its showing our shadow copy queues in the report. Is there a way to exclude shadow copy queues? This is giving a failure on the server transport queues because the shadow copy queues are above 200.

      1. Justin Durlewanger

        Wow! Thanks for the prompt reply Paul! As always you and your site are an excellent resource for any exchange administrator.
        Keep up the great work!

  163. Sumeet Soni

    Hi Paul,

    I have implemented this script to run for each site in my infra but recently experiencing issues where it takes more than 8 hours for it to complete and show results. Is there a reason that you can share for script to take such a long time?

    Quick info:
    Exchange 2010 only.
    I execute this script from server with HT role.
    I run this using schedule task and configured it to terminate if it runs above 8 hrs.
    Only changes to your script that i use is to check for DAG from the current site.

    1. Sumeet Soni

      Request urgent assistance with this.

      1. Avatar photo
        Paul Cunningham

        Have you tried just running it manually and see where it gets slowed down? Or reverting your changes and try the original script without modifications?

        1. Sumeet Soni

          Yes. Manual run generates results but again it takes lot of time and i observed it gets paused while running around half way but starts again after a pause of and hour plus.

  164. David Shriner

    Thanks for providing this script. It has been really helpful in getting an overall glimpse at my Exchange environment. I have encountered one problem recently after upgrading my Exchange 2013 servers to CU12. When I run the script now I get reported errors that Mail flow has failed on all of each Exchange 2013 server. When I look at the log file I see this:

    05/24/2016 06:02:32 Checking mail flow
    05/24/2016 06:02:32 The term ‘Test-Mailflow’ is not recognized as the name of a cmdlet, function, script file, or operable program. Check the spelling of the name, or if a path was included, verify that the path is correct and try again.
    05/24/2016 06:02:32 Mail flow status is Fail

    The script ran fine before the upgrade to CU12 and I am running it with elevated privileges. I have also updated to the latest version of your script with the same results. Do you have any ideas what could be wrong? Thanks for any help you can provide.

  165. Elmer Ernesto Menendez

    Muchas gracias, fue de gran utilidad tu script

  166. Gothdoll

    Paul,

    I am running this script and while I am not getting any errors – the report comes out but there is an issue Id like to resolve without removing these hybrid servers completely out of the script entirely.

    I have 8 HUBS, 4 are set up to communicate with Exchange Online. That being said, the Test-ServiceHealth will always fail on these, multi-role Hub/CAS servers because the MSEdgeSync Service is not needed.

    Is there any way to avoid this, to cont to work in the script on everything else.

    1. Avatar photo
      Paul Cunningham

      I just start the service (and set it to auto start too). The script doesn’t have the logic to tell whether an Edge Subscription exists or not, it just uses what Test-ServiceHealth considers to be a good/bad result.

  167. james T

    hey Paul, love your site BTW.
    I am trying to run the health check report on my two 2013 exchange servers (both are build 1044.25) and keep running into the error below when attempting to email the report, and it happens on both servers:

    mail flow test: WARNING: Connecting to remote server mail.mydomain.com failed with the following error message : WinRM cannot process the request. The following err
    or occurred while using Kerberos authentication: Cannot find the computer mail.mydomain.com. Verify that the computer exists on the network and that the name provid
    ed is spelled correctly. For more information, see the about_Remote_Troubleshooting Help topic.
    WARNING: Cannot validate argument on parameter ‘Session’. The argument is null or empty. Provide an argument that is not null or empty, and then try the command again.
    Remove-PSSession : Cannot validate argument on parameter ‘Id’. The argument is null. Provide a valid value for the argument, and then try running the command again.
    At C:WindowsSystem32Test-ExchangeServerHealth.ps1:426 char:19
    + Remove-PSSession $session.Id
    + ~~~~~~~~~~~
    + CategoryInfo : InvalidData: (:) [Remove-PSSession], ParameterBindingValidationException
    + FullyQualifiedErrorId : ParameterArgumentValidationError,Microsoft.PowerShell.Commands.RemovePSSessionCommand

    Fail

  168. Shahir Thottathil

    Dear Paul,

    Hope you are doing well!.

    While i trying to run the script, its running almost okay, but at the end i am always getting an error as given below,

    You must provide a value for this property.
    + CategoryInfo : NotSpecified: (0:Int32) [Get-MailboxDatabase], DataValidationException
    + FullyQualifiedErrorId : 15FA16A2,Microsoft.Exchange.Management.SystemConfigurationTasks.GetMailboxDatabase

    Please help me in this case.

    Thanks and Regards,
    Shahir

  169. Joe

    in the report its say DB redundancy and availability is n/a, whats the reason for that?

    thanks, great script

    1. Avatar photo
      Paul Cunningham

      Depending on the design of the DAG and where the active DB copies happen to be at the time the script runs, some of those items are not applicable.

      1. Jesse

        We had a failed copy a few days a go and the report showed those fields as *FAILED*. Once we resolved the issue, they went back to saying na. Shouldn’t it report “Passed” instead?

        Thanks

  170. naxin

    Hi,Paul, thanks for the great script. I have a error when run the script.

    —— Checking CAS03
    DNS Check: Pass
    Ping Check: Pass
    Uptime (hrs): 824
    Server version: Exchange 2013
    Roles: ClientAccess
    Could not test service health. : System.Management.Automation.RemoteException: Not installed on CAS03.electric.com
    Microsoft Exchange 2007 Server Roles

    Is there something wrong in my server config ? thanks.

    1. naxin

      I have three cas server ( exchange 2013 ) , All of them “Could not test service health” , and show “System.Management.Automation.RemoteException” , look like something about exchange 2007 that I have not in my environment.

    2. naxin

      Sorry , I see the page “Exchange 2013 Test-ServiceHealth Doesn’t Work for Client Access Servers” , that is exactly my situation . Thanks a lot.

      1. Avatar photo
        Paul Cunningham

        Some test cmdlets just break if it’s a CAS-only server. I don’t plan to spend much time trying to fix it, sorry. I am investing time in an entirely new script instead. It’s also recommended to not deploy dedicated CAS, and instead deploy multi-role servers.

  171. SteveB

    Paul, thanks for a great script. Quick question, have you considered modifying this script to check for proper log truncation (or does it already do it and I missed it)? Specifically, our backup software regularly issues VSS log truncation requests to Exchange, however some issue with Exchange prevents the logs from truncating. Over time we get notified when disk space runs low, but this script seems like a natural place to check for log file age/truncation.

  172. Lanray

    Hi Paul, Great work.
    This part of the script executes fine for every server in my environment except for one 🙂
    It runs fine on that server only when I replace $e15mailboxserver with its FQDN.

    i.e:
    $url = “http://hostname/powershell” – works for every server except one
    $url = “http://hostname.domain.com/powershell” – Works for the recalcitrant server

    ########################################################################
    if ($url -eq $null)
    {
    $url = “http://$e15mailboxserver/powershell”
    }

    try
    {
    $session = New-PSSession -ConfigurationName Microsoft.Exchange -ConnectionUri $url -ErrorAction STOP
    }
    ########################################################################

    Any suggestions???
    Thanks!

  173. Aerrow

    Made a few changes on the script. As this is a health checkup, added few tables related the status of the database. But couldn’t find anywhere to upload to you guys to verify.

    1. Avatar photo
      Paul Cunningham

      Github (link in the article) is the best place to submit specific feedback.

  174. Joe Zapata

    Hi Paul,

    Thanks for sharing such a wonderful script. One thing I noticed is that the “Client Access Server Role Services” and the “Hub Transport Server Role Services” are shown as fail (RED) on the email that’s generated. The “Transport Queue” is shown as “Unknown” (Yellow) whenever the script runs from a daily scheduled task on one of my CAS Array member. Everything else is GREEN. I’m using Exchange 2010 SP3 in a CAS Array (2 servers with CAS, HT roles) and a DAG (2 Servers with Mailbox Server roles ) environment.

    Please see below for the Task parameters:

    Program/Script: C:WindowsSystem32WindowsPowerShellv1.0powershell.exe
    Arguments: -ExecutionPolicy Bypass -NonInteractive -Command “& ‘C:TempPSTest-ExchangeServerHealth.ps1’ -ReportMode -SendEMail”

    However, if I run this script below from a PowerShell session on the same CAS array member where I have the task scheduled, the generated email shows all green.
    Test-ExchangeServerHealth.ps1 -ReportMode -SendEMail

    Any reason for this behavior?

    Thanks in advance,

    Joe Zapata

  175. Mike Nadelman

    I was able to create this batch file to run either on demand or using task manager. I works as a batch file but need to add the -sendemail parameter and not sure how to do it. Also need some help to run this as a scheduled task.

    @ECHO OFF
    SET ThisScriptsDirectory=%~dp0
    SET PowerShellScriptPath=%ThisScriptsDirectory%test-exchangeserverhealth.ps1
    PowerShell -NoProfile -ExecutionPolicy Bypass -Command “& ‘%PowerShellScriptPath%'”;

  176. Mike Nadelman

    I was able to create this batch file to run either on demand or using task manager. I works as a batch file but need to add the -sendemail parameter and not sure how to do it. Also need some help to run this as a scheduled task.

  177. martin b

    i have been using this script on my enviroment of EX2010, but now, im tring to use it on the new Exchange 2013 env. all the test are OK, but i never recive the email report… i have allready configured the smtp settings, and are OK. I try to use sendmail and its working too.

    any ideA?

  178. Aleem Ijaz Janjua

    Thanks for the script Paul.

    I’m facing issue in scheduling this script from the task scheduler. I get the wrong report in which the “Up time hrs comes with “Unable to retrieve up time ” and Client Access Server Roles Services “fail”. But when i run this script through windows power shell the report comes perfectly, without any issues.

    I used the same arguments which you have mentioned in your comment earlier.

    can you please tell me how can i get the correct report through task scheduler.

  179. DeSteeph

    Hi Paul,

    This script and none of my other reporting scripts are working anymore since we have applied the Microsoft patches from January 2016. It basically comes down to the part where “get-mailboxdatabase -status” loads the list of servers from memory but that fails (at least.. that is what I suspect). It gives me the output: “you must provide a value for this property”.
    I am running Exchange 2010 SP3 RU11 on W2008R2 SP1
    Did you or any one else run in to this problem?

  180. Dwight

    The script works great when running from my Exchange 2013 servers, but ran into some fields missing from the report when running the script on a non-Exchange (but tools installed) host.

    For the activation preference data that was missing from the report, I followed this comment for the fix: https://www.practical365.com/powershell-script-exchange-server-health-check-report/#comment-197858

    The other item missing from the report were the server names from the ‘Database Availability Group Member Health’ section.

    This was due to the variable $dagmember.names not providing the same value as it did when the script ran directly on an Exchange server. To fix that issue, I ended up just using the $dagmember variable directly.

  181. prasant

    Please ignore the above post. I was not using the -ReportMode parameter. It is now giving me error with gmail authentication which I should be able to fix by disabling dual app verification

  182. prasant

    Hi Paul,

    My issue has been resolved after starting services on passive server. However, when run the script I only get the report on powershell and do not see HTML or email.
    I already modified email parameter and authentication to gmail. I do not get error with script but runs report only on pshell

  183. prasant

    Thanks for your response Paul. I will try -log and send you the log. Friday night I exported and imported certificate from active server and change all CAS, we, autodiscover, activesync services to same FQDN as active server. I did not create second host A on public DNS with different public address and NAT on firewall yet. First I wanted to test internal communication before making changes to my firewall and public DNS.
    I shut down the active server to see the communication from internal Outlook client and it changed to disconnected, until I rebooted the active server and rebooted passive following that. So, I got a feeling there is still issue with mal flow services, outlook anywhere proxy on passive as database replication health is good

  184. Andy

    Excellent script, Paul. Thanks a bunch for writing and maintaining it for the community. I encountered some of the same issues as others noted above, and have come up with the following resolutions for them:

    Server name is blank in DAG member health table:
    change line 1530 to
    $memberObj | Add-Member NoteProperty -Name “Server” -Value $($dagmember.Name)
    – the ‘$dagmember’ variable is just the string, there’s no ‘name’ attribute

    change line 1532 to the following to also fix the verbose logging
    $tmpstring = “—- Checking replication health for $($dagmember.Name)”

    Exchange 2010 DAG health table shows only ‘n/a’:
    change line 467 to
    $e14replicationhealth = Invoke-Command -Session $session -Args $e14mailboxserver {Test-ReplicationHealth $args[0]} -ErrorAction STOP
    – the function is called with ‘$dagmember’ as the argument; related to the $dagmember issue above

    Running in Remote PowerShell:
    If you have an active Remote Powershell session to an Exchange 2013 server, commenting out lines 503-521 will allow it to work flawlessly. This just removes the check for the local snap-in.

    Thanks again for all your work!
    Andy

    1. Andy

      copy/paste fail… Sorry all. here’s the fixed lines 1530 and 5132

      1530: $memberObj | Add-Member NoteProperty -Name “Server” -Value $dagmember
      1532: $tmpstring = “—- Checking replication health for $dagmember”

      Andy

  185. Navneet

    i am getting below error while running this script

    WARNING: No snap-ins have been registered for Windows PowerShell version 4.

    i am using Remote powershell.. version is 4 and i have first connected with exchange organization..
    my all exchange commands are running fine.. excerpt this script

    1. Avatar photo
      Paul Cunningham

      Install the Exchange management shell on the server/workstation you want to run the script from. I haven’t tested it in remote powershell (due to the way the script was originally written) and don’t have any plans to fix this version for remote powershell, but a future version might support remoting.

  186. Carlos Rotver

    Hello Paul, thanks for this script!!

    I have a question: We just added a new mailbox server to a 3rd. DAG we have. All seems to work fine but:

    – Mail Flow Test appears as “Fail” in 3 MBX servers out of 13 servers. We are running the script from a CAS.

    – On the DAG Tests, on the 3rd. DAG, The folloging fields appear as “n/a” for the new mailbox server: DB Copy Suspended, DB Initializing, DB Disconnected, DB Log Copy Keeping Up, DB Log Reply Keeping UP.

    Any idea what this could be?

    Kind Regards,

    1. Avatar photo
      Paul Cunningham

      The “n/a” aren’t a concern because some tests are not applicable if the DAG member isn’t hosting any active database copies at the time.

      For the mail flow test, run the script with -Log and email the log to me, paul [at] this domain.

      1. Carlos Rotver

        Excellent! I will send you the log. Thanks from Mexico!

  187. prasant

    I get this warning, is it normal?-

    ARNING: The file C:certignorelist.txt could not be found. No servers, DAGs or databases will be ignored.
    —— Checking EXC-DAG
    DNS Check: Pass
    Ping Check: Pass
    Uptime (hrs): 87
    Server version: Exchange 2013
    Roles: Mailbox, ClientAccess
    Mailbox Server Role Services: Fail
    Client Access Server Role Services: Fail
    Unified Messaging Server Role Services: Fail
    Hub Transport Server Role Services: Fail
    Total Queue: 1
    Mailbox databases mounted: Pass
    Mail flow test: No active mailbox databases
    —— Checking FAB-EXCH13
    DNS Check: Pass
    Ping Check: Pass
    Uptime (hrs): 186
    Server version: Exchange 2013
    Roles: Mailbox, ClientAccess
    Mailbox Server Role Services: Pass
    Client Access Server Role Services: Pass
    Unified Messaging Server Role Services: Pass
    Hub Transport Server Role Services: Pass
    Total Queue: 2
    Mailbox databases mounted: Pass
    MAPI connectivity: Success
    Mail flow test: Success
    WARNING: Windows Failover Clustering encountered a transient error. Trying the operation again may be successful. Error: ‘IsNodeClustered’.
    —— Finishing

  188. Ephibob

    Can you help me with a health check script for application servers in Linux SUSE environment? Kindly drop the link here please

  189. Mohamed Elsayed

    I have this error while trying to execute this PS
    I have Exchange 2010 SP1
    Pls Help

    PS C:ScriptsExchangeServerHealth> .Test-ExchangeServerHealth1.ps1
    The ‘<' operator is reserved for future use.
    At C:ScriptsExchangeServerHealthTest-ExchangeServerHealth1.ps1:112 char:13
    + <!– < <<< –>
    + CategoryInfo : ParserError: (<:OperatorToken) [], ParseException
    + FullyQualifiedErrorId : RedirectionNotSupported

  190. Gabriel

    Paul,

    This script is great! I have one small issue that I can’t figure out. The Server field for the Database Availability Group member health shows up as blank. All the other fields in that table are fine, just no entries for the Server column. Any ideas?

    1. Avatar photo
      Paul Cunningham

      Generate a log file for the script (use the -Log switch) and send it to me at paul (at) this domain, and I’ll take a look.

  191. Paul Sheath

    Hi,

    I am trying to run this script and get the following error:

    â?” $OS.ConvertToDateTime($OS.LastBootUpTime)
    [int]$uptime = ” : Unexpected token ‘â?” $OS.ConvertToDateTime($OS.LastBootUpTime)
    [int]$uptime = “‘ in expression or statement.
    + CategoryInfo : ParserError: (â?” $OS.Convert…int]$uptime = “:String) [], ParseException
    + FullyQualifiedErrorId : UnexpectedToken

    Can someone please advise what I am doing wrong here please.

    Thanks

    Paul

    1. Avatar photo
      Paul Cunningham

      Have you modified the script? I’m not sure where the “â” character in your error is coming from.

    2. 0livier

      Hi Paul,

      Same error here when i took the script from Script Center. No problem if you take it frome Github.

      0livier.

      1. Avatar photo
        Paul Cunningham

        Still works okay for me when I download a fresh copy, but perhaps there’s something wrong in the script center somewhere. I’ll make a note to refresh the copy hosted there.

    3. Daniel B

      Copy script into ISE and resave it. I got the same error saving it from Notepad++

  192. Stephane Gagne

    Hi Paul,

    Do you think it would be possible, for the mail flow test, to target a specific mailbox? (e.g. administrator..)

    I’ve been struggling with antispam and cannot whitelist the “systemmailbox….” email address.

    Thanks.

  193. Sanju

    Just for the record if anyone wants to send it to multiple recipient and not a DL I modified it as below to make it work,

    $smtpsettings = @{
    To = “Recipient 1 “, “Recipient 2 “, “Recipient 3 ”
    From = “reporting@xx.com”
    Subject = “$reportemailsubject – $now”
    SmtpServer = “smtp@xx.com”
    }

    1. Sanju

      Dear Paul,

      Just to update on this. I fixed the Activation Preference and Server names for Replication Test by using the below.

      if ($database.AdminDisplayVersion -like “Version 14.*”)
      {
      $pref = ($database | Select-Object -ExpandProperty ActivationPreference | Where-Object {$_.Key -eq $mailboxserver}).Value
      }
      else
      {
      $pref = $dbcopy.ActivationPreference
      }
      This worked out and the report is having the correct output.

      I am also figuring if when using the Alerts Only Switch can we send the message with the error. Suppose the Queue is high we say the queue is high which is ok but if we can mention the current value that would be amazing… I will update if i can make this happen.

      Thanks again

      1. Sanju

        Just used the value with the queue output and worked flawlessly, Now the Alerts have the numbe rof queue as well..

  194. Sanju

    I have been using all the versions when it started back in the days of this script. However I have a challenge now. My client loves this report. But he wants me to take away the email part which I can do and host the HTML as a dashboard and refresh every 20 minutes from the server. Is it something possible to do. Maybe creating an IIS site or something. I am still thinking aout this and thought would ask the experts here.

    1. Avatar photo
      Paul Cunningham

      Try using the -ReportFile parameter to output the HTML file to a folder that is configured as an IIS virtual directory.

      1. Sanju

        Kewl Thanks. One other thing. When Using the parameter -Alerts only is it possible not to have the complete HTML and just send the alerts found. Also what if I don’t want this as an attachment and need it in the body of the email.

        Thanks again for the help. This script is marvelous and a life saver for Admins like us…

        1. Sanju

          Also I noticed on the Activation Preference Table the values are empty. Any thoughts on that.

          1. Sanju

            Dear Paul,

            For me all looks good now…accept no server name in the Replication tests and Activation preference table is blank. I customized the script a bit for the Alerts Only to send the Server Summary and Dag Summary 🙂 Works like a charm.

            Any ideas why the activation preference and server names on replication tests are blank…

  195. Jack

    Important question mailflow test is external or internal

  196. sotomayor

    Hi!

    I executed .ps1 in powershell success and I receive mail correctly.
    I configured scheduled task and I receive mail void.
    The log shown:
    =====================================
    Exchange Server Health Check

    =====================================
    Initializing…
    Loading the Exchange Server PowerShell snapin
    Setting scope to entire forest
    The file C:Scriptsignorelist.txt could not be found. No servers, DAGs or databases will be ignored.
    Retrieving server list
    Removing servers in ignorelist from server list
    Servers to check:
    Beginning the server health checks
    Beginning the DAG health checks
    0 DAGs found
    0 DAGs will be checked
    0 DAGs to check:
    0 No DAGs found

    This is surprise! Do you know case? How I can fix it?
    Thanks in advance

    1. Avatar photo
      Paul Cunningham

      Have you followed the suggestions in the article about the scheduled task settings?

  197. Claudiu Gheorghe

    Hello Paul,

    The latest script is ran from the exchange server which is only CAS and Mbox, dc is on the same vlan. I am able to create “New-PSSession” as you can see below. From what i can gather i see that the script is trying to create a “remote” session to the local exchange server? I also tried it from a diff server on the same vlan and i was able to open a new ps session as admin without get-credential
    Can you give me any hints?

    [PS] C:Usersadministrator.RACKALLEYDesktop>New-PSSession

    Id Name ComputerName State ConfigurationName Availability
    — —- ———— —– —————– ————
    9 Session9 localhost Opened Microsoft.PowerShell Available

    [PS] C:Usersadministrator.RACKALLEYDesktop>Enable-PSRemoting

    WinRM Quick Configuration
    Running command “Set-WSManQuickConfig” to enable remote management of this computer by using the Windows Remote
    Management (WinRM) service.
    This includes:
    1. Starting or restarting (if already started) the WinRM service
    2. Setting the WinRM service startup type to Automatic
    3. Creating a listener to accept requests on any IP address
    4. Enabling Windows Firewall inbound rule exceptions for WS-Management traffic (for http only).

    Do you want to continue?
    [Y] Yes [A] Yes to All [N] No [L] No to All [S] Suspend [?] Help (default is “Y”): A
    WinRM is already set up to receive requests on this computer.
    WinRM is already set up for remote management on this computer.

    Confirm
    Are you sure you want to perform this action?
    Performing the operation “Set-PSSessionConfiguration” on target “Name: microsoft.powershell SDDL:
    O:NSG:BAD:P(A;;GA;;;S-1-5-21-4179456325-3254648906-924085538-500)(A;;GA;;;BA)(A;;GA;;;RM)(A;;GAGR;;;S-1-5-21-4179456325
    -3254648906-924085538-1162)S:P(AU;FA;GA;;;WD)(AU;SA;GXGW;;;WD). This lets selected users remotely run Windows
    PowerShell commands on this computer.”.
    [Y] Yes [A] Yes to All [N] No [L] No to All [S] Suspend [?] Help (default is “Y”): A
    [PS] C:Usersadministrator.RACKALLEYDesktop>.Test-ExchangeServerHealth.ps1
    Initializing…
    WARNING: The file C:Usersadministrator.RACKALLEYDesktopignorelist.txt could not be found. No servers, DAGs or
    databases will be ignored.
    —— Checking MAIL
    DNS Check: Pass
    Ping Check: Pass
    Uptime (hrs): 1
    Server version: Exchange 2013
    Roles: Mailbox, ClientAccess
    Mailbox Server Role Services: Pass
    Client Access Server Role Services: Pass
    Unified Messaging Server Role Services: Pass
    Hub Transport Server Role Services: Pass
    Total Queue: 0
    Mailbox databases mounted: Pass
    MAPI connectivity: Success
    Mail flow test: WARNING: Connecting to remote server “mail-server” failed with the following error message : Access
    is denied. For
    more information, see the about_Remote_Troubleshooting Help topic.
    WARNING: Cannot validate argument on parameter ‘Session’. The argument is null or empty. Provide an argument that is
    not null or empty, and then try the command again.
    Remove-PSSession : Cannot validate argument on parameter ‘Id’. The argument is null. Provide a valid value for the
    argument, and then try running the command again.
    At C:Usersadministrator.RACKALLEYDesktopTest-ExchangeServerHealth.ps1:426 char:19
    + Remove-PSSession $session.Id
    + ~~~~~~~~~~~
    + CategoryInfo : InvalidData: (:) [Remove-PSSession], ParameterBindingValidationException
    + FullyQualifiedErrorId : ParameterArgumentValidationError,Microsoft.PowerShell.Commands.RemovePSSessionCommand

    Fail
    —— Finishing
    Done.
    [PS] C:Usersadministrator.RACKALLEYDesktop>

    1. Claudiu Gheorghe

      I figured it out,

      The internal URL for Powershell was set to HTTPS, once i change it to HTTP in ECP>Servers>Virtual Directories>PowerShell (Default Website)>Edit>Internal URL: to http://FQDN/powershell, it succeeded in sending the report to my email with this command:

      .Test-ExchangeServerHealth.ps1 -server MAIL -Verbose -reportmode $true -sendemail $true

      Credits go to Paul Cunningham for the above command.

  198. Reynaldo Ruiz Flores

    Error running the script

    Mail flow test: WARNING: Connecting to remote server exchange13.mah.com.mx failed with the following error message : The WinRM client cannot process the request. It canno
    t determine the content type of the HTTP response from the destination computer. The content type is absent or invalid. For more information, see the about_Remote_Trouble
    shooting Help topic.
    WARNING: Cannot validate argument on parameter ‘Session’. The argument is null or empty. Provide an argument that is not null or empty, and then try the command again.
    Remove-PSSession : Cannot validate argument on parameter ‘Id’. The argument is null. Provide a valid value for the argument, and then try running the command again.
    At C:Usersadministrator.MAHDesktopTest-ExchangeServerHealth.ps1:426 char:19
    + Remove-PSSession $session.Id
    + ~~~~~~~~~~~
    + CategoryInfo : InvalidData: (:) [Remove-PSSession], ParameterBindingValidationException
    + FullyQualifiedErrorId : ParameterArgumentValidationError,Microsoft.PowerShell.Commands.RemovePSSessionCommand

    1. chris hall

      I have same issue did you resolve

  199. Mukhan

    Hi,

    All of our MS Exchange Users are unable to search from OWA, error: The action couldn’t be completed, Please try again.

    is there any script to find out what is wrong on our Exchange server, Please share.

  200. Glen

    When the database is mounted on server01, the following error message is generated below.
    But, when I failover the database from server 01 to server02 and run the script, there is no issues with the reporting. What would cause the error below? It was confirmed by running the test-exchangeservices that the WinRM service was in a running state on server01.

    Mail flow test: WARNING: Connecting to remote server “server01” failed with the following error message : The WinRM client received an HTTP bad request status (400), but the remote service did not include any other information about the cause of the failure. For more information, see the about_Remote_Troubleshooting Help topic.

    WARNING: Cannot validate argument on parameter ‘Session’. The argument is null or empty. Provide an argument that is

    not null or empty, and then try the command again.

    Remove-PSSession : Cannot validate argument on parameter ‘Id’. The argument is null. Provide a valid value for the

    argument, and then try running the command again.

    At C:SCRIPTSServer_HealthTest-ExchangeServerHealth.ps1:425 char:19

    + Remove-PSSession $session.Id

    + ~~~~~~~~~~~

    + CategoryInfo : InvalidData: (:) [Remove-PSSession], ParameterBindingValidationException

    + FullyQualifiedErrorId : ParameterArgumentValidationError,Microsoft.PowerShell.Commands.RemovePSSessionCommand

  201. Mukhan

    Hi Paul,

    I want to run this script in my environment to make my life easier, we have a very simple scenario;

    Server 1: Hub and CAS roles installed
    Server 2: Mailbox role installed

    Please let me know what changes should i make as per my scenario and how to run this script, its a bit stupid to ask such things but I am quite new to scripting.

    Thanks in advance.

    1. Mukhan

      I have MS Exchange 2010 SP3

      1. Avatar photo
        Paul Cunningham

        You should only need to change the SMTP settings in the script. Run the script from the Exchange Management Shell to get started. The link to Github in the article has more help info if you need it.

  202. Suraj

    Thanks for script….it works great !!!!!

  203. Paul

    Hi Paul,

    great script and one I use a lot. Just put it into one of the DAG’s I look after and all is coming back healthy… most of the time. However one of the public folder DB’s which is on our DR site keeps coming back as “Public Folder database not mounted. ” However in the same report I get the PFDB as mounted and healthy. Any time I jump onto the server and manually run the script ( it is on a schedule ) it is mounted and healthy. Server has lots of free resource and event logs are clean with no errors. I can only assume the script is timing out or not getting a correct response. But not all the time. Any ideas what I can look for?

    Thanks

    Paul

    1. Avatar photo
      Paul Cunningham

      Send me a sample report as well as the log file that the script produces to paul at exchangeserverpro dot com and I’ll have a look at it.

  204. Kapil K

    Awesome script, Thanks for sharing Paul.

    Require one more help, please let me know if there is any script for below mentioned powershell cmds which can provide the output of these cmds in single file or mail,

    1) Get-MailboxDatabase -Status | ft name,last* -auto
    2) Get-MailboxDatabaseCopyStatus -Server mbx1
    3) Get-MailboxDatabaseCopyStatus -Server mbx2
    4) Get-TransportService | Get-Queue
    5) Test-ReplicationHealth -Identity mbx1 | ft
    6) Test-ReplicationHealth -Identity mbx2 | ft
    7) Test-MapiConnectivity -Server mbx1
    8) Test-MapiConnectivity -Server mbx2
    9) Test-Mailflow -Identity MBX1
    10) Test-Mailflow -Identity MBX2

    1. Avatar photo
      Paul Cunningham

      A PowerShell script is basically just a series of commands. If you already know the commands you want to run, putting them in a script is a very simple step from there. If you’re new to PowerShell scripting then it will be a good learning exercise for you.

  205. Chris

    Paul, thank you so much for your work!! We have exchange 2013 SP1 2 member DAG on server 2012 R2. I can not get this script to either make the report or send an email using scheduled task. The script does send email when run from powershell with the -sendemail switch/option. I looked through the event logs to see if i could see any error but did not see anything related to the script. I have the exact same settings in the scheduled task as you shared in the article above.

    Run whether user is logged on or not
    Run with highest privileges
    Action: Start a program
    Program: powershell.exe
    Arguments: -command “C:ScriptsTest-ExchangeServerHealth.ps1 -Log -SendEmail”

    I have removed the quotes at the end of the arguments to look like this:
    Arguments: -command “C:ScriptsTest-ExchangeServerHealth.ps1″ -Log -SendEmail
    and i have entered the full path in the program line:
    Program:C:WindowsSystem32WindowsPowerShellpowershell.exe

    This task is at the root level of the task scheduler. Not sure what else to try not knowing any error(s). Any ideas?

    1. Avatar photo
      Paul Cunningham

      Put the powershell.exe command line you’re trying to run in Task Scheduler into a .bat or just run it from a cmd.exe, see if you get any different errors. Make sure you’re running the .bat or cmd.exe with the credentials you’re trying to run the scheduled task with too.

      1. Chris

        Thanks for those instructions! Turns out, it did not like the quotes (“) in the command. Removed those and its working like a champ. Thank you again Paul!

  206. Jack Chuong

    Hi Paul,
    Thank you for your script.
    On my Exchange 2013 (Windows 2008 OS) server when I ran script as domain admin at Exchange Power Shell successfully
    cd D:Scripts
    .Test-ExchangeServerHealth.ps1 -SendEmail ==> I received report html email.
    But when I make schedule task for script (as domain admin too) :
    Program : C:WindowsSystem32WindowsPowerShellv1.0powershell.exe
    Arguments : -command “D:ScriptsTest-ExchangeServerHealth.ps1 -SendEmail”
    It didn’t work, the task completed return code 0 but I didn’t receive any email.

    1. Jack Chuong

      I fixed it by select “run with highest privileges” at task setting.

  207. Randall

    Hi Paul

    very useful report however notice database availability and redundancy is showing n/a the rest is passed

  208. HerbZ

    Hey Paul,

    Major fan of your work.!

    Tell, me, where is the output of the HTML content churned out to prior to invoking the SENDMAIL feature?

    PLEASE, SPEAK!

    HerbZ

    1. randall

      is actually at the C root

  209. Matt

    Hi Paul,

    Great script, it does exactly what it says on the tin!

    One question though, is it possible to have the report emailed to more than one address?

    I’ve tried separating different email addresses by space, comma and semi-colon but none seem to work.

    Any thoughts?

    Cheers

    Matt

    1. John

      I’m looking to do the same thing and wondered if Paul has any suggestions?

  210. John

    mail report show mail flow test failed.,

    using .test-exchangeserverhealth.ps1 -server servername
    mail flow test : success.

    i ‘m using V1.14, 21/5/2015

    no idea.

  211. Sanat

    Hi Paul,

    Thank you for the script, its a real great help. However, I was hoping to get a more detailed list of the below commands appended into the script:
    Get-TransportService | Get-Queue | Sort MessageCount – To view a detailed summary of all the queues
    Also if I can pull up Individual Disk Spaces on all the servers with a summary of Free Space, Total Space and Space Consumed
    Last but not the least, a detailed summary of the Mailbox Databases and the size and whitespace in case.

  212. Raj

    I am planning to check the service health of specific DAG servers and its respective CAS and HUB, if I have to create ignore list it will be more in number. Can you please modify script such that I can specify the server list rather than specifying ignore list ?

    1. Avatar photo
      Paul Cunningham

      No. But the script is free for you to take it and customize it any way you like for your own specific needs.

  213. Manfred Paleit

    for a simple sort of Servers …

    #Begin the health checks
    $exchangeservers = $exchangeservers | SORT

    foreach ($server in $exchangeservers) ….

  214. Niclas Johansson

    I get a error message on line 2096:

    Send-MailMessage : Unable to connect to the remote server
    At C:ScriptsExchangeServerHealthtest-exchangeserverhealth.ps1:2096 char:4
    + Send-MailMessage @smtpsettings -Body $htmlreport -BodyAsHtml -Encoding ([Syst …
    + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    + CategoryInfo : InvalidOperation: (System.Net.Mail.SmtpClient:SmtpClient) [Send-MailMessage], SmtpExcept
    ion
    + FullyQualifiedErrorId : SmtpException,Microsoft.PowerShell.Commands.SendMailMessage

    Im running this on a Windows Server 2008 R2 with Exchange 2013.

    1. Niclas Johansson

      Instead of mail.domain.com I copied the IP Adress of the server. Solved the problem.

  215. Manfred Paleit

    Hello Paul,
    great script and very usefull to check our Exchange Systems.

    I’m getting 2 hours instead of 1780 in Powershell 3 with
    [int]$uptime = “{0:N0}” -f $uptime

    My fix is
    int]$uptime = “{0:N0}” -f $uptime.ToString
    The Uptime is now reported correctly.

  216. Lucas Falconi

    Hi !

    When I receive the e-mail with Exchange Server Health Check Summary, There is the following message:

    Server1 – Mail Flow Test Failed

    But at Exchange shell when I run Test-Mailflow SERVER1 -TargetMailboxServer SERVER2 , the result was succesfull.

    Everithing is working perfectly ! I don’t have any idea why i’m receving this error only at report.

    Can you help me ?

    1. Avatar photo
      Paul Cunningham

      Does that error always appear in the report or just that one time?

      1. Lucas Falconi

        Hy Paul !

        Always appear in report.

  217. Rob Derbyshire

    Hi Paul, thanks for this.
    Im running this on an Exchange 2013 Server, and am getting an error on the Mail Flow Test.
    Running Test-mailflow is successful, but this script returns an error for the Server it is running fromon

    Mail flow test: WARNING: Connecting to remote server ServerMBXpd01 failed with the following error message : The WinRM client cannot process the reques
    t. It cannot
    determine the content type of the HTTP response from the destination computer. The content type is absent or invalid. For more information, see the
    about_Remote_Troubleshooting Help topic.
    WARNING: Cannot validate argument on parameter ‘Session’. The argument is null or empty. Supply an argument that is not null or empty and then try
    the command again.
    Remove-PSSession : Cannot validate argument on parameter ‘Id’. The argument is null. Supply a non-null argument and try the command again.
    At C:psHealthReportTest-ExchangeServerHealth.ps1:425 char:19
    + Remove-PSSession $session.Id
    + ~~~~~~~~~~~
    + CategoryInfo : InvalidData: (:) [Remove-PSSession], ParameterBindingValidationException
    + FullyQualifiedErrorId : ParameterArgumentValidationError,Microsoft.PowerShell.Commands.RemovePSSessionCommand

    Fail

    1. Avatar photo
      Paul Cunningham

      Which CU are you running? I’ve seen reports of issues like this for some of the older CUs but AFAIK CU9 works fine.

      And have you configured the PowerShell virtual directory URLs? Mine are left as the server FQDN and the script works. I think some folks have seen similar errors when their PowerShell URLs are set to an alias.

      1. Brian

        I just got this same error CU11
        PSURL=FQDN

        Mail flow test: WARNING: Connecting to remote server xxx-xxxx failed with the following error message : The WinRM
        client cannot
        process the request. It cannot determine the content type of the HTTP response from the destination computer. The
        content type is absent or invalid. For more information, see the about_Remote_Troubleshooting Help topic.
        WARNING: Cannot validate argument on parameter ‘Session’. The argument is null or empty. Supply an argument that is not
        null or empty and then try the command again.
        Remove-PSSession : Cannot validate argument on parameter ‘Id’. The argument is null. Supply a non-null argument and
        try the command again.
        At C:tempTest-ExchangeServerHealth.ps1:426 char:19
        + Remove-PSSession $session.Id
        + ~~~~~~~~~~~
        + CategoryInfo : InvalidData: (:) [Remove-PSSession], ParameterBindingValidationException
        + FullyQualifiedErrorId : ParameterArgumentValidationError,Microsoft.PowerShell.Commands.RemovePSSessionCommand

        Fail

          1. Matthew McDonald

            In my case we change all virtual directory internal URLs to our external mail URL (ex. mail.domain.com). When the script tries to connect to this host for mail flow, it fails with the same error as above. Any suggestions?

        1. Aftab

          managed to fix this. change the internal url for the powershell default to exchange server name with domain (FQDN) instead of load balancer URL, this worked for me.

  218. Krishna

    Hi Paul,

    Firstly, Thanks for the great superb.

    We are running Exchange 2013 environment, Script works fine. However, In the output I get “n/a” under Client Access Server Role Services, Hub Transport Server Role Services, Mailbox Server Role Services.

    All servers are multi role servers. Could you please help how to rectify/make required changes in the script to get the desired output.

    1. Avatar photo
      Paul Cunningham

      That part of the script uses Test-ServiceHealth so see you can run that cmdlet on its own.

      1. Krishna

        Thanks for the quick reply Paul.

        I’ve tried to change that part of script to the best of my knowledge which did not work.

        Would you mind helping me with exact lines which need updated/modified in the script for me to get the desired output.

        Thanks in advance.

        1. Avatar photo
          Paul Cunningham

          Don’t change the script, I’m suggesting you run Test-ServiceHealth on its own to see whether it returns an error or gives you some clue as to why the script is not working correctly.

          Also if your servers are running non-English language then there are extra steps explained in the article above for what you need to change to get that to work.

  219. Paul Slade

    Great script, many thanks.

    Paul.

  220. Carlos Rotver

    hello Paul!

    Thanks for an excellent script. I have installed 3 new Exchange Servers, two mailbox and one CAS/HUB, on a remote site.

    The weird thing, is that the script is running perfect, on the rest of the servers but on the new CAS/HUB. It returns an error:

    Unable to retrieve uptime. Could not test service health. Could not test service health. Could not test service health. Could not test service health.

    I´ve check WMI on the server, with no problem. These 3 servers are on a different site, but again the script is running fine on the mailbox servers.

    Any Clue that you could give me??

  221. Jijo Antony

    Thanks for this useful script.

    But,I am not getting any email after completed the successful execution of the script. I have changed my own SMTPsettings.

  222. Rana

    Amazing Wonderful..

    Love the script & the output is amazing :DDDD

    you are the best MAN :DDDD

  223. Steven

    Hi Paul

    How do I make this to send report to multiple recipients?

    I tried “user1; user2”, this ends up in an error.
    I also tried “user1, user2”, but only user1 ends up getting the report while user 2 seems to be chopped off.

  224. Kristijan

    Well i overlooked that the Exchange EdgeSync service was down. After starting service everything was fine.

    Thnx & regards!

  225. Kristijan

    Hello Paul,

    the script works fine until last Exchange Rollup 10 update from Microsoft when the Hub Transport Role keeps saying Fail ( – Hub Transport Server Role required services not running )…. but service is running and mail flow is just OK. Tested.

    I have Exchange 2010.

    Regards

    1. Avatar photo
      Paul Cunningham

      Run Test-ServiceHealth on the server and see if any of the required services are not running.

  226. Shahid

    Paul,

    It only shows fail when you run the script from scheduled task. When i run it manually from PS Console it shows all ok.
    It only shows fail for the server the scheduled task is running from. If i scheduled task from another server it will show fail for that server and the previous server will show pass.
    Any idea why this is happening.
    i am also looking to get mailbox count for each databases in this script. Is it possible for you to amend the script.
    Your help is really appreciated.

  227. Shahid

    Paul,

    I would like to request to you if you can add to get mailbox counts on each database in this existing script, that would be great. I trying to consolidate the report for our environment.

  228. Shahid

    Thanks for the reply.
    I ran test-servicehealth and it shows all OK.
    The problem is which ever server you pick to run this script from, it shows some service fail on that server.
    I then tried using Send-MailMessage at bottom of your script andded this report send as attachment and all looks OK.
    I think the problem occurs when we use -SendEmail parameter and report comes in a body message.

    For NashTek,
    You can add this command at the end of this script

    Send-MailMessage -To User1@xyz.com, user2@xyz.com -From admin@xyz.com -Subject “$reportemailsubject – $now” -Body “Test Message” -SMTPServer -Attachments

    i am too using this method to send report to multiple users.

  229. NashTek

    Hello Paul or anyone else that might be able to offer some insight,

    Hopefully this is an easy request. Please tell me how this script can be edited to send email to multiple recipients? I have tried separating recipients in the To: field by comma, semi colon and blank space but nothing works for me when my scheduled task runs. Specifying a single recipient works without issue.

    Kind Regards

    1. NashTek

      Here’s something I found from a similar issue that may have some relevance:

      The MailMessage constructor you are using only takes one email address. See the MSDN documentation http://msdn.microsoft.com/en-us/library/5k0ddab0.aspx

      You should try using Send-MailMessage instead because it’s -To parameter accepts an array of addresses

      Send-MailMessage -from from@email.mail -To $recipients -Subject “Disk Space Report – $Date” -smptServer smtp.server -Attachments $freeSpaceFileName

      Note: Send-MailMessage was introduced in PowerShell v2.0 so that’s why there are still examples that use other commands.

      The script is run from Scheduled Tasks on a Windows Server 2008-R2 server running Exchange 2010-SP3 Update Rollup-9 as follows;

      Action:
      Start a Program

      Program/script:
      C:WindowsSystem32WindowsPowerShellv1.0PowerShell.exe

      Add arguments (optional):
      -command “. ‘C:Program FilesMicrosoftExchange ServerV14BinRemoteExchange.ps1’; Connect-ExchangeServer -auto; C:ScriptsTestExchangeServerHealth.ps1 -ReportMode -SendEmail”

      Start in (optional):
      C:Scripts

      1. NashTek

        That’s what I decided as well. Thanks for the reply.

  230. Shahid

    Paul,
    Thanks for this wonderful script and the work you are doing to help people like us who do not much experience on writing the PS scripts.
    I am having one issue with report, the script runs fine without any errors.
    The server from which this script is executed it shows in the report that the server role as failed.
    I tried running this script on my HT/CAS, MBX role server and it shows same in the report.
    But when i execute the script -server parameter the report shows all green.
    e.g i am running the script from EXCH01 and generate the report for this only it shows all green, but when run the script against all server with scheduled task or from management shell from server EXCH01 which has HUB/CAS role then it shows HUB Transport Role as failed.
    Another thing i noticed is if i execute the script from EXCH02 which is in ignorelist.txt file then report comes out as expected, but if this server is not listed in ignorelist.txt file and the script is executed from this server then it shows role service failed for this server.
    I hope i have put down my issue in detail for you to understand and help me fix this.

    Thanks in advance for your help.

    Shahid

    1. Avatar photo
      Paul Cunningham

      Sounds like one of your servers has some services not running. Use Test-ServiceHealth to test that server.

  231. Sachin ladde

    Hello Paul,

    I would like to thank not just for this script, but for each and every blog that you have written as it is helping a lot to me in my day to day task.

    Regarding Test-ExchangeHealth script, I think for Exchange 2013 MA events or HealthReport should be added.

    I am looking for a Exchange 2013 report which will include all database and server health + managed availability health set command result (Get-HealthReport) for all the servers.

    I would also like to suggest to add few line to the script which will dig into Managed Availability Logs and find the number of occurrence of probe failure with error description.

  232. Gabe Foltz

    To clarify, I obviously can see that the “Test-Mailflow” cmdlet (at least) is being used, but I can’t tell where or what it is testing. (if it helps, I am running Exch 2010, with 1 Hub/CAS server, and a 2-server DAG, I’ll call them “MB1” and “MB2”. I have a single mail database, and it is active on MB1). Here are the results:
    —— Checking MB1
    DNS Check: Pass
    Ping Check: Pass
    Uptime (hrs): 300
    Server version: Exchange 2010
    Roles: Mailbox
    Mailbox Server Role Services: Pass
    Public Folder databases mounted: Pass
    Mailbox databases mounted: Pass
    MAPI connectivity: Success
    Mail flow test: *FAILURE*
    —— Finishing
    Done.

  233. Gabe Foltz

    Paul (or anyone else), please help!

    I had a backup problem over the weekend. My LOGS volume filled up, and my exchange database dismounted. Iwas forced to turn on circular logging and manually restart replication. My servers are both up and everything appears great–EXCEPT that TestExchangeServerHealth script is returning a FAILURE for “Mail flow test” on my active mailbox server.

    I have confirmed that my Exchange system is sending and receiving both internal and external email. None of my other tools (SolarWinds, EMC, Mail Flow Troubleshooter) are showing any issues. I tried turning on “-Log” to get more detailed information, but all the log file shows is the same generic info as the screen display.

    I have looked in the script, but frankly I am not a PS guru, and I can’t even tell what EMS commands are being used to test “Mail Flow”… Can someone help illuminate what calls are being made so I can at least replicate this failure outside the script?

  234. Tausif

    Thanks Paul!!

  235. Tausif

    Hi Paul,

    Really nice work!!!

    Can we customize it to show last backup done for databases.

    Usually we run the following cmd

    get-mailboxdatabase -status | ft name,last* -auto

    can we include it in script

  236. Frank

    Hi Paul,

    Thanks for the wonderful script.

    While there were several errors when script ran:
    The term ‘Test-Mailflow’ is not recognized as the name of a cmdlet, function, script file, or operable program. Check the spelling of the name, or if a path was included, verify that the path is correct and try again.
    The term ‘Test-ReplicationHealth’ is not recognized as the name of a cmdlet, function, script file, or operable program. Check the spelling of the name, or if a
    path was included, verify that the path is correct and try again.

    Do you have suggestion about what will be the cause ?

    Regards,
    Frank

  237. Harish Bajaj

    Running above scripts give output on screen no email to HTML file. I modified the email setting no error but no email is also being sent.

      1. Harish Bajaj

        I have saved the script and changed email details like To , from and server details.

        than ran the script from Exchange power shell..

  238. Chretien

    06/18/2015 13:10:20 —— Checking PVW0-EXCH-F-UL1
    06/18/2015 13:10:20 Checking DNS
    06/18/2015 13:10:20 DNS check passed
    06/18/2015 13:10:20 Checking ping
    06/18/2015 13:10:23 Ping test passed
    06/18/2015 13:10:23 Checking uptime
    06/18/2015 13:10:23 Uptime is 671 hours
    06/18/2015 13:10:23 Server is running Exchange 2010
    06/18/2015 13:10:23 Server roles: ClientAccess, HubTransport
    06/18/2015 13:10:23 Checking service health
    06/18/2015 13:10:24 Client Access Server Role Services status is Pass
    06/18/2015 13:10:24 Hub Transport Server Role Services status is Fail
    06/18/2015 13:10:24 Checking Hub Transport Server
    06/18/2015 13:10:24 Queue length is 1
    06/18/2015 13:10:24 Finished checking server PVW0-EXCH-F-UL1

      1. Chretien

        Yes all others parts are good, and I copy only the check of that server. Note that the server giving me that error is in a different AD Site. I am sure that, maybe there is something blocking it through the network. It’s really weird. Thanks for your suggestion.

        in which mail can I send you the whole log file?

        Thanks

        1. Avatar photo
          Paul Cunningham

          You can send me the log at paul at practical365.com, but I’m confused what you’re asking for help with. Is it a problem running the script, or is the script reporting a problem with one of your servers and you’re not sure what to do about it?

  239. Chretien

    Hello Paul,

    I cannot find it. It seems that it does not generate anything. I have checked everywhere and event use a tools to look for it without success.

    Thank you to guide me.
    I am looking forward to hearing from you.

    Regards

  240. Paul

    Hi Paul

    I can run the powershell scrip using .Test-ExchangeServerHealth.ps1 -ReportMode -SendEmail

    and receive the email and a copy of the report in html.

    The issue is with the task schedule as the scripts run but I am not receiving emails and log details
    In the task schedule I have used your recommended settings.

    My scheduled task settings for this script are:

    Run whether user is logged on or not
    Run with highest privileges
    Action: Start a program
    Program: powershell.exe
    Arguments: -command “C:ScriptsExchangeServerHealthTest-ExchangeServerHealth.ps1 -Log -SendEmail”

    could you please advice on this?

    1. Avatar photo
      Paul Cunningham

      What does the log file say? If you can’t find it then it may be writing to a different folder. Try searching your C: drive for the log file name, or change the “Start In” setting in the scheduled task to match where the script is located.

  241. Chretien

    Bonjour,

    Merci pour ce scripts, j’ai une error peux-tu s’il te plait m’aider parceque j’ai cet error pourtant mon transport server n’a pas de probleme.

    —— Checking PVW0-EXCH-F-UL1
    DNS Check: Pass
    Ping Check: Pass
    Uptime (hrs): 505
    Server version: Exchange 2010
    Roles: ClientAccess, HubTransport
    Client Access Server Role Services: Pass
    Hub Transport Server Role Services: Fail

    Merci

    1. Avatar photo
      Paul Cunningham

      Run Test-ServiceHealth on that server and it will list the services that need to be started for the test to pass.

  242. Gregory

    When running the script on the “primary” machine the mailflow test fails for that machine. Is this script intended to be ran from outside of the actual exchange machines. The server is server 2012r2 and exchange 13 cu8.

    Actual error:
    Mail flow test: WARNING: Connecting to remote server failed with the following error
    message :
    Access is denied. For more information, see the about_Remote_Troubleshooting Help topic.
    WARNING: Cannot validate argument on parameter ‘Session’. The argument is null or empty. Provide an argument that is
    not null or empty, and then try the command again.
    Remove-PSSession : Cannot validate argument on parameter ‘Id’. The argument is null. Provide a valid value for the
    argument, and then try running the command again.
    At C:PowershellTest-ExchangeServerHealth.ps1:425 char:19
    + Remove-PSSession $session.Id
    + ~~~~~~~~~~~
    + CategoryInfo : InvalidData: (:) [Remove-PSSession], ParameterBindingValidationException
    + FullyQualifiedErrorId : ParameterArgumentValidationError,Microsoft.PowerShell.Commands.RemovePSSessionCommand

    Fail

  243. Admin

    Hi Paul,

    I get the following message when the scripts runs the Mail flow test: Warning: Connecting to remote server xxxxx failed with the following error message: The WinRM client cannot process teh request. The WinRM client tried to use Negotiate authentication mechanism, but the destination computer (xxxxxxx:80) returned an ‘accesss denied’ error. The script was running fine while I was testing before the error appeared. Please advise how to fix this error. Thanks.

  244. Essexboy

    Hi Paul, Great script!! Thanks I just want to create a Batch script to have this run, not necessarily through task scheduler. I need the report and email. Can you provide me the script for this? Report PS1 file is located in C:ScriptsExchange Health ReportTest-ExchangeServerHealth.PS1.

    Apologies if this is a simple request. Trying to get my head around scripting!!

    1. Avatar photo
      Paul Cunningham

      Just put the same info you’d use in Task Scheduler into a batch file instead. In the article above I shared my Task Scheduler configuration.

  245. Rich

    Hey Paul, great script! I’ve been using it for over two years now.

    I’m not sure if it has already been suggested, but I would like to see one small feature added – what server has quorum for each DAG. Currently, I manually use this:

    Get-DatabaseAvailabilityGroup -Identity DAG -Status | fl PrimaryActiveManager

    It would be nice to see this in your script as well. Just my $.02.

  246. SysAdmin

    It was a missing quote in one of the email fields. Thanks!

  247. SysAdmin

    Hello Paul – great script. I’m looking forward to using it. I am however getting an error message when I try to run it:

    At D:scriptsTest-ExchangeServerHealth.ps1:549 char:8
    + Write-Verbose $string21
    + ~
    Missing ‘=’ operator after key in hash literal.
    + CategoryInfo : ParserError: (:) [], ParseException
    + FullyQualifiedErrorId : MissingEqualsInHashLiteral

      1. SysAdmin

        Just the email section and I double checked all the values.

        1. Avatar photo
          Paul Cunningham

          Most likely issue is you’ve not closed quotes or brackets properly. Try the script without edits (just let it output to console). If that works then redo your edits and look for typos.

  248. Mohamed Ramadan

    Hi Paul,
    The script is amazing and running very smooth.

    I have a question:
    I have mixed environment 2010/2013, when I run the script against the 2010 CAS/hub server it runs very smooth on the default receive connector.
    when I run it against 2013 it doesn’t send email and require authentication.

    in the protocol logs, I’ve found that the script is authenticating with the 2010 server by the user that ran the script while this doesn’t happen on 2013.

    is there a way to do so or whay does it authenticate with 2010 and doesn’t do so with 2013?

    1. Mohamed Ramadan

      This is the trasport logs on both servers

      On 2010:

      220 2010Servername Microsoft ESMTP MAIL Service ready at Sun, 3 May 2015 11:47:59 +0300
      EHLO
      250-2010servername Hello [RemoteIP]
      250-SIZE
      250-PIPELINING
      250-DSN
      250-ENHANCEDSTATUSCODES
      250-STARTTLS
      250-X-ANONYMOUSTLS
      250-AUTH NTLM
      250-X-EXPS GSSAPI NTLM
      250-8BITMIME
      250-BINARYMIME
      250-CHUNKING
      250-XEXCH50
      250-XRDST
      250 XSHADOW
      AUTH ntlm
      334
      Set Session Permissions
      SMTPSubmit SMTPSubmitForMLS SMTPAcceptAnyRecipient SMTPAcceptAuthenticationFlag SMTPAcceptAnySender SMTPAcceptAuthoritativeDomainSender BypassAntiSpam BypassMessageSizeLimit SMTPSendEXCH50 SMTPAcceptEXCH50 AcceptRoutingHeaders AcceptForestHeaders AcceptOrganizationHeaders SendRoutingHeaders SendForestHeaders SendOrganizationHeaders SMTPSendXShadow SMTPAcceptXShadow
      DomainUsername ” the user that ran the script” authenticated
      235 2.7.0 Authentication successful
      —————-
      On 2013
      220 2013servername Microsoft ESMTP MAIL Service ready at Tue, 5 May 2015 08:20:55 +0300
      EHLO
      None
      250-2013server Hello [Remote IP]
      250-SIZE 36700160
      250-PIPELINING
      250-DSN
      250-ENHANCEDSTATUSCODES
      250-STARTTLS
      250-X-ANONYMOUSTLS
      250-AUTH NTLM
      250-X-EXPS GSSAPI NTLM
      250-8BITMIME
      250-BINARYMIME
      250-CHUNKING
      250 XRDST
      AUTH ntlm
      334 Inbound Negotiate failed because of LogonDenied
      User Name: NULL

      Tarpit for ‘0.00:00:05’ due to ‘535 5.7.3 Authentication unsuccessful’

      1. Avatar photo
        Paul Cunningham

        I can’t tell anything from that protocol log info because you’ve left out the receive connector detail.

        The default frontend connectors on Exchange 2013 allow unauthenticated SMTP to *internal* recipients. So if you have not created any custom receive connectors in Exchange 2013 it should work.

        If you *have* created custom receive connectors it’s possible that the custom connector is handling your SMTP connection. The way to tell is to look at the receive connector name in the protocol log entries.

  249. Jose Byron Gonzalez

    Or simply create a DL that includes those two people?

  250. Alexis Crawford

    Hi,

    Great scripts and Exchange information. In the script I want to be able to send the email 2 people.
    I’ve tried “email1″,”email2” this did not work
    “email1″;”email2” this did not work
    (“email1″,”email2”) this did not work
    (“email1″;”email2”) this did not work

    Any ideas?

    1. Erik

      did you try “email1;email2” ?

    2. Avatar photo
      Paul Cunningham

      As Jose suggests, use a DL for this. Much simpler to manage in the long run.

  251. Tim Klassen

    Great work Paul! I really enjoy your articles and scripts.

    One thing I get when running this script in my 2 server Exchange 2013 CU6 environment is a Kerberos error against the Round Robin DNS name when doing the Mail Flow Test on the server hosting the database.
    This happens as the computer object for the round robin DNS name doesn’t exist.
    Any input on getting this to test the actual computer name rather than the round robin DNS name?

    Thanks!

    1. Avatar photo
      Paul Cunningham

      Can you email me the full error or the full log file (use the -Log switch) to paul at practical365.com and I will take a look.

      Some earlier CU’s don’t run the script properly for some reason but yours is the first report of a Kerberos error, as far as I recall.

      1. Tim

        Did this ever get fixed? I’m experiencing the same with Exchange 2016 CU6, but only if I run it for all servers. If I run it against any individual server, mail flow checks pass. If I run it without the server name switch, it fails when connecting to the round-robin DNS name we use

        1. Avatar photo
          Paul Cunningham

          If the script is trying to connect to a PowerShell vdir that is configured with an alias instead of the server FQDN, I believe it fails unless Kerberos auth is fully set up and configured for your Exchange environment.

          1. Tim

            I apologize if I’m missing something, but does that still explain why running “Test-ExchangeServerHealth.ps1 -Server mailsrv17a” produces a mail flow test with a result of Success, but just running “Test-ExchangeServerHealth.ps1” show a failure on that same server (mailsrv17a)?

  252. Doug

    Hey Paul, do you have any recommendations for me if we have disabled the indexing service on all mailbox servers by design? My environment is 110TB and enabling indexing would require more storage than we want to procure at this time. Is there a way to ignore indexing completely without ignoring the rest of the services on the mailbox servers?

    Also, for some reason the log is never created in the directory I am running the script from, and I cannot find it anywhere else on the server. I haven’t modified your script so I am pretty confused.

  253. CR H.

    I’m having trouble setting this up as a scheduled task. I’m using the settings you provided in the post, running on a 2013 CAS server. Running the script manually works fine on the server, but when I set up a scheduled task the result is always successful, but I never receive the report. I’m running the task as a domain user that has org admin rights within Exchange.

    Any ideas?

    Thanks!

  254. Anthony

    Script runs flawlessly! I do have one question though. What if I want to check my Edge Transport Servers? Where do I edit the script?

    1. Avatar photo
      Paul Cunningham

      There’s no edit I can suggest. I haven’t written or tested any Edge server checks. Some of the tests may happen to work against Edge but that isn’t by design.

  255. Matt

    Fantastic script, thanks for all the hard work! It seems, however, the WinRM is back with CU8. Anyone else experiencing the same thing?

  256. shanif

    Hey Paul,

    Is there a way the dive space for each server in a DAG can show up on this report? or do you have another report that can give me that information?

    please let me know

    1. Erik

      Wow, that script of June Castillote is awesome!

      I made a less awesome and little simpler modification to the original script of paul. This will check if the free disk space is lower than a specific treshold. Let me know if you are interested in the less awesome solution 🙂

      Regards,

      Erik

  257. Nick Paolini

    Hello,

    This is a great script, love it. But, when I run the script my results say two of my three mailbox servers fail the “Mail Flow test. I verified each server with PS that mail does flow. The error message is below. It appears to have a problem with WinRM Client.

    Any help would be great.

    Mail flow test: WARNING: Connecting to remote server sjmmail01 failed with the following error message : The WinRM client cannot process the request. It cannot determine the content type of the HTTP response from the destination computer. The content type is absent or invalid. For more information, see the about_Remote_Troubleshooting Help topic.
    WARNING: Cannot validate argument on parameter ‘Session’. The argument is null or empty. Provide an argument that is not null or empty, and then try the command again.
    Remove-PSSession : Cannot validate argument on parameter ‘Id’. The argument is null. Provide a valid value for the argument, and then try running the command again.
    At C:ScriptsTest-ExchangeServerHealth-v1.2Test-ExchangeServerHealth.ps1:424 char:19
    + Remove-PSSession $session.Id
    + ~~~~~~~~~~~
    + CategoryInfo : InvalidData: (:) [Remove-PSSession], ParameterBindingValidationException
    + FullyQualifiedErrorId : ParameterArgumentValidationError,Microsoft.PowerShell.Commands.RemovePSSessionCommand

    1. Mike

      Nick, I had the same error as you, I upgraded to CU7 and the script now works as expected

      Mike

  258. Erik

    Hi Paul,
    when running this scripts, some of the Exchange 2010 servers return:
    fyi: I am using v1.12 of the script.

    —->
    Mail flow test: Write-Log : The term ‘Write-Log’ is not recognized as the name of a cmdlet, function, script file, or op
    erable
    program. Check the spelling of the name, or if a path was included, verify that the path is correct and try again.
    At C:ScriptTest-ExchangeServerHealth.ps1:402 char:14
    + if ($Log) {Write-Log $_.Exception.Message}
    + ~~~~~~~~~
    + CategoryInfo : ObjectNotFound: (Write-Log:String) [], CommandNotFoundException
    + FullyQualifiedErrorId : CommandNotFoundException

    Write-Log : The term ‘Write-Log’ is not recognized as the name of a cmdlet, function, script file, or operable
    program. Check the spelling of the name, or if a path was included, verify that the path is correct and try again.
    At C:ScriptTest-ExchangeServerHealth.ps1:416 char:14
    + if ($Log) {Write-Log $_.Exception.Message}
    + ~~~~~~~~~
    + CategoryInfo : ObjectNotFound: (Write-Log:String) [], CommandNotFoundException
    + FullyQualifiedErrorId : CommandNotFoundException

    Remove-PSSession : Cannot validate argument on parameter ‘Id’. The argument is null. Provide a valid value for the
    argument, and then try running the command again.
    At C:ScriptTest-ExchangeServerHealth.ps1:423 char:19
    + Remove-PSSession $session.Id
    + ~~~~~~~~~~~
    + CategoryInfo : InvalidData: (:) [Remove-PSSession], ParameterBindingValidationException
    + FullyQualifiedErrorId : ParameterArgumentValidationError,Microsoft.PowerShell.Commands.RemovePSSessionCommand
    <—

    any idea what might cause this? It is pretty weird because not all the exchange 2010 servers return this error. Not all 2010 servers are running the same CU, but it does not seem to be bound to a specific CU (error occurs on servers with different CU levels).

    1. Avatar photo
      Paul Cunningham

      Whoops, a typo when trying to call the Write-LogFile function… must have been there for a while and gone unnoticed.

      I just pushed an update to Github and TechNet Script Gallery that should fix it.

  259. Phil

    This is a great script and I have been using it for years. However, recently in one of our environments where there is 2 CAS servers and 2 MBX servers, I am getting reports from the script saying ‘Could not test service health’. I run the script on two servers 30 minutes apart from each other. One server does not send the alert, so everything is ok, but the other started sending this regularly about a week ago.
    All other tests pass. but for each of the role services on each server, it shows Could not test service health. and ‘n/a’ in its own server roles.
    Does anyone have an idea what may have changed to cause this?

  260. IT

    Hi,

    We do have a strange issue with exchange 2013 where all the emails are in submission queue. All the test and checks are positive. Still cant fihure out why. The exchange server looks fine and seems no issue with it. All the emails are stuck in the queue and does nothing.

    1. Avatar photo
      Paul Cunningham

      Get-Queue | Get-Message | Fl

      That command will output a bunch of information about the messages in the queue, including any error messages (if any exist).

      1. IT

        Hi Paul,

        Thanks for the reply. I was able to clear the message queue by restarting the transport services which should do automatically pushing out emails.

        Hence, it is not the concern of messages in the queue but its not pushing out by itself.

        Exact Scenario: The email reaches the exchange server and just stuck there in the queue. Once the transport service is restarted, it pushes out few e mails and stops again.

        I had recreated the send/receive connectors but still doesn’t work.

        1. IT

          Just appending the error logs

          2015-02-05T00:14:43.859Z,08D208896C3835E1,SMTP,client proxy,>,Established connection to
          2015-02-05T00:14:44.258Z,08D208896C3835E1,SMTP,,-,Messages: 0 Bytes: 0 (Remote error from proxy client)

        2. Avatar photo
          Paul Cunningham

          If you do a few Google/Bing searches for things like “Exchange 2013 messages stuck in queue” you’ll find a lot of discussion around this topic. It is quite common, but can also be due to a wide variety of root causes. For example:

          http://thoughtsofanidlemind.com/2013/03/25/exchange-2013-dns-stuck-messages/

          First thing to check is whether you’re running the latest CU version of Exchange 2013 (currently CU7). Some of the earlier builds of Exchange 2013 did seem more prone to this type of transport issue.

  261. Mike

    Hi
    Thanks for the script, I can run it however I get an error on Mail Flow Test (see below)

    PS C:INSTALLSEXCHANGE_SCRIPTS> .Test-ExchangeServerHealth.ps1 -ReportMode -SendEmail
    Initializing…
    WARNING: The file C:INSTALLSEXCHANGE_SCRIPTSignorelist.txt could not be found. No servers, DAGs or databases will be ignored.
    —— Checking EXCHANGE-SERVER
    DNS Check: Pass
    Ping Check: Pass
    Uptime (hrs): 141
    Server version: Exchange 2013
    Roles: Mailbox, ClientAccess
    Mailbox Server Role Services: Pass
    Client Access Server Role Services: Pass
    Unified Messaging Server Role Services: Pass
    Hub Transport Server Role Services: Pass
    Total Queue: 1
    Mailbox databases mounted: Pass
    MAPI connectivity: Success
    Mail flow test: WARNING: Connecting to remote server mail.DOMAIN.COM failed with the following error message : WinRM cannot process the request. The follo
    wing error occurred while using Kerberos authentication: Cannot find the computer mail.DOMAIN.COM. Verify that the computer exists on the network and that
    the name provided is spelled correctly. For more information, see the about_Remote_Troubleshooting Help topic.
    WARNING: Cannot validate argument on parameter ‘Session’. The argument is null or empty. Provide an argument that is not null or empty, and then try the command again.
    Remove-PSSession : Cannot validate argument on parameter ‘Id’. The argument is null. Provide a valid value for the argument, and then try running the command again.
    At C:INSTALLSEXCHANGE_SCRIPTSTest-ExchangeServerHealth.ps1:410 char:19
    + Remove-PSSession $session.Id
    + ~~~~~~~~~~~
    + CategoryInfo : InvalidData: (:) [Remove-PSSession], ParameterBindingValidationException
    + FullyQualifiedErrorId : ParameterArgumentValidationError,Microsoft.PowerShell.Commands.RemovePSSessionCommand

    Fail
    —— Finishing
    Sending email.
    Done.

    The report is emailed OK (I edited the smtp section within the script), I have run the script on all exchange server and get the same result, I think the problem may be due to a missing spn mail.DOMAIN.com but I do not know what it is to registered to, can you help?
    Thanks
    Mike

      1. Mike

        Hi Paul,
        I was running CU3, I’ve upgraded to CU7 and now its working (thank you very much) However the CU7 upgrade has made the ForwardSyncDaemon component inactive and I cannot start it!!!!

        Many Thanks
        Mike

  262. George

    Hey Paul,

    I would like to run this script for my environment. Does it require a downtime or anything? I just need to know if its ok to run during business hours or I need to put in a change control as it may cause a temporary down of the servers.

    Thanks

  263. Peter

    Hi Paul,

    Script looks fantastic, however I’m running into three issues.

    1. Test-ServiceHealth against Ex2007 HUB server generates Watson dump. Below is error message:

    ////////////////////////////////////////////////////////////
    Roles: HubTransport
    WARNING: An unexpected error has occurred and a Watson dump is being generated:
    Could not test service health. : System.Management.Automation.RemoteException: NotSpecified: (:) [Test-ServiceHealth],
    OutOfMemoryException
    ////////////////////////////////////////////////////////////

    2. Mail-flow test against Ex2007 ccr cluster just skips.
    3. Mail-flow test against Ex2013 (in dag) that holds active databases fails. Below is error message:

    ////////////////////////////////////////////////////////////
    Mail flow test: WARNING: Connecting to remote server webmail.interpipeline.com failed with the following error message :
    WinRM cannot process the request. The following error occurred while using Kerberos authentication: Cannot find the computer webmail.interpipeline.com. Verify that the computer exists on the network and that the name provided is spelled correctly. For more information, see the about_Remote_Troubleshooting Help topic.

    WARNING: Cannot validate argument on parameter ‘Session’. The argument is null or empty. Provide an argument that isnot null or empty, and then try the command again. Remove-PSSession : Cannot validate argument on parameter ‘Id’. The argument is null. Provide a valid value for the argument, and then try running the command again.
    At X:Custom_ScriptsTest-ExchangeServerHealth.ps1:423 char:19
    + Remove-PSSession $session.Id
    + ~~~~~~~~~~~
    + CategoryInfo : InvalidData: (:) [Remove-PSSession], ParameterBindingValidationException
    + FullyQualifiedErrorId : ParameterArgumentValidationError,Microsoft.PowerShell.Commands.RemovePSSessionCommand

    Fail
    ////////////////////////////////////////////////////////////

    Any help is greatly appreciated!

    1. Avatar photo
      Paul Cunningham

      For 1 and 2 , the script isn’t tested or intended to work against Exchange 2007 servers.

      For 3, that looks similar to an issue raised by someone else. I believe the problem is SSL validation when trying to do a remote PowerShell session. I haven’t looked into a fix yet but it is on my list.

  264. Prakash

    Hi Paul,

    I like this new script as it has all information in one script.

    But It’s not showing color in Trans Queue like green/yellow/read. though information is written clearly that warning with number of messages/pass/fail.

    over all good.

    Thanks,
    Prakash

    1. Avatar photo
      Paul Cunningham

      Whoops, that got broken with a recent update. I’ll make a note and push out a fix as soon as I can.

    2. Avatar photo
      Paul Cunningham

      This is fixed now in the latest versions available on TechNet or Github.

  265. Mohamed Salama

    Hi Paul,

    Great Script!
    Is it possible in version 1.10 to get the number of messages in the Queue in the e-mail report?

    1. Avatar photo
      Paul Cunningham

      Sure thing. Just pushed an update to TechNet and Github to include that change.

      1. Mohamed Salama

        Thanks for your support 🙂

  266. Adam Borders

    Paul-

    I ran into an issue with the script I wanted to let you know about.

    I was running this against my new 2013 environment and it was not detecting my LAG copies correctly. I traced it down to line 1326. if ($replaylagcopy.Key -eq $mailboxserver)

    What I found is that in my environment it was having an issue due to case sensitivity. I changed the -eq to a -match and it resolved the issue.

  267. Damian

    Paul,
    I downloaded the script and am running on my Exchange server via windows powershell. I am using the -reportmode $true and I get an error that says “The operation couldn’t be performed because object ‘True’ couldn’t be found on “my domain controller”. Any ideas? My DC’s are Server Core.

    1. Damian

      Nevermind..I see now you don’t need $true. Saw youtube video of this script being run and that was included.

  268. Ian

    I’d like express a little frustration at your comment in the script that “reportfile implies reportmode:$true”. After chasing for an hour or two why no file was being created, I decided to add -reportmode in addition to -reportfile parameter and suddenly the file is being created.

    TL;DR: -reportfile DOES NOT IMPLY -reportmode, despite documentation to the contrary. *shakes fist*

  269. Nikolas

    As for the command I am using, “-Command .Test-ExchangeServerHealth.ps1 -ReportMode -SendEmail”

    1. Nikolas

      Paul,

      Awesome that answered my question. Thank you very much!

  270. Nikolas

    The script runs flawlessly in powershell and everything is passed or success, but I am not able to find the outputted .HTML file. Nor is it sending an email to the address I inserted. The relay is working without any issues, any ideas?

    1. Nikolas

      It looks like there are parameters that are set to false,
      ——————————————-
      [CmdletBinding()]
      param (
      [Parameter( Mandatory=$false)]
      [string]$Server,

      [Parameter( Mandatory=$false)]
      [string]$ServerList,

      [Parameter( Mandatory=$false)]
      [string]$ReportFile=”exchangeserverhealth.html”,

      [Parameter( Mandatory=$false)]
      [switch]$ReportMode,

      [Parameter( Mandatory=$false)]
      [switch]$SendEmail,

      [Parameter( Mandatory=$false)]
      [switch]$AlertsOnly,

      [Parameter( Mandatory=$false)]
      [switch]$Log

      )

      ———————————————

      Is this what I need to change in order for this to work?

      1. Avatar photo
        Paul Cunningham

        Mandatory=$false just means that they don’t need to be specified for the script to run.

        What is the exact command you’re running?

        1. Nikolas

          I am just running the script but my question is if I want this to push out the HTML file does something need to be modified or is the script doing this by default? Also I need it to send out the email in which I already added the smtp settings including testing via telnet.

        2. Avatar photo
          Paul Cunningham

          The script has multiple parameters/switches that are used to control the behaviour and output.

          The script also has built-in help. So you can run this command to see some examples of how to use the different parameters:

          [PS] C:Scripts>get-help .Test-ExchangeServerHealth.ps1 -Examples

          So if you want it to output both the HTML file and send the email, you would run:

          C:Scripts>.Test-ExchangeServerHealth.ps1 -ReportMode -SendEmail

  271. Mr. JIT

    Trying to download the script, but taken to my member content page and never gets me to the script download page.

  272. Mb

    Hi where do we download this script I cannot find the link anywhere

    thanks

  273. Mustafa Zain

    Thank you for your script.
    I have a little bug on the report. I run this report from Exch 2013 MBx server. So this server mail flow test always be failed.

    I replace the following line in the script to solve this problem:
    $result = Invoke-Command -Session $session {Test-Mailflow} -ErrorAction STOP

    with:
    if ($env:computername -like $e15mailboxserver)
    {$result = Test-Mailflow -ErrorAction STOP}
    else {$result = Invoke-Command -Session $session {Test-Mailflow} -ErrorAction STOP}

    Regards,

    1. BigGreg

      This fixed mt problem with Mail Flow tests failing. Thanks

    2. BigGreg

      This fixed my problem with Mail Flow tests failing. Thanks

  274. Amar Kanta

    Hi Paul,

    Thank you for the awesome script, but I was trying to send the report to multiple recipient but get is not sending , it is sending to only one address , I have tried putting , as well as ; ..any help would be appreciated..
    Amar

    1. Avatar photo
      Paul Cunningham

      Try sending it to a distribution group. That way you don’t need to modify the script any time a recipient needs to be added or removed, you can just do it in the group membership.

  275. Adam Borders

    I am in the process of migrating from 2010 to 2013. When I run the script on a system with the 2013 management tools it dies with the error: “Could not load file or assembly ‘Microsoft.Exchange.Data, Version=14.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35’ or one of its dependencies. The system
    cannot find the file specified.”

    The error happens at line 1159: $tmpdags = @(Get-DatabaseAvailabilityGroup -Status)

    I currently have two DAGs. An Exchange 2010 and an Exchange 2013. The (Get-DatabaseAvailabilityGroup -Status) command works but the (Get-DatabaseAvailabilityGroup -Status) command gives the error. I can run the command without the -Status parameter just fine.

    If I run the same script on a system with the 2010 tools installed it grabs the 2010 Dag just fine.

    Thanks,

    Adam

    1. Avatar photo
      Paul Cunningham

      Some bugs with the script like that seem to pop up in co-existence scenarios.

  276. Gabe Foltz

    Paul, I was able to get this working with *very* little effort in my Exchange 2010 environment. Although I already have other monitoring tools in place, this handy little script will give me additional peace of mind. I even got it running as a task from my local Win7 workstation with no errors.

    If anyone cares, my task was setup like many others, except I omitted the path in the argument by simply specifying the “Start in” folder. My Arguments looked like this:

    -Command .Test-ExchangeServerHealth.ps1 -ReportMode -SendEmail

  277. Andy

    Hi Paul,
    These scripts are awesome and the results have impressed the right people in the places I have used them.
    I have been asked if it is possible to get the results in an xml format so they can be used in a system dashboard.
    Can you give me any pointers on adding thast to the script as my powershell isn’t that good yet
    TIA
    Andy

    1. Avatar photo
      Paul Cunningham

      I’ve never tried XML output for the report. I suspect it won’t easily work because so much of the code is spitting out bits of HTML code that get assembled into the final report.

  278. Juanita

    Hi, I’m looking for a script that would automatically run the following tests. All in one.
    Test-Servicehealth
    Test-ReplicationHealth
    Test-Mailflow
    Get-MailboxDatabaseCopyStatus
    Test-MapiConnectivity

    1. Avatar photo
      Paul Cunningham

      Sure. Have you looked at the script mentioned in the article above?

  279. Sean

    Where is the link to download the script(s). If no link how I am able to get it?

  280. Chris

    Hi
    Where can I download this script from… cant find the download button

  281. Pär Glanzén

    Hi, when I run this script on one of my exchange server i get that the Tcp listener failed, but when I use the script on another server it says that there is nothing wrong with the tcp listener on the first server.

    is this something in the script or should I look elsewhere to find out why I get different results?

  282. Ram

    Steve, the script is not downloadable !

    1. Ram

      sorry – it is. rgrds.

  283. June Castillote

    Thank you for this Paul.

    I found that the script only does MAPI test on Mailbox DBs and does not include Public Folder DBs.
    In effect when you have a Mailbox Server without Mailbox DBs, only hosting PF DBs, you get an “Unknown” result in the report.

    I modified the script to include PF DBs in the MAPI Test.

    ———-
    ####Combined the two arrays into one####
    [array]$totaldbs = $pfdbs + $mbdbs
    ———-

    Then in the MAPI Test Loop
    ———-
    Instead of the original:
    foreach ($db in $mbdbs)

    I changed it to:
    foreach ($db in $totaldbs)
    ———-

  284. Vishal Patel

    When I run the test-exchangehealth.ps1 script on Exchange 2013 in co-existence with 2007 I get an error

    EXCH002FP – Hub Transport Server Role required services not running. (this is an exchange 2007 server with both CAS and Hub transports roles)

    When I run the test-exchangehealth.ps1 script manually and send email all works apart from the above , however when I use task scheduler to run the script and send email I get MAPI test failed on all servers that do hold active DB. (But works if I run manually)

    • EXCH003FP – MAPI tests failed.
    • EXCH004FP – MAPI tests failed.
    • EXCH010FP – MAPI tests failed.
    • EXCH011FP – MAPI tests failed.
    • EXCH020FP – MAPI tests failed.

    1. Spyros

      Did you find any solution for the MAPI tests failed?

  285. Jeromy Baldridge

    Thank you very much for the script. It saved me a lot of time trying to come up with a less robust solution on my own.

    After quite some digging I found the two pain points that I was having with the scripts. I did not want an email on uptime errors or database preference errors. Line numbers are not exact because I added some comments and set some variables to $true so I wouldn’t have to remember switches. I am using v1.09 of the scripts.

    Somewhere around line number 771 I modified the line for Uptime :
    Switch ($uptime -gt 23) {
    For my purposes I changed 23 to 1. I also modified the error message lines that followed in the next couple lines for completeness.

    Somewhere around line number 1594 I modified the line for DB Preferences :
    $dagsummary += “$($line.Database) – $string62 $($line.Preference)”
    For my purposes I commented this line out so it would not trigger an email when the database was not active on the preferred server.

    1. Avatar photo
      Paul Cunningham

      Always great to hear people are successfully customizing the script for their own needs 🙂

  286. Gary Libero

    Hey Paul!

    We’ve been having issues with our Exchange 2010 server and I was VERY thankful to find your script here to help troubleshoot and check the health of our DBs. I’m not much a script guy, but I changed the email parameters, ran the script and when it gets to “mail flow check”, the script seems to stop (the PS window closes). Does that mean the script is not completing? I’m not receiving emails or seeing a file generated either way.

    Any help would be great appreciated!

    Thanks!
    Gary

    1. Rosario

      You may send me that piece of code you changed for review rosario-dot-carco{at}fhnw-dot-ch

    2. Avatar photo
      Paul Cunningham

      Gary, the window closes? If you’re running the script from a PowerShell window it should remain open and display any error that is causing the script to halt. Are you running it some other way?

      Otherwise, run it with the -Log parameter, which will write a log file that may assist with troubleshooting.

      1. Gary Libero

        Hey Paul!

        I got it working! I was right-clicking the file and selecting “run with Powershell”. Maybe it didn’t like that. I ran directly from PS and it completed fine.

        I can’t seem to get the email portion working. I set the parameters with all of our SMTP settings, but get nothing. I’ll have to review the notes again, but where is the parameter to just write an output file to the C Drive?

        Thanks!
        Gary

        1. Avatar photo
          Paul Cunningham

          You’ll find all the instructions and an FAQ on the page where the script is downloaded.

  287. André Winkler

    Hi @ll,

    at the moment im having problem with our Exchange 2013 and the mailflow test. Powershell tells me that there is a problem mit WIN-RM and negotiate Authentication.

    Another problem is on line 408 sign 19: Remove-PSSession $session.Id is not found. Is the variable defined somewhere?

    I am using Windows Server 2012 R2 in german with Exchange 2013 SP1.

    THX.

    1. André Winkler

      Hi again,

      yesterday i tried to run the script on the CAS and not on the Mailboxserver. Now it is running without any Errors.

      On all my Exchange 2010 Servers i have to run the script on the Mailboxrole. Can someone explain this?

      THX
      André

      1. Rosario

        As I told above, I scheduled the script to run on a CAS-Server, no problems. As I am developing another script, yesterday I tried to load the PSSnapin as Paul does to execute the exchange powershell commands from my Win7 Workstation and it quit with the Error “SnapIn could not be loaded”. So I do also wonder how much of the exchange powershell must be installed on my remote workstation, or whether we could get everything without installing any tools by opening a remote-powerShell-Session like this:

        $s = New-PSSession -ConfigurationName Microsoft.Exchange -ConnectionUri http://phx-ex01.exchangelab.com/PowerShell/ -Authentication Kerberos -Credential (Get-Credential)

        Import-PSSession $s

        Of course this would only be a solution for interactive development. For scheduled execution during night, it may in any case be better to let the scripts run directly on the CAS-Servers where the needed user privileges are set up in the schedule itself (no need to ask for credentials)

        Rosario

  288. Aidan

    Hey Paul,

    Im getting the following error from one of my cas servers… other cas server works fine…

    Send-MailMessage : The SMTP server requires a secure connection or the client was not authenticated. The server response was: 5.7.1 Client was not authenticated

    Ive checked permissions on all the connectors, tried using ssl and forcing credentials… any ideas?

    Much appreciated!

      1. Aidan

        Sorry! Should have looked, thanks a million Paul!!

  289. Jimmy Singal

    Hi Paul,

    Need your help:
    1. How do I pause the script when it finished checking? It seems the window will auto close.
    2. How can we send email to more recipients?
    3. If I create a shortcut using this command: %SystemRoot%system32WindowsPowerShellv1.0powershell.exe -ExecutionPolicy Bypass -File “C:scriptsTest-ExchangeServerHealthTest-ExchangeServerHealth.ps1” -ReportMode -SendEmail

    The script will run just fine and I will receive the email, but in a glance at the end of the result (on the powershell window) before the window close by itself I saw some lines in red, it looks like there are some errors.

    Thank you.

    1. Aidan

      Hi Jimmy,

      Answer1+3: At the end of the script you can add the noexit parameter e.g.

      %SystemRoot%system32WindowsPowerShellv1.0powershell.exe -ExecutionPolicy Bypass -File “C:scriptsTest-ExchangeServerHealthTest-ExchangeServerHealth.ps1″ -ReportMode -SendEmail -noexit

      Also running the script directly from a powershell window (rather than the scheduled task) will give the desired result.

      E.G. from powerhsell “C:scriptsTest-ExchangeServerHealthTest-ExchangeServerHealth.ps1 -ReportMode -SendEmail ”

      Answer 2:

      1 option would be to just create a Distribution list on the exchange with the desired users.

      The other option would be to add the accounts into the script like so:
      $To = “user1@domain.com,user2@gmail.com,distrolist@domain.com”

      Hope that helps,
      Aidan

      1. Jimmy Singal

        Hi Aidan,

        Thanks for your reply.
        Looks like the it works for my question 1 and 3.
        But for the email I have tried with the commas, it will only send to the first recipient. I haven’t created a distribution list.

        1. Aidan

          Sorry Jimmy, my bad!

          I wasnt looking at the script…

          Remove the To parameter from the array and below it create a variable with the smtp addresses:

          Line numbers 109-116

          $smtpsettings = @{
          From = “exchangeserver@exchangeserverpro.net”
          Subject = “Exchange Server Health Report – $now”
          SmtpServer = “smtp.exchangeserverpro.net”
          }
          $To = “user1@domain.com”,”user2@domain.com”,”user3@domain.com”

          Now add the -To parameter in the send-mailmessage function:

          Line numbers 1528-1530
          Send-MailMessage @smtpsettings -Body $htmlreport -BodyAsHtml -To $To -Encoding ([System.Text.Encoding]::UTF8)

          That should be that!

        2. Avatar photo
          Paul Cunningham

          Seriously, just use a distribution list. Then you don’t need to edit the script every time your list of recipients changes.

        3. Rosario

          It worked for months as Paul programmed it. But for a strange reason I did not track back, it began to send the eMail only to the first person around January or February. I guess Aidans solution should be

          $to = “user1@domain.com,user2@domain.com,user3@domain.com”

          with only one pair of “” – Rosario

        4. Jimmy Singal

          Thanks Paul & Aidan,

          I have not tried Aidan’s solution yet, as I am just using the distribution list for keep the thing simple.

          To wrap up at this point, my task scheduler is being used to run the script from inside a batch file. Not sure why I keep having problem running the script if I specify it directly in the task scheduler.

          Also don’t forget to use @echo off at the beginning if not the task will keep running and running.

        5. Rosario

          Scheduling the powershell script is a little bit tricky.

          Program/Script: C:WindowsSystem32WindowsPowerShellv1.0powershell.exe

          Add argument: -Command “& C:psScriptsCheckExchangeServerHealth.ps1 -sendEmail”

          Start in: C:psScripts

  290. Robert

    Disregard ran this Set-ExecutionPolicy -Scope Process -ExecutionPolicy Bypass and good to go. Thanks!

  291. Robert

    Paul,

    When I run the script I get not digitally signed error… ***HELP*** 🙂

  292. Jose Byron Gonzalez

    Hello and thanks for another wonderful script, Paul.

    Also related to the ignorelist.txt a rather silly question but one that’s vexing me: is it supposed to have any particular format or structure? Or a simple line-by-line list of servers, databases, DAG, etc?

    Is there a way to limit the scope to a single AD site (or exclude others)?

    Thanks so very much. You The Man, man!

    1. Avatar photo
      Paul Cunningham

      Simple line by line list, yes.

      You can customize it any way you like really. The builtin parameters provide some flexibility but everyone has different needs.

      The script just uses the Exchange cmdlets. So if you want Get-ExchangeServer to return just the servers in a site, modify that line of the script accordingly.

  293. Or Elim

    Did anyone managed to migrate this wonderful script to support Exchange 2007?

  294. Rob

    Love the script, I am having one error though, it will not call the ignorelist.txt file. It says “Warning: The file at …ignorelist.txt could not be found. No servers, DAGs, or databases will be ignored.” Is there a fix for this?

    Thanks.

    1. Avatar photo
      Paul Cunningham

      The script looks for the file in the current directory. Are you running the script from the directory where it is stored, or running it from a different directory?

  295. Michael Wiskman

    Great script. Very good to show customers. They know that green is good and red is bad. Then it is easy to explain that you have to fix errors in their environment.

    Thank You Paul.

  296. luis

    Thanks Paul. !!!!!!!!!!!!!!!!!!

    Perfect work.

  297. martinezjrj

    Brilliant! i should have known to retrace steps… like i said before, “NEWB”

    i was missing a double quote at the end of the smtp server name string!

    Thanks! wish there was a way to buy you a beer or cup of coffee!

    Cheers!

    Joel

  298. martinezjrj

    Paul thank you! This is probably a newb issue but i keep getting this error when i run this and cant seem to figure it out…

    [PS] C:scripts>.Test-ExchangeServerHealth.ps1 -Reportmode -Sendmail
    Unexpected token ‘Mailbox’ in expression or statement.
    At C:scriptsTest-ExchangeServerHealth.ps1:327 char:19
    + $mbrole = “Mailbox <<<< Server Role"
    + CategoryInfo : ParserError: (Mailbox:String) [], ParseException
    + FullyQualifiedErrorId : UnexpectedToken

    the error refers to the section in the script where variables for the server roles are initialized, here:

    # The server roles must match the role names you see when you run Test-ServiceHealth.
    $casrole = "Client Access Server Role"
    $htrole = "Hub Transport Server Role"
    $mbrole = "Mailbox Server Role"
    $umrole = "Unified Messaging Server Role"

    Thank you

    Joel

      1. martinezjrj

        Yes Paul i did but only to try and narrow down the issue. Running the script as is, with only the email settings modified, produces the same error. Sorry for the confusion. i posted the error produced when using the modified order, but posted the original code as reference. My bad!

        the original code:
        # The server roles must match the role names you see when you run Test-ServiceHealth.
        $casrole = “Client Access Server Role”
        $htrole = “Hub Transport Server Role”
        $mbrole = “Mailbox Server Role”
        $umrole = “Unified Messaging Server Role”

        i get this error:
        [PS] C:scripts>.Test-ExchangeServerHealth.ps1 -reportmode -sendmail
        Unexpected token ‘Client’ in expression or statement.
        At C:scriptsTest-ExchangeServerHealth.ps1:327 char:19
        + $casrole = “Client <<<.Test-ExchangeServerHealth.ps1 -Reportmode -Sendmail
        Unexpected token ‘Mailbox’ in expression or statement.
        At C:scriptsTest-ExchangeServerHealth.ps1:327 char:19
        + $mbrole = “Mailbox <<<< Server Role"
        + CategoryInfo : ParserError: (Mailbox:String) [], ParseException
        + FullyQualifiedErrorId : UnexpectedToken

        I have a Single Exchange 2010 Server SP3 (All Roles – no Unified Messaging) running on Windows Server 2008 R2 Standard SP1.

        Could it be SP3?

        thank you

        Joel

        1. Avatar photo
          Paul Cunningham

          The problem will most likely be where you made changes (to the SMTP settings) and haven’t closed a set of quotes properly.

  299. Jackson

    I found this took quite a while to run in a larger environment, 14+ hours. I was able to cut that time down to just a few hours with modifying the Test-E15MailFlow function, line 372 to simply add the -ADPropertiesOnly flag. Running the script with -Verbose I saw this is where it was hanging up. I hope it can help others!

    Write-Verbose “Creating PSSession for $e15mailboxserver”
    $url = (Get-PowerShellVirtualDirectory -Server $e15mailboxserver -ADPropertiesOnly | Where {$_.Name -eq “Powershell (Default Web Site)”}).InternalURL.AbsoluteUri

  300. Richard

    I have tried this on our Exchange 2010 set up. It reports a FAIL for the ‘Mailbox Server Role Services’ for one of our mailbox servers, but I’m not sure where to check why this is failing. I have looked at the script and couldn’t find out what test it is running for this. The server concerned seems to be running fine, our backup mailbox server gets a Pass for this test. A look at the logs on the server shows nothing amiss either.

    What does ‘Mailbox Server Role Services’ actually test?

  301. James Ledgard

    Brilliant script. Thanks for the hard work you and the others put into this.