Monitoring Exchange 2007 / 2010 with Powershell (Part 4)

If you would like to read the other parts in this article series please go to:






In the first part of this series we highlighted that the ability to know what is happening on your Exchange Servers quickly and accurately is key to effective Exchange Administration.


In the second part we began to construct a script that when completed could be scheduled via the Windows Task Scheduler to monitor some basic aspects of your Exchange environments – in the second part we defined the following functions:



  • Checking CPU Utilisation
  • Checking Free Memory
  • Checking Event Logs
  • Checking each server for specific Exchange Roles and executing the relevant tests


In the third instalment we added functionality to the script in the form of:



  • Checking the status of Exchange related Services
  • Defining a function that will perform a number of Mailbox Role tests
  • DiskspaceTests
  • Database BackupTests


In this the final part we will round off the script by:



  • Define health checking functions for the CAS and HT roles
  • Put the whole script together in a single file for download
  • Explain how you can schedule the script
  • Add a few suggestions for further development


Checking Hub Transport Role


The purpose of the HT Role checking function is naturally to provide some basic information about the health of mail transport within your organisation.


The function itself is called from the check_roles () function and determines all of the queues which are resident on the Hub Transport Server(s) that are passed to the function from the ExchangeServers.txt file.


The function then compares the amount of messages awaiting processing in those queues against the threshold value that is stored in the $QueueMessageUpperLevel global constant. If the number of messages in the queue is greater than the global constant an alert is sent to the administrator.


The number of messages in each queue on the transport server is determined by using the Get-Queue function in a variable called $AvailableQueues.


Then using a for each loop we cycle through the queues in the $AvailableQueues variable checking the number of messages contained within – we then use an if statement to invoke the SMTPAlertMessage function if needed.


We finish off the function by checking disk space on the HT server (the checkDiskSpaceFree function was detailed in part 3 of the series).










if($Queue.MessageCount -gt$QueueMessageUpperLevel){


$MessBody=”The following Transport Queue: “+$Queue.Identity +” has exceed the maximum permissible message count with “+$Queue.MessageCount


SMTPAlertMessage”Exchange Transport Queue Error”$MessBody











Checking the CAS role


The CASRoleTest function purpose is to check the basic health of the Client Access Function. Now you might expect me to make use of the Test-Outlookweb Services or Test-OWAConnectivity within this function – and indeed as part of the developments section of this article I do suggest that this functionality is added.


However in the context of web connectivity I have focussed on actually checking to see if you can establish a connection and hit a webpage on your Client Access Server.


In essence I establish a .Net Web Request to a URL on the client access server (the URL is defined in $URL – this can be changed to fit your own personal configuration. I then attempt to make a connection to that URL. If the result of that connection is anything other than Status 200 (OK) then the script sends an alert to the administrator.


If I cannot make a http request to the CAS (e.g. if the IIS service is down) the GetResponse() with throw an exception – therefore using the try{}catch{} exception handling – the code in the }catch{ segment is invoked – this will send an alert message to the administrator suggesting that the IIS service has terminated or is down.


You could expand the functionality of this function at this point by adding in some more detailed testing using the Test-OwaConnectivity or Test-OutlookWebServices should you wish.


I finish off the function by performing a very basic MAPI connectivity test using the Test-MAPIConnectivity cmdlet.





# Change the URL below to your internal OWA instance





$webRequest= [net.WebRequest]::Create($URL)










Write-Host“Testing OWA Site”-ForegroundColorCyan


if($response.statusCode -ne 200){


$MessBody=”There appears to be a problem with the IIS instance of $URL – testing of the instance returns Status code: “+$response.statusCode


SMTPAlertMessage”Exchange CAS Error”$MessBody







Write-Host“Testing OWA Site”-ForegroundColorMagenta


$MessBody=”There appears to be a problem with the IIS Service of $URL – Cannot connect to Service”


SMTPAlertMessage”Exchange CAS Error”$MessBody







Write-Host“Testing MAPI”-ForegroundColorMagenta





if($MapiEndPoint.Result -ne”Success”){



$MessBody=”There appears to be a problem with MAPI Connectivity on: “+$MapiEndPoint.Server +” Context: “+$MapiEndPoint.Database +” Error: “+$MapiEndPoint.Error


SMTPAlertMessage”Exchange CAS Error”$MessBody










The completed script


You can download the compressed version of the completed script with all the functions in order from the following location:




Using and Scheduling the Script


In order to make use of the script in your environment please use the following steps –



  1. Download it to an Exchange Server of your choosing
  2. In the same folder as the script – create a file called “ExchangeServers.txt
  3. Within the ExchangeServers.txt file – add the NETBIOS names of each Exchange Server that you would like to monitor. Each server should be placed on a new line within the file
  4. Save and close the file
  5. Open the script and add the following line at the top
  6. Within the script file change the following lines:
    To the location of the ExchangeServers.txt file and an appropriate SMTP smart host within your environment.
    You should also modify the following thresholds to acceptable values for monitoring:
    # Set global Constants
    $DBSizeThreshold= 200                           # In MB
    $PDBSizeThreshold= 200                          # In MB
    $lastBackupThreshhold= 1                        # In days
    $DiskspacePercentageFree= 10                           # In %
    $QueueMessageUpperLevel= 5                      # In Number of Messages
    $MemoryThreshold= 800                           # MB Free
    $CPU_UpperLeverPercentage= 20                   # Utilisation over sample period
    You should also change the values in the SMTPAlertMessagefunction to reflect your administrator account within your organisation:
    From =”[email protected]
    To =”[email protected]
  7. Save and close the script file
  8. Ensure that the Execution Policy for PowerShell is set to “Remote Signed”
    Open a PowerShell command prompt and type “Set-ExecutionPolicy RemoteSigned”
  9. Create a batch file called “ExMon.bat” on your Exchange Server and add the following lines:
    @Echo Off
    @Powershell –command “& {<path to script>\MSEXMON_DEMO.ps1}”
    See example below:

    Figure 1
  10. Save the file to a location on your Exchange Server
  11. Use the Windows Task scheduler to execute the batch file at a re-occurring time which is convenient for you (5, 10 minutes) – you should ensure that the account that the task context executes in has the correct Exchange permissions


Possible Improvements or future developments for the script


The script itself is very basic – and is designed to give people an idea of what can be accomplished with PowerShell in terms of Exchange Monitoring.


There are a number of improvements that could certainly be made to the overall functionality – the following are a few suggestions that may stimulate the creative minds amongst you:



  • The script determines each Exchange Server from names that are contained within a Text file, there is no reason why this cannot be automated using the Get-ExchangeServer cmdlet and performing role checks based on the “ServerRole” property
  • In the examples given the script uses the actual Exchange Server as the SMTP smart host. In production – it is probably better to use an independent SMTP server, just in case one of the problems that you have is the Exchange Server’s HT function is not working correctly – this will naturally result in no mail being sent
  • There is little or no support for clustered instances (or DAGS) within the script – whereas most of the functions will work against clustered servers – there is no detection of nodes within a cluster or any specific node based tests
  • Some of the script construct is very messy – e.g. the checkDiskSpaceFree function will be called multiple times for multi-role servers resulting in duplicate mails to the admin
  • The HTRoleTest function could be expanded to actually attempt a connection to the HT Server on port 25 – if this fails, the script could failover to another SMTP host
  • The CASRoleTest function does not make use of any commands to test the Autodiscover  or OWA connectivity services – it could be expanded to include these




This pretty much wraps up this series. In this part we have covered the code that can help you can monitor HT and CAS Servers, provided the completed script and made some suggestions for improvements.



If you would like to read the other parts in this article series please go to:



Leave a Comment

Your email address will not be published.

This site is protected by reCAPTCHA and the Google Privacy Policy and Terms of Service apply.

Scroll to Top