I was performing some mailbox server health checks recently and was trying to find an easy way to test mail flow latency between a lot of servers at once using Test-MailFlow.
After a little bit of tinkering I came up with a PowerShell script that would do the job, but the report it generated was a bit hard to read because all of the output was just on the screen in a single colour. So I decided to take it a step further and output the results to HTML and use colour-coded table cells to give me a report that is easier to read at a glance.
So I’m sharing the script with you here as well. Please be aware that I haven’t put a lot of coding effort into adding custom parameters, testing a wide variety of scenarios, or doing complex error handling. Also the script doesn’t troubleshoot for you, it only outputs a result that may indicate a problem for you.
Download the script from Github: MailFlowHeatMap.ps1
How to Run the Script
The script has no parameters, you simply execute it from within PowerShell on a server or computer that has the Exchange 2010 management tools installed.
PS C:\>.MailFlowHeatMap.ps1
You may need to right-click the downloaded file, open the Properties and unblock it. You may also need to set your PowerShell execution policy to allow unsigned scripts to run.
A small amount of output is written in the shell window to let you know that the script is making progress.
The result is a HTML file showing colour-coded table cells for the mailbox latency values (which are in seconds).
Customizing the Script
You can customize the heat map colours and the output file name by modifying these variables in the script itself (values are in seconds, cool and cold should be the same).
[int]$hot = 30 [int]$warm = 20 [int]$cool = 10 [int]$cold = 10 $filename = "mailflowheatmap.html"
If you’re looking to scheduled the script to run using Task Scheduler there is an example of how to do that here.
If you’d like to email the report to yourself there is example code here. You would just need to modify that example to use the $htmlreport in this script as the message body.
$message.Body = $htmlreport
Download the script from Github: MailFlowHeatMap.ps1
If you have other questions please leave a comment below.
I’ve closed comments on this post as it’s likely that this script simply won’t work well in most 2013/2016 environments these days. Keep in mind that this script was written in the Exchange 2007 era, when Test-Mailflow worked properly. The cmdlet tends to break in more situations now. But the script was always intended more as a proof of concept for building visual HTML reports from PowerShell scripts, and you’re welcome to take the code and use it or modify it for your own purposes.
You killed this Paul!!
Great Job Brother
Hi This is working fine and generating output in html format , but i am not receiving email although i have put correct sender,recipient and smtp server name.
could you please help.
The Real Person!
The Real Person!
This script doesn’t have any options for sending the report as an email.
Hi Paul
Is it possible to modify the script so that it will run a test against an Exchange box in another org? We want to test mailflow originating from outside (so as to include any internet failures in the mix) so want to run something like this on a box external to the mail servers themselves.
Olly
Hi Paul,
Great script. unfortunately after for about 2 months something isnt working. i’ve been troubleshooting this for a while and i am about to give up.
issue: mailflowheatmap comes back with an error – but i cant find where to resolve.
environment – two exchange 2013 CU13 servers in a dag – exch1, exch2
let me jump to the end for a minute – Test-Mailflow comes back clean from both sides
Test-Mailflow exch1 -TargetMailboxServer exch2
RunspaceId : 0b2dddf7-ae8b-4152-8caf-945d97e13fae
TestMailflowResult : Success
MessageLatencyTime : 00:00:00.7563999
IsRemoteTest : True
Identity :
IsValid : True
ObjectState : New
error from mailflowheatmap
[PS] C:installExchange Tools>.MailFlowHeatMap.ps1
Creating a new session for implicit remoting of “Get-ExchangeServer” command…
Testing exch1 to exch1
Testing exch1 to exch2
WARNING: Message latency from exch1 to exch2 not tested due to an error.
WARNING: Starting a command on the remote server failed with the following error message : The WinRM client sent a request to the remote WS-Management service and was notified that the request size exceeded the configured MaxEnvelopeSize quota. For more information, see the about_Remote_Troubleshooting Help topic.
Testing exch2 to exch1
WARNING: Message latency from exch2 to exch1 not tested due to an error.
WARNING: Starting a command on the remote server failed with the following error message : The WinRM client sent a request to the remote WS-Management service and was notified that the request size exceeded the configured MaxEnvelopeSize quota. For more information, see the about_Remote_Troubleshooting Help topic.
Testing exch2 to exch2
WARNING: Message latency from exch2 to exch2 not tested due to an error.
WARNING: [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=304][latency=421]
Lid: 52176 ClientVersion: 15.0.1210.3
Lid: 50032 ServerVersion: 15.0.1210.3
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.1210.000:exch2
Lid: 1750 —- Remote Context End —-
Lid: 26849
Lid: 21817 ROP Failure: 0x4DC
Lid: 60547 StoreEc: 0x4DC
Lid: 21966
Lid: 30158 StoreEc: 0x4DC
Done.
both servers return 700 for MaxEnvelopeSizekb
winrm g winrm/config
Config
MaxEnvelopeSizekb = 700
MaxTimeoutms = 60000
….
if i run emtshooter – it always runs against exch2 (cant get it to connect to exch1)
output – identical on both servers
Welcome to the Exchange Management Troubleshooter!
We recommend that you run the troubleshooter after making changes to
IIS to ensure that connectivity to Exchange Powershell is unaffected.
Checking IIS Service…
Checking the Exchange Install Path variable…
Checking the Powershell Virtual Directory…
Checking the Powershell vdir SSL setting…
Checking the Powershell vdir path setting…
Checking HTTP Port 80…
Checking HTTP Port 80 Host Name…
Testing for errors…
2
Location ConnectToAnyServer 2
VERBOSE: Connecting to Exch2.swiftechosting.com (it says this on BOTH servers – never says connecting to exch1)
The Exchange Management Troubleshooter successfully completed connecting to:
Exch2.swiftechosting.com
test get-datghealth comes back clean (and correct)
we are not experiencing any issues anywhere – i just like the script and it no longer works.
thoughts?
thank you
The Real Person!
The Real Person!
Test-Mailflow seems to have had a bumpy ride over the years. Keep in mind this script was written in a 2007 environment, and was mostly a PoC for HTML formatting for me. Since then the server architecture has changed a lot, and I’ve seen all kinds of wacky behavior with the Test-* cmdlets as a result.
Right now the script throws some errors in my 2016/2013/2010 coexist lab. It might have something to do with where active database copies are sitting at the time, or something else. Haven’t dug any further into it to be honest.
Hello Paul,
thanks for the script. I tried it into my enviromnent but something is strange with the result values. They are to high after the conversion in line ‘[double]$latency = “{0:N2}” -f $($result.MessageLatencyTime.TotalSeconds)’. For example, the value of MessageLatencyTime.TotalSeconds is 1,3785 after the conversaion the value is 138.
It estimated there is a possibility that you can send me the script please download it and that tells me that there is no 404 page not found
very thankful
The Real Person!
The Real Person!
Hi Rodolfo, I’ve uploaded the script to Github and updated the download links in the article above, so you should be able to get it now.
Paul, thank you very much for your answer, is very good
Best regards!!!
Hi Paul
Is there anyway i can automate this Script to have Message Latency Hourly results.
Actually, I want to have the Message Latency hourly results for atleast 3 Days.
Best Regards
Hi Paul
Thanks for the script. You have made the job much more easier.
Please let me know what are the factors the message latency depends on.
Is there any way to reduce the message delivery between two mailbox servers.
Hi Paul,
Many thanks for so many good scripts. I have been trying to tinker with this script (Exchange Mail Flow Latency Heat Map) to get it to work with Exchange 2013 but it is beyond my PowerShell skills.
Have you ever been able to get it to work with Exchange 2013?
Many thanks
Sean
When I run the MailFlowHeathMap I get the following error …. Any idea’s
Thanks …
Joel
Get-Member : No object has been specified to the get-member cmdlet.
At C:scriptsmailflowheatmapMailFlowHeatMap.ps1:97 char:32
+ $headers = $report | Get-Member <<<< -MemberType NoteProperty | Select Name
+ CategoryInfo : CloseError: (:) [Get-Member], InvalidOperationException
+ FullyQualifiedErrorId : NoObjectInGetMember,Microsoft.PowerShell.Commands.GetMemberCommand
Hi Paul,
The script was very helpful and working without any issues. thank you very much.
Pl. help me to modifiy the script to show only the mailbox server results and skip the non mailbox result in the table.
Great tool. You don’t have a catch for a mail flow failure (and failure shows latency of 0 for some reason) so I modified the code in the following way:
if ($result.testmailflowresult -eq “Success”)
{
[double]$latency = “{0:N2}” -f $($result.MessageLatencyTime.TotalSeconds)
$reportObj | Add-Member NoteProperty -Name “To $targetserver” -Value $latency
}
else
{
$reportObj | Add-Member NoteProperty -Name “To $targetserver” -Value $result.testmailflowresult
}
And down below:
elseif ($value -eq “*FAILURE*”)
{
$htmltablerow = $htmltablerow += “$value”
}
Threw in new catch for a -le $suspicious value of 0 and a nice purple hue (#8000FF) for td.suspicious as well, just in case.
Mail flow and transport queues showed RED in your test-exchangeserverhealth and I tried to use this script to diagnose. Turned out to be insufficient Log disk space. Log Disk Free space in my Exchange Environment Report is showing 96.1% free for all disks likely because it’s checking the mount point rather than the actual LUN space. Doh! Any suggestions for querying that accurately?
The Real Person!
The Real Person!
Nice fix. Glad to see someone using the script 🙂
Querying mount points in PowerShell is reasonably simple. The complex bit is working out the log or database path for a database and then finding the appropriate mount point. Not impossible, just needs a bit of work.
Pingback: Testing Exchange Server Updates – Part 1 | Just A UC Guy
Hi Paul
Could you help me?
When I try to execute your script I receive this error:
Get-Member : No object has been specified to the get-member cmdlet.
At C:MailFlowHeatMap.ps1:97 char:32
+ $headers = $report | Get-Member <<<< -MemberType NoteProperty | Select Name
+ CategoryInfo : CloseError: (:) [Get-Member], InvalidOperationException
+ FullyQualifiedErrorId : NoObjectInGetMember,Microsoft.PowerShell.Commands.GetMemberCommand
Pingback: pumpernickel bread recipe
Pingback: Netrix LLC – Exchange 2013 PowerShell Scripts – A Practical Guide – Part 2
Hi Paul,
this script check email latency between mailbox server’s, but is there any way to find latency with email send out to internet ?
Pingback: Exchange 2013 PowerShell Scripts – A Practical Guide – Part 2 | Just A UC Guy
Pingback: Exchange 2013 PowerShell Scripts – A Practical Guide | Just A UC Guy
Great job Paul,
I just tested this script in severals environments but in some cases the latency is returned with a comma 1,32 instead of returning 1.32. To solve this I’ve modified the script
Added this variable: $USCulture = New-Object System.Globalization.CultureInfo(“en-US”)
and replaced [double]$latency = “{0:N2}” -f $($result.MessageLatencyTime.TotalSeconds) with
[double]$latency = $result.MessageLatencyTime.TotalSeconds.ToString(“F2”,$USCulture)
This works fine in all environments
Hey Paul,
Will this heat map PS work in Exchange 2013? Or will this only work for 2007/2010?
The Real Person!
The Real Person!
I haven’t tested it but it will probably work fine as the cmdlets are the same.
Hi Man,
Thanks for your script, this is perfect.
I have one question.
When I execute this script in a physical machine, evertything is all right on report but when i execute this one in one virtual machine the report be all red…
Do you know why this things happen? did you see it in another environment?
Regards.
The Real Person!
The Real Person!
I can’t think of any reason a physical vs virtual would give you different results other than that the virtual machine is under-resourced perhaps.
Hi Paul,
Thanks very much for sharing this. The script is very handy. It worked like charm almost since first run despite a permission error trying to create the html in C: (My bad)
Thanks again mate.
Hi Paul,
Can you tell me how to verify daily /weekly/monthly email transactions from Exchange servers 2010.
I there any reporting tool ?
Hi Amit,
Please try User profile analysis scrpit. It works great for my organization.
http://blogs.technet.com/b/neiljohn/archive/2011/08/09/user-profile-analysis-for-exchange-server-2010.aspx
Hi Paul,
Can you tell me how to verify daily /weekly/monthly email transactions from Exchange servers 2010.
I there any reporting tool ?
Thanks and Regards,
Amit Atugade
I would like this to email through the results the same way the test-exchangeserverhealth script does.
please can you help elobrate on the format to get it the same
I meant to say also, for a larger organisation with multiple active servers, scheduling this with another task to copy it to a IIS server where the html file could be viewed in IE by the whole IT team, that would be fantastic.
Thanks for the great script Paul.
I got a bit worried when I ran it the first time, as it errored everywhere, but then.. yeah.. realised that only one of our DAG servers is active..
BB-EX02 Error Error Error
RC-EX02 Error Error Error
RC-EX03 Error Error 2.77
I will definitely file this one away for future reference though, thanks again!
Question / Suggestion:
Could this HTML output include a reference legend for the code …..
td.cold{background: #B3E6B3;}
td.cool{background: #E2F09C;}
td.warm{background: #FF6E6E;}
td.hot{background: #E34949; color: #ffffff;}
A visual so it is known what the values and color relationships are?
Is it right to get errors when running it on servers in a dag?
I’ve got 3 mailbox databases accross two servers (local and remote) in a DAG. Is it because the active server is LOCAL?
Seems the only one that didn’t give an error is when it tested LOCAL to LOCAL
I get …
Testing REMOTE to REMOTE
WARNING: Exchange can’t perform the mail flow test because currently there are no mailbox databases on server TRINITY.
Testing REMOTE to LOCAL
WARNING: Exchange can’t perform the mail flow test because currently there are no mailbox databases on server TRINITY.
Testing LOCAL to REMOTE
WARNING: Exchange can’t perform the mail flow test because currently there are no mailbox databases on server TRINITY.
Testing LOCAL to LOCAL
Done.
My bet is it will only report on the databases that are active on the server you’re running the script against.
We’ve got a 2 location, 4 DB DAG, with 2 running in one location, and the other 2 in the other.
The script should report the 2 that are running on the server they’re currently mounted on.
The Real Person!
The Real Person!
Yes, the script will error (or really its just a warning) for a DAG member with no active databases.
Another fine script to help us Exchange Administrators out! Great work – I’m adding it to my daily scripts.
The Real Person!
The Real Person!
Glad you like it Joe.
Thank you Paul, I use your script daily and i really appreciate you for sharing it.
Test-mailflow was working fine but i starting getting the below error , any idea?
Test-Mailflow not working on server1 when mailbox database X is mounted on server1
Error [Microsoft.Mapi.MapiExceptionADPropertyError]: MapiExceptionADPropertyError: Unable to open message store.
(hr=0x80004005, ec=2418)
· Test-Mailflow works fine on server1 , when mailbox database X is ,mounted on server2
The Real Person!
The Real Person!
See my comment below:
https://www.practical365.com/exchange-server/create-exchange-mail-flow-latency-heat-map-powershell/#comment-13214