Finding Sent/Received per user per day and average message size

I need quite often to upgrade customers Exchange organization to newer version. Before I can start upgrade I need to figure out how many servers and what kind of hardware customer needs for new Exchange servers. Exchange Product Group released Excel spreadsheets to simplify finding hardware for new Exchange environment (you can find Exchange 2013 Server Role Requirements Calculator or Exchange 2010 Server Role Requirements Calculator at Exchange PG blog). Calculator is expecting 2 input values present for these calculations: sent/received item count per user per day, and average message size. Finding these values are not something you can explicitly get from system and usually we need to use some script which analyze message tracking log and calculates these values. I believe that most popular method is using MessageStats script created by Rob Campbell and blog article by Neil Johnson. Script will analyze lots of information and creates CSV file which you should import to Excel, remove some columns and add some formulas at the end of table to get sent/received count and average message size. If you are using often this script and later modifying CSV file then it doesn’t feel complicated. Although if you are using first time or not so often, then you usually using blog article and following carefully steps. Most of the time you usually spending just waiting until script is finished and for bigger companies (lots of severs and thousands of users) it might take loooong (hours, even days).

I get bored (I believe this is the right word) to modifying CSV file every time after script has finished. Usually my customers are just leaving this activity to me, just sending CSV files to me. And quite often I want to get sent/received items and average message size when I am already onsite and analyzing their Exchange environment but getting CSV file is problem as I don’t have Internet access at customer site. That’s why I was starting to create script which will give you sent/received item count and average message size automatically as output of script work and without additional work. After starting to create the script I changed little bit the scope and added some additional functionality the script can do. So currently Powershell script is ready and these values you are looking are displayed at the end of script. And as bonus the script is working more than twice faster compared with the MessageStat script.

Finding good name for script was quite challenging. I finally decided to name it as CalcMsgAverage.ps1. You can get syntax for script with command CalcMsgAverage.ps1 -Help:

You can also use CalsMsgAverage.ps1 -Examples command to get view some examples which cover some basic scenarios:

Some comments for several parameters in script.

First bundle for specifying timeframe: Period, StartTime and EndTime. Script will need at least one of these present. If there is none of timeframe parameters specified then Period is set to 1, EndTime is set script startup time and StartTime as 1 day back from EndTime (so it will analyze last 24 hours records). Most common usage might be to analyze last 30 days from script startup: CalcMsgAverage.ps1 30 (Period is positional parameter and you don’t need to specify it). If all three time parameters are present then Period will be ignored and calculated from StartTime and EndTime parameter. By the way – you can use fraction part with Period parameter, for example 1.5 as Period means one and half day or 36 hours. Please take a note that period is important to calculate average values. For example if you have server log files for 10 days only but you are specifying Period as 20 days, then even if you have data for 10 days, average will be calculated for 20 days (instead of dividing by 10, it will be divided by 20). It means smaller number compared actual value. Usually this might happen for new servers only where collecting message tracking information haven’t done for longer period.

You can also specify what servers to analyze (using Servers parameter). This could be useful if you want to analyze only few servers from bigger range. The opposite functional approach using SkipServers parameter which enables you skip certain servers from analyzing results (for example some servers might be down). For both parameters if there are more than one name then include text to parenthesis (single or double) and separate values by coma or semicolon. If you include both Servers and SkipServers parameters then SkipServers parameter will be ignored (why the hell you need specify servers and then skip them?).

There is one parameter I created targeted to Exchange 2013 only (it will make no difference for older Exchange versions). This parameter is SkipHealthMailboxes which makes script to skip all Exchange 2013 health messages from calculation and analyze activities. Usually the difference is very small and not so different from actual value. It might give some effect if you have Exchange 2013 installed for some period but no user mailboxes migrated to this server yet. So no sent/received mails for users but all traffic is only for health mailbox probe messages.

I did testing comparing CalcMsgAverage script by analyzing 30 days of data for about 700 user environment and then using exactly the same timeframe for MessageStats script.

First example using CalcMsgAverage with 30 days period, running 40 minutes 40 seconds.

Second example using CalcMsgAverage with 30 days (exactly the same start and end time) but using SkipHealthMailboxes parameter (MBX01 and MBX02 is Exchange 2013). Running time 40 minutes 6 seconds.

Third example using MessageStats with 30 days (exactly the same start and end time written inside to script). Running time 7300 seconds which is little more than 2 hours. It means CalcMsgAverage is more than twice faster compared to MessageStats (40 minutes versus 121 minutes).

I also found that there are some inconsistency between CalcMsgAverage and MessageStats. I did some tests to find out why it’s happening and found out that MessageStats is analyzing incorrectly under certain conditions (it will add e-mail size to calculation but don’t increase user count which will give back wrong statistical results).

Please let me know your feedback, also suggestions and bug report (I really hope there are none but you never know). You can download CalcMsgAverage script from TechNet Gallery here.

Comments (20)

  1. Anonymous says:

    Nice script! Is it in the TechNet Gallery too?

  2. Anonymous says:

    @Tee: I have seen similar error few months ago and the reason seems to be not updated .NET version. One option is definitely update .NET to 3.5.1 version, another option is to little bit change the lines 145 and 147 to make it work even not updated .NET
    (this is how I solved it last time). I try to find some time to provide update which should be solving this problem also.

  3. Anonymous says:


  4. Anonymous says:

    Now it is published to TechNet Gallery too

  5. Anonymous says:

    As mentioned in previous reply script has no option to calculate statistics for specific user. I’ll start working with next version at the end of February. Next version contains some small fixes, little better feedback processed and remaining servers count,
    and if user-based statistics is requested then probably this one also.

  6. Anonymous says:

    Usually this error happens if your custom list of servers contains no-transport capable server. It means for Exchange 2010 it have to be Hub Transport role installed on this server. For Exchange 2013 it requires Mailbox role installed.
    If you still see problems then send me offline e-mail and describe more detail level your problem.

  7. Anonymous says:

    Script is not checking what drive Exchange is installed. It is using only Exchange PS commands and .NET commands, nothing to do where Exchange binaries are.

  8. Anonymous says:

    There will be probably option to get averages for specific user in future release. Definitely no statistics based on storage group as this is Exchange 2007 which is already out of support. Another reason is that tracing logs don’t contain any information
    to which database e-mail is going. This is true also for Exchange 2010 and Exchange 2013.

  9. Itworkedinthelab says:


  10. Anonymous says:

    Pingback from @WinObs Tweeted Links for June 16, 2014 | Wiki

  11. goten tee says:

    When running the script inside an Exchange 2013 shell I get the following output:

    [PS] C:scripts>.CalcMsgAverage.ps1 -Servers "DC-Exchange"
    Cannot convert the "DC-EXCHANGE" value of type "System.String" to type "System.Collections.ArrayList".
    At C:scriptsCalcMsgAverage.ps1:145 char:1
    + $Exchange2013Transport = [System.Collections.ArrayList]($ExchangeServers | Where …
    + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    + CategoryInfo : InvalidArgument: (:) [], RuntimeException
    + FullyQualifiedErrorId : ConvertToFinalInvalidCastException

    Cannot convert the "DC-EXCHANGE" value of type "System.String" to type "System.Collections.ArrayList".
    At C:scriptsCalcMsgAverage.ps1:147 char:1
    + $TransportServers = [System.Collections.ArrayList]($ExchangeServers | Where {$_. …
    + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    + CategoryInfo : InvalidArgument: (:) [], RuntimeException
    + FullyQualifiedErrorId : ConvertToFinalInvalidCastException

    You cannot call a method on a null-valued expression.
    At C:scriptsCalcMsgAverage.ps1:171 char:13
    + If (-not $TransportServers.Contains($Server)) {
    + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    + CategoryInfo : InvalidOperation: (:) [], RuntimeException
    + FullyQualifiedErrorId : InvokeMethodOnNull

    Any help would be greatly appreciated.

  12. Chandrakant Neel says:

    Script is awesome but consecutively failing on few nodes with error “I am getting error “Server name ‘XXXX’ is not valid. Make sure there are no typing errors or the server has transport role or transport service available. “Immediate support much appreciated

  13. Chandrakant Neel says:

    Thanks Toomas for quick response. In our case those servers are having transport role installed but still failing with error which I have shared earlier. I have observed one thing, script is working on those servers only where we have installed exchange
    binaries on D drive but failing on those systems where we have binaries on c: drive. Not sure from where script is checking this information. Kindly check and pls support us.

  14. Jazeel says:

    Would you please help me to get the average mail size send/receive by specific user/storage group?
    Appreciate your prompt support.

  15. Jazeel says:

    Can we generate by user?

  16. Jazeel says:

    When you are expected to release the next version?

  17. Absolutlety brillaint, thanks v much Toomas

  18. lucindo_ says:

    Good day. I have tried to run the script in a server 2012 with exchange 2013 with the following error. can you assist?

    .CalcMsgAverage.ps1 30
    Get-ExchangeServer : The term 'Get-ExchangeServer' 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:UserstradminDesktopExchange ScriptsMsAvgCalcCalcMsgAverage.ps1:143 char:20
    + $ExchangeServers = Get-ExchangeServer | select Name, Fqdn, IsHubTransportServer, …
    + ~~~~~~~~~~~~~~~~~~
    + CategoryInfo : ObjectNotFound: (Get-ExchangeServer:String) [], CommandNotFoundException
    + FullyQualifiedErrorId : CommandNotFoundException

  19. Toomas Ruus says:

    @Thiago: did you started the script on Exchange Management Shell (EMS) or just in Powershell? Script requires Exchange commands which is not possible directly from Powershell and that’s why running it on EMS. I’ve noticed that even if you do Exchange Remote
    Powershell not all Exchange commands are giving the same output as running them from EMS. The error message you sent shows that script is not capable to understand Get-ExchangeServer PS command and that’s why I believe it is not started from EMS.

Skip to main content