Get-MailboxReport.ps1 – PowerShell Script to Generate Mailbox Reports

One of the Exchange Server administration tasks I perform almost every day is creating mailbox size reports. There are a few different reasons that I create these reports, such as planning a mailbox migration project, responding to a storage capacity alert for a particular database, or providing a specific team of people with a report of their mailbox sizes.

Now it is pretty easy to get the sizes for Exchange mailboxes and to handle the formatting of the Exchange 2010 mailbox statistics so that they are easier to perform calculations on, but it gets a bit boring running those commands day after day.

Even worse, after running the commands to create a CSV report I still had to open that in Excel, remove the unwanted details, use Excel formulas to convert the values from bytes to megabytes, sort them into order, and so on. Again not difficult, just boring after doing it hundreds of times.

So I created a PowerShell script, Get-MailboxReport.ps1, to do all of the heavy lifting for me, and I’m sharing that script with you here.

31477 downloads so far.
This script is available for download by Exchange Server Pro Insiders. Join here it’s free.

Let’s take a look at how the script works. Here is a video to demonstrate:

I’ve included help information within the script itself so you can use Get-Help to discover how to run the script.

[PS] C:\Scripts\demo>Get-Help .\Get-MailboxReport.ps1


    Get-MailboxReport.ps1 - Mailbox report generation script.

    C:\Scripts\demo\Get-MailboxReport.ps1 [-database ] []

    C:\Scripts\demo\Get-MailboxReport.ps1 [-file ] []

    C:\Scripts\demo\Get-MailboxReport.ps1 [-server ] []

    C:\Scripts\demo\Get-MailboxReport.ps1 [-mailbox ] []

    C:\Scripts\demo\Get-MailboxReport.ps1 [-all] []

    Generates a report of useful information for
    the specified server, database, mailbox or list of mailboxes.
    Use only one parameter at a time depending on the scope of
    your mailbox report.

    For more script details, a video demo, or to give feedback please go to:

    To see the examples, type: "get-help C:\Scripts\demo\Get-MailboxReport.ps1 -examples".
    For more information, type: "get-help C:\Scripts\demo\Get-MailboxReport.ps1 -detailed".
    For technical information, type: "get-help C:\Scripts\demo\Get-MailboxReport.ps1 -full".

Depending on which parameter you use the output will vary.

  • If you use the -mailbox parameter to query a single mailbox, then the output will appear in the console window. I don’t really see the need to output a single mailbox’s details to a CSV file.
  • If you use any of the other parameters, -server, -database, -file, or -all, the output will be written to a CSV file in the same folder you’re running the script from.
  • You can use the optional -filename parameter to specify your own output file name

Once you’ve generated the CSV report you can open it with Excel and begin to analyze the data.

31477 downloads so far.
This script is available for download by Exchange Server Pro Insiders. Join here it’s free.

Change Log:

  • 6/02/2012 – V1.0 – Initial version
  • 27/02/2012 – V1.1 - Improved recipient scope settings, exception handling, and custom file name parameter.
About Paul Cunningham

Paul is a Microsoft Exchange Server MVP and publisher of Exchange Server Pro. He also holds several Microsoft certifications including for Exchange Server 2007, 2010 and 2013. Find Paul on Twitter, LinkedIn or Google+, or get in touch for consulting/support engagements.


  1. Devang Patel says:

    This is Awsome. I tried it and works smoothly. Before using this scripte i used to get the results manually by just entering the commands every time.

    I have one query about the text file that we need to create for getting the results for particular users. which fileds should i enter in the text file.


    • Display name, alias, or UPN should work. Take your pick. I usually just use display name.

      • Yogish Acharya says:

        Hi Paul,

        I have one query on quota limit set as a default on those mailboxes where the actual mailbox quota limit value need to fetch from database. for example, If the MBProhibitSendReceive quota set on database is 1GB, mailboxes related to this database should show the report as 1GB ,in fact we are getting the report as unlimited. So i need a powershell command for the mailboxes, where it shows actual quota limit set on database along with other attributes of mailboxes. and one more thing on the same list, some mailboxes quota size not set as default value, it should fetch the exact value on same report. Hope you could understand my query. Please do the needful, would be a grateful to you. Thanks in advance

  2. Hi Paul,

    Can u make this script work with server parameter? So it can list all the mailboxes from the server at once.


  3. Script has had a major overhaul and re-release, so much so that I’m just going to call this new one V1.0 :-)

  4. Edward Walton says:

    question. is it possilbe to script a way to find all emails with attachments over 25meg.


  5. Hi Paul,

    That script very useful, very well documented as well. I’ll try to improve it adding if the user has mailbox default storage limits.

    Thanks for sharing!

  6. hi

    good work paul, thanks for sharing,

  7. Paul

    I have an issue where the powershel is preventing my from runnin gthe script. ” the file is not digitally signed” is the complaint from the PS!!

  8. Keep getting an error ….
    “Missing opening “(” after keyword ‘for’.
    At C:\Scripts\get-mailboxreport.ps1:48 char:5
    + For m <<<< ore script details, a video demo, or to give feedback please go to:

    Am I missing something?
    Exch 2007

    • Hi Josh, it is written for PowerShell v2.0. Try running:


      …to see which version you’ve got. If you’re on version1.0 you can try and edit the script to remove all that help info at the start, and see if that works, but I haven’t specifically tested it on v1.0 to check for any other issues.

  9. Excellent script! Thanks for the work and the updates. I know that this will be used much by myself and the consultants I work with.

    Thanks again

  10. Getting this error message.

    [PS] C:\temp\Exchange\PowerShell\other>.\Get-MailboxReport.ps1 -database MBX1VP\MbxDb-YNHH-002

    Security Warning
    Run only scripts that you trust. While scripts from the Internet can be useful, this script can potentially harm your
    computer. Do you want to run C:\temp\Exchange\PowerShell\other\Get-MailboxReport.ps1?
    [D] Do not run [R] Run once [S] Suspend [?] Help (default is “D”): R
    Cannot process argument transformation on parameter ‘Database’. Cannot convert value “MBX1VP\MbxDb-YNHH-002″ to type “M
    icrosoft.Exchange.Configuration.Tasks.DatabaseIdParameter”. Error: “‘MBX1VP\MbxDb-YNHH-002′ is not a valid value for th
    e identity.
    Parameter name: Identity”
    + CategoryInfo : InvalidData: (:) [Get-Mailbox], ParameterBindin…mationException
    + FullyQualifiedErrorId : ParameterArgumentTransformationError,Get-Mailbox

  11. Never mind. Got it now. Still getting this message:

    Security Warning
    Run only scripts that you trust. While scripts from the Internet can be useful, this script can potentially harm your
    computer. Do you want to run C:\temp\Exchange\PowerShell\other\Get-MailboxReport.ps1?
    [D] Do not run [R] Run once [S] Suspend [?] Help (default is “D”): R

    I ran Set-ExecutionPolicy Unrestricted

  12. Jeff Strubberg says:


    Great script! I removed a few of the output fields (we only have one mail server and one mail database, so those fields weren’t meaningful for us). At the moment I am trying to sort the resulting csv file via the script to put the mailboxes in order largest to smallest. Could use some help getting this to work.

    Once I’ve got that figured out, this script is going to save me a ton of time. I’ve got it running as a schedlued task on my exchange server and emailing me the resulting csv on the first of every month.

  13. starchaser says:

    I am trying to run this script using the -database or -file parameter and it’s generating a blank csv file. The csv file generated is of 0 bytes.

    • That will happen if no mailbox info could be retrieved.

      For -database make sure you’re supplying a value that would work if you ran “Get-Mailbox -database “.

      For -file try removing the -ignoredefaultscope switch from the script line

      “if($file) { $mailboxes = @(Get-Content $file | Get-Mailbox -resultsize unlimited -IgnoreDefaultScope) }”

    • I’ve added some script logic so that instead of creating a 0kb file it will instead show a warning that no mailboxes were found matching the criteria given.

  14. starchaser says:

    Well, I tested the -database parameter works with .\GetMailboxReport.ps1 -database ‘ServerName\StorageGroupName\DataabaseName’

    However, .\GetMailboxReport.ps1 -file does not work. I tried Display Name, Primary SMTP address, UPN but it doesn’t work. It creates a blank 9 byte csv file.

    • Ah yep, see comment above. Try removing -ignoredefaultscope from the line:

      “if($file) { $mailboxes = @(Get-Content $file | Get-Mailbox -resultsize unlimited -IgnoreDefaultScope) }”

      I’ll add it to my bug list.

  15. starchaser says:

    Fantastic! It worked. Great script.


  16. David Taig says:

    Hi Paul,

    Great report for Migrations. As I need the Alias to perform the migration, I have added this in the first column:

    $userObj | Add-Member NoteProperty -Name “Alias” -Value $mb.Alias

    I also added sort “Size (Mb)” -Desc

    I did run this on a combined DC and Exchange 2007 SP3 Server – Enabled and Expires is blank. OK on other Exchange 2007 SP3 Server, so seems issue having DC and Exchange 2007 together..

  17. Thanks again paul for an amazing time saver(and also teaches me powershell)
    i only had one issue when i ran it through 2010 ps(dont know if it matters) using -file
    i got cannot move something about distinguage name cannot be used or must be used:) when using -ignorescope
    so i removed the ignorescope for the file part of the script and it ran like a charmer:)
    Thanks again
    Much appreciated

    • Yep, little bug I need to work on there. If you have a multi-domain forest you’d just need to put your management shell session into viewentireforest $true mode to see all the mailboxes in the report.

      Or if you’re a single domain forest it doesn’t matter, script will work as you’ve modified it :-)

    • This bug should be fixed now in the latest version (1.1).

  18. Hello Paul,

    Thanks again för sharing your script. Works great, I just have a question… How can I do to find the right character in the csv file .. I m having in my exchange swedish names with those: å,ä,ö.

    Is it a parameter to add ?

  19. Christa Wilson says:

    Nice report. I’d like to put it into a scheduled task for a weekly/monthly report that’s emailed to me. I’m wondering how to call upon the output file as it will change each time it’s ran.

    • Hi Christa, probably two ways you could do that.

      1) Remove the file name randomization. So instead of

      $reportfile = “MailboxReport-$timestamp-$random.csv”

      have simply

      $reportfile = “MailboxReport.csv”

      2) The file name is stored as $reportfile, so if you’re adding email functionality to the script you can always reference the file name by that variable, no matter what the real name is.

    • I’ve added a -filename optional parameter to the latest version (1.1) for those who wish to specify the file name instead of the randomly generated ones (actually I use -filename almost every time I run it now :))

  20. I guess I am a retard because I can’t get it to run. I keep getting the following error:

    [PS] C:\Windows\system32>c:\scripts\get-Mailboxreport.ps1
    The term ‘c:\scripts\get-Mailboxreport.ps1′ is not recognized as the name of a cmdlet, function, script file…..

    What am I doing wrong? I am not an expert with PowerShell but this shouldn’t be this hard. thanks

    • Hi Tom,

      Navigate to the folder where you’ve saved the script file, then run it with:


      You’ll need to supply one of the parameters for which type of report you want to run. You can see the help info by running:

      Get-Help .\Get-MailboxReport.ps1

      Or watch the video above for a demonstration.

      Hope that helps.

  21. I had already tried it that way but I ran it again. See below. I get the same error. It doesn’t seem to matter how I run it. Can you help further? This is driving me nuts. I will watch the video as well.

    [PS] C:\scripts>.\Get-MailboxReport.ps1
    The term ‘.\Get-MailboxReport.ps1′ is not recognized as the name of a cmdlet, function, script file,…….


  22. Great script, but I am seeing something odd when I use the -server parameter. The number of mailbox objects listed in the EMC is 2498, but when I use the -server parameter it only processes about 1400 or so, not the full 2498. To get around that for now, I am using a generated user.txt file and using the -file parameter. Any ideas why the difference ?

  23. thz a lot fr the script, very useful

  24. FYI I wrote a similar in concept script to generate Exchange 2010 mailbox billing reports in Excel directly. While it is a slightly different focus than what you are doing (in that it grabs all customer mailboxes or specific OUs, not databases or servers), perhaps you could recycle the Execl logic in my script to dump your data directly into Excel spreadsheet where you have already pre-formatted the attributes the way you want (which we also had to do) and save yourself a step or two:

    I hope it helps.

  25. Shane Bryan says:

    Thanks for the great script Paul. I’ve removed a few of the objects I don’t need, and plan to schedule this to be exported to a SQL server so we can import the results into a database and report on mailbox growth per user.

    I’ve changed your script to remove the random number being added to the file name, but if you can give me some advice on how to alter the export location that would be fantastic as i’d like the file exported to a folder that will have everything in it xcopied to another location at set times.

    Eg: C:\ExchangeReportExport

    Cheers from Aus, and thanks again Shane.

    • Shane Bryan says:

      Oh worked it out…

      $reportfile = “C:\PSScripts\Copy\MailboxReport-$timestamp.csv”

      easy :-)

      • Yep, also I’ve added a -filename parameter to the latest version (1.1) just uploaded in the last few minutes if you wanted to grab that. It has a few other minor fixes as well.

  26. Shane Bryan says:

    thanks so much :)

  27. Simon Craner says:

    works great. What do i need to change the output file name to contain the server name it was run against?

  28. Carlos V says:

    Thank you for providing us this script, I run it fine from PS command but when I try to run it on a batch file it doesn’t fetch anything. Can you please help with the line to run it on a batch file?

    powershell.exe -noexit c:\Temp\Get-MailboxReport.ps1 -all

    I get
    Collecting mailbox list
    Collecting report data
    No mailboxes were found matching that criteria.

  29. Getting output below when running the scripts
    Collecting mailbox list
    Collecting report data
    No mailboxes were found matching that criteria.

  30. Carlos V says:

    It’s working now in the batch file, I just added the command to load Exchange Management Shell in the PS script.


  31. Hi Paul
    How can we use this script and add the User Mailbox Quota in , so that it also shows in the csv file

  32. I have added to following values to show the Storage quotas as well

    $userObj | Add-Member NoteProperty -Name “IssueWarningQuota” -Value $mb.IssueWarningQuota.Value.ToMB()
    $userObj | Add-Member NoteProperty -Name “ProhibitSendQuota” -Value $mb.ProhibitSendQuota.Value.ToMB()
    $userObj | Add-Member NoteProperty -Name “ProhibitSendReceiveQuota” -Value $mb.ProhibitSendReceiveQuota.Value.ToMB()

    • BR Thurr says:

      I have added these as well:

      $userObj | Add-Member NoteProperty -Name “Primary SMTP Address” -Value $mb.PrimarySMTPAddress
      $userObj | Add-Member NoteProperty -Name “Forwarding Address” -Value $mb.ForwardingAddress
      $userObj | Add-Member NoteProperty -Name “Hidden From Address Lists” -Value $mb.HiddenFromAddressListsEnabled

      Make sure that in your “Select=-Object” line (154 in the latest version), that you add these attributes into your select statement. For example:

      $stats = $mb | Get-MailboxStatistics | Select-Object TotalItemSize,TotalDeletedItemSize,ItemCount,LastLogonTime,LastLoggedOnUserAccount,HiddenFromAddressListsEnabled,ForwardingAddress,PrimarySMTPAddress

    • BKK-Mac says:

      Hi ShaunH,

      I have added those lines to get storage quota and if I run the script against 1 mailbox, I can see those values but when I run against a database, those values are missing from the export CSV file.

      I have also added the values of BR Thurr and they are present in the CSV

      Any idea?


      • @BKK-Mac

        did you get this solved eventually? I`m also having this issue with the script. Can only display it for one user but not for all in Mb.

        • The issue is the Value.ToMB() setting as when it encounters a mailbox which has no value set this is returned as “Unlimited” which can’t be converted to MB and it causes it to fail.

          I got round that by setting up a conditional statement to test if the quota returns a value and attached to a variable and then calling that variable

          $ProhibitSendReceiveQuota = if($mb.ProhibitSendReceiveQuota.value){$mb.ProhibitSendReceiveQuota.value.ToMB()} else {“unlimited”}
          $ProhibitSendQuota = if($mb.ProhibitSendQuota.value) {$mb.ProhibitSendQuota.value.ToMB()} else {“unlimited”}
          $IssueWarningQuota = if($mb.IssueWarningQuota.value) {$mb.IssueWarningQuota.value.ToMB()} else {“unlimited”}

          $userObj | Add-Member NoteProperty -Name “MBIssueWarning” -Value $IssueWarningQuota
          $userObj | Add-Member NoteProperty -Name “MBProhibitSend” -Value $ProhibitSendQuota
          $userObj | Add-Member NoteProperty -Name “MBProhibitSendReceive” -Value $ProhibitSendReceiveQuota

  33. This could be helpful. Is it possible to have the script run against just “room mailboxes” ?

    • BR Thurr says:


      Go to line 75, and add this line underneath:
      [Parameter(ParameterSetName='room')] [switch]$room,
      Go to line 139, and add this underneath:
      if($room) { $mailboxes = @(Get-Mailbox $mailbox -RecipientTypeDetails RoomMailbox ) }

      Save it and run it with the -room parameter. I tested this and it works.

      • Thanks BR – put doesnt the switch (-mailbox, -database -server, etc) specify where to pull the mailbox information from? Therefore using ‘-room’ switch it would have to be followed by the actual room ? I am trying to pull all rooms from a database or server.

        Unless I am missing something. Thanks again !

    • The mailbox type us already included in the report, so you could just run it without modifications and use Excel to filter the data afterwards.

      Another way would be to generate the list of room mailboxes into a text file and use the -file parameter when running the script.

      Or, yet another way, make a copy of the script and call it say “Get-RoomMailboxReport.ps1″ and as BR suggests above change all the Get-Mailbox commands to add the “-RecipientTypeDetails RoomMailbox” parameter.

  34. If you are getting the “No mailboxes were found matching that criteria.” message, make sure you are running the script in the Exchange Management Shell, this fixed it for me on Exchange 2007 and 2010.

  35. Peter Watson says:

    Many thanks for this script, saved me many hours and lots of fingernails!

  36. Rajkumar says:

    Hi Paul,

    I have added one Ps1 file which is calling\having one function. I’m able to run the function( ex: get-Mail….). All is well.
    Can you help me to know, how to remove the Ps1 file and the function Get-Mail… in my exchange server environment. I don’t want others to run this shell command, whenever i need the details, i ll run the script and get the data.
    Help me to remove the function and PS1 file in safe manner

  37. Kickass script Paul! Thanks for sharing.

  38. Michael Boback says:

    Awesome script. Can you add functionality to show whether Exchange Archiving is enabled and the Total Size and Total Items in the archive? So far it seems the best way to check if archiving is enabled is to use Get-Mailbox | Select-Object ArchiveDatabase. Someone please correct me if I am wrong though. A value of null means archiving is disabled. I added some lines to the script and this worked.

    When I tried to use Get-MailboxStatistics -Archive | Select-Object TotalItemSize,ItemCount this seems to work, but if the mailbox doesn’t have archiving enabled it throws out an error. I’m new to powershell scripting so I don’t know the best way to add this to the script so it’s handled gracefully.


  39. I do not normally post comments on any website, but I just felt I had to this time!
    Thank you – you have made my job about a milliontimes easier with this script…and such a simple thing it is too when you delve into it.

    Why I had not thought of doing this sort of thing myself before I will never guess…but today, yes today Paul, you have made a new friend for life!

    Once again, thank you mate!

  40. I am not familiar with Exchange. When I run the script I get these error:
    Can you help me find the missing links?
    PS C:\Mailboxes> .\Get-MailboxReport.ps1 -database ‘PWRExchange\PWRE_MBX_2-2′
    Get-PSSnapin : No Windows PowerShell snap-ins matching the pattern ‘Microsoft.E
    xchange.Management.PowerShell.Admin’ were found. Check the pattern and then try
    the command again.
    At C:\Mailboxes\Get-MailboxReport.ps1:89 char:27
    + $2007snapin = Get-PSSnapin <<<< -Name Microsoft.Exchange.Management.PowerShe
    + CategoryInfo : InvalidArgument: (Microsoft.Excha…owerShell.Ad
    min:String) [Get-PSSnapin], PSArgumentException
    + FullyQualifiedErrorId : NoPSSnapInsFound,Microsoft.PowerShell.Commands.G

    Get-PSSnapin : No Windows PowerShell snap-ins matching the pattern 'Microsoft.E
    xchange.Management.PowerShell.E2010' were found. Check the pattern and then try
    the command again.
    At C:\Mailboxes\Get-MailboxReport.ps1:96 char:28
    + $2010snapin = Get-PSSnapin <<<< -Name Microsoft.Exchange.Management.Powe
    + CategoryInfo : InvalidArgument: (Microsoft.Excha…owerShell.E2
    010:String) [Get-PSSnapin], PSArgumentException
    + FullyQualifiedErrorId : NoPSSnapInsFound,Microsoft.PowerShell.Commands.G

    Import-Module : The specified module 'ActiveDirectory' was not loaded because n
    o valid module file was found in any module directory.
    At C:\Mailboxes\Get-MailboxReport.ps1:124 char:14
    + Import-Module <<<< ActiveDirectory
    + CategoryInfo : ResourceUnavailable: (ActiveDirectory:String) [I

    Please Help!

  41. @Kalvin – it looks like you are running that script from within a regular PowerShell console. You either need to load the Exchange snap-ins into that console, or instead run the Exchange Management Shell version of the PowerShell console (preferably IMHO). The Exchange Management Shell is installed on any computer you install the Exchange Administration tools on.
    Happy hunting!

    • I am actually running it remotely and I am not in Exchange admin group. I have been given readonly access. Does that suffice or I need to do more?

  42. Kalvin, as HotFix says, you will only be able to run this script either from with in the Exchange Management Shell version of the PowerShell console on an exchange server or from a computer that has the Exchange Administration tools installed onto it.

    You can use the following command to load the Exchange Management tools in a script though, if that helps or you have problems fiding the Exchange console.

    function Load_Exchange_Tools {
    if (-not (Get-pssnapin | ? {$ -like ‘Microsoft.Exchange.Management.PowerShell.e2010′})) {
    Add-PSSnapin Microsoft.Exchange.Management.PowerShell.e2010

    If you don’t have access to the tools, or your permissions don’t allow access to Exchange, you won’t be able to run scripts like this though.

    Rgds, Shane.

  43. Bjarni Kristjansson says:

    This is brilliant, thanks
    e.s. I changed the export command to $report | Export-Csv -encoding ‘unicode’ -Path $reportfile -NoTypeInformation – because here in Iceland we have alot of strange Icelandic characters like æ á þ ð ó and so on!
    Nice work.
    best regards, Bjarni

  44. It seems that code
    #This is an aged mailbox, so we want some extra details about the account
    $user = Get-User $mb
    isn’t exact
    better is
    $user = Get-User $mb.Alias

  45. Animesh says:

    Have you ever considered using a txt or csv file as input? I am currently evaluating Petri’s script for the same and can’t specify an input file. After analyzing your script, I find my problem as it is. Can you suggest me a way where I can specify a TXT or CSV file as input for users?


    • The script has a -file parameter for using a txt file as the list of users to generate the report for. The txt file should contain the list of mailbox users in a format that would work with Get-Mailbox, so that could be alias, email address, display name, etc.

  46. Hi thank u a lot for your wonderfull script.
    I need to bublic it to may intranet site. How convert it in html formatted tablereport?

    Could u modify the script to add html export?

    I’m trying to modify it but I’m not able.

    Thank you very much.


  47. Shane Bryan says:

    David, do you have SQL reporting services available to you?

    We take the data from this script and it gets imported into a database for SQL reporting. It allows me to see weekly growth on mailboxes by department and user. I totally recommend that if you have the resources available to you. Perhaps that might be more useful than simply dumping it into a html file, using a database and reporting services will let you track growth, find the heaviest mail users – and if your company is so inclined, charge accordingly.

    Before I found this script we were going to spend a great deal of money on a reporting system that went through the Exchange server logs. This script coupled with SQL reporting has pretty negated that.

    Anyhoo, there IS a ConvertTO-HTML option you can use with PowerShell, this link may help.

    • Hi Shane,

      how is this done ? I am quite interested in doing this. Could you or any one else shed some more light on it ?


      • Shane Bryan says:

        Hi Ray. I use the script that Paul kindly created with just a couple of slight modifications. My copy of it is here;

        One change was the folder where it dumps the csv file. The other change was appending the date to the filename of the csv file to create a history. I take no credit for this, from memory Paul helped me work that out also :-)

        There is a scheduled task on our Exchange server that runs this script once a week. Another scheduled task then robocopies the csv file to a SQL server that’s running Reporting Services. We then convert the .csv file to a .xls file, cleaning some of the data up. This excel file is then fed into the reporting database and then displays in the report when that is run. I’d past an export of that, but there’s corporate information in it so here’s a snippet of it, with corporate info blurred out.

        The report can be filtered by date, department etc so the majority of the work here was in the quality of the report created by our apps\dev person.

        It also drops down to show the users from each department and the size of their mailbox on those dates. It’s shows growth, but also shows when someones doing a mass delete in their mailbox (perhaps a pending resignation etc, so we make a note of this in case we have to restore it from tape at some point).

        So unfortunately my ability to help further is hindered by the fact that the majority of the awesomeness was done by our awesome report writer. They take the data dump from this file and turn it into something useful :-)

    • Thanx a lot Shane.

      • CRAZY IT guy says:

        Hi Shane,

        Can you please provide the code to import excel file to SQL reporting DB server

      • Shane Bryan says:

        Hi CRAZY IT guy. It’s a standard INSERT

        First we edit the spreadsheet a bit by changing the date from 020712 to 02/07/2012 which is done manually, then our code to import it is;

        INSERT INTO [ExchangeReporting].[dbo].[MailboxReport]

        select *

        from [ExchangeReporting].[dbo].[MailboxReport-070512]

        Obviously things will change for your environment such as the database name etc, also the file name is changed for each import as well. I hope that helps.

  48. Hi Bryan, thank you for your answer.
    I do not have a sql database but only a intranet webs erver where to publish the html report.
    I saw the codee like this:

    $style = “BODY{font-family: Arial; font-size: 10pt;}”
    $style = $style + “TABLE{border: 1px solid black; border-collapse: collapse;}”
    $style = $style + “TH{border: 1px solid black; background: #dddddd; padding: 5px; }”
    $style = $style + “TD{border: 1px solid black; padding: 5px; }”
    $style = $style + “”
    $message.Body = Get-ExchangeServer | Select-Object Name,ServerRole | ConvertTo-Html -Head $style

    Where can i put this code in your script to have the csv to html report file?

    I tried to insert in the following part of your script code but but I did not get the html table file:

    $reportcount = $report.count

    if ($reportcount -eq 0)
    Write-Host -ForegroundColor Yellow “No mailboxes were found matching that criteria.”
    #Output single mailbox report to console, otherwise output to CSV file
    if ($mailbox)
    $report | Format-List
    $report | Export-Csv -Path $reportfile -NoTypeInformation ???–> in this part?
    Write-Host -ForegroundColor White “Report written to $reportfile in current path.”
    Get-Item $reportfile ?? or in this part?

    Thank you so much for you help.


  49. Jon Schlatter says:

    Thank you, this script has been very helpful! I do have one question that on an issue I see when I use it.

    Each time I run it I see a number of errors saying the following. Please note the

    The operation could’nt be performed because object ” couldn’t be found on ”.
    + CategoryInfo :NotSpecified: (:) [Get-User], ManagementObjectNotFoundException
    +FullyQualifiedErrorID: : ,Microsoft.Exchange.Management.RecipentTasks.GetUser

    This happens to users that are in one specific domain (which I can query with no issues in AD Management). Would anyone have any ideas on what I can do to resolve this?

    • Jon Schlatter says:

      Please disregard my previous post. I found the answer to my issue only moments later. I corrected the recipent scope and all is fine.

  50. Thanks for your help by providing this Scrip, However I have tried to us is from ( Exchange powershell and Windows Poershell ) and while trying to import it there is an error message :

    [PS] C:\Scripts>import-module .\Get-Mailboxreport.ps1
    Collecting mailbox list
    Collecting report data
    No mailboxes were found matching that criteria.


    • Hi Aziz, this is a script to run, not a module to import. Please review the article above again, read the built-in help for the script, or watch the video. They all demonstrate how to run the script.

  51. Excellent script, thanks for sharing!

    Works like a charm. One question though. How did you get excel to sort the csv file automatically?


    Hi Paul,

    I want to be run powershell command for Send As permissions in exchange 2010 ….which command should be used normally I am giving manually in exchange 2010 console..can you post Send as permissions command and if you possible share all the basic commands etc..add permissions.. DLG Creation .. and RMB Creations

  53. Shane Bryan says:

    Hi Paul. I notice in the script that the variable $timestamp is used in 2 places?

    $timestamp = Get-Date -UFormat %dd%mm%yy
    $reportfile = “C:\PSScripts\Copy\MailboxReport-$timestamp.csv”

    this places the timestamp on the file name (which is invaluable)

    and also;

    $userObj | Add-Member NoteProperty -Name “Date” -Value $timestamp

    places the time stamp into the spreadsheet data itself, next to the user name, dept, mailbox size etc.

    in the csv file, the date is displayed as 060712 (when I run it today).

    is it possible, to have the date (in the data, not necessarily the file name – as it won’t like slashes) be in the 06/07/2012 format?

    that might require the creation of a second timestamp variable though just for the date inside the csv file?

    if i change the $timestamp variable to;

    $timestamp = Get-Date -UFormat %dd%mm%yy

    the date on the file, and in the data gets written as; 06d07m12y

    I don’t expect you to solve the worlds problems for us, but is there a link or something you can share that will educate me on how to achieve the date formatting I need?

    Cheers, Shane.

  54. Shane Bryan says:

    Possibly :p It was a while back now. Apologies if I’ve turned your beautiful script into some bastard child :-p

    • Yeah I just don’t see it in the original. Modifications are fine, people should certainly feel free to tweak these scripts to suit their needs.

      So what is the goal of that extra property you’re trying to set? Is it so your SQL import knows which day the stats apply to?

      • Shane Bryan says:

        Hi Paul, yep at present I manually edit the csv file and replace all the 020712 date data with 02/07/2012 manually.

        it doesn’t take long, but the more i can automate the better :-)

      • Try this:

        $a = Get-Date -f d

        $userObj | Add-Member NoteProperty -Name “Date” -Value $a

        You can use any variable name you want I’m just $a for the sake of example.

  55. Shane Bryan says:

    Thank you Paul, that did the trick.

    I now have 2 variables.

    $filetimestamp = Get-Date -UFormat %d%m%y
    $datatimestamp = Get-Date -f d

    $filetimestamp is appended to the csv file when it’s written.
    $datatimestamp is used in [$userObj | Add-Member NoteProperty -Name "Date" -Value $datatimestamp] and displays the date as “6/07/2012″ inside the csv file

    Perfect! Thank you so much :-)

  56. Hi Paul,

    Great Stuff, is it possible to alter the script to display total mailbox size per user, currently it only displays, Item Size and deleted item size.


  57. IntroToLogic says:

    The script is awesome Sir and so are you of having written it!

  58. Hi Paul,
    I ran your script, it worked fine, thank you. I summed the Mailbox and deleted items they added up to 112Gb, but my two edb files are 86Gb and 45Gb, any idea wat is using the extra 20Gb? Db maintenace runs nightly.

  59. Hi Paul,

    Thanks Exactly what i was looking for, Is it possible for you to add the option to email the report.


  60. narasimha says:

    Can i run ..powershell command as the following requirements.
    1 ) DLG Creation
    2 ) RMB Creation
    3 ) moving mail box from one location to another location ( Database )
    4 ) how to view log if we applied succesfully p-shell commands

  61. Paul when i run the script I get:

    WARNING: Error initializing default drive: ‘Unable to find a default server with Active Directory Web Services

    but then it looks like it runs…



  62. Vivek Malik says:

    Hi Paul,
    How can i get output of EmployeeType and EmailAddresses in this script.


  63. very nice Script, Works perfectly for me with limited count.

    I have 500 mailbox, but i am getting only 139.

    .\Get-MailboxReport.ps1 -server Exmbx02 -filename e:\allmailbox.csv

    Please advise to get the full mailbox report.


  64. By executing the following command it is giving the full report,
    .\Get-MailboxReport.ps1 -full -filename e:\allmailbox.csv


  65. Nice script. But i have a question, could you advise on how i can generate a report that will include the “date” a mailbox is disbled. In otherwords, the disabled date for all disabled mailboxes.

    Thank in anticipation.

    • Do you already know how to retrieve the disabled date for a mailbox, and just want to know how to incorporate that into the script? Or are you also asking how/if its possible to retrieve the disabled date itself?

  66. Peter Davidse says:

    I am in Norway and the DisplayName contains ØÆÅ characters that are not in the generated reports, there they are substituted by a questionmark.
    Do you have a fix for that?

    • Hi Peter, someone else encountered the same problem and fixed it by adding the -encoding switch to the Export-CSV command towards the end of the script


      Export-Csv -encoding ‘unicode’

  67. Just wanted to drop a note of thanks for this script. I’ve been cobbling together a couple different reports to get me (and my supervisors) what we need. That was excellent. Cheers!

  68. Dont suppose you could give us a ZIP file of this script. We dont allow direct internet downloads of PS1 extentions.

  69. how can you sort the office, department and Total item size in the script?

  70. Peter Davidse says:

    I have an issue with the saved report.
    The first characters of the file are not “normal” characters.
    When using the report in Linux the file is being identified as a assembler file, not a text file.
    How can i fix this in the report generated instead of writing a workaround in my scripting language on the linux machine?

    Cheers, Peter

  71. Excellent One.

    how to get mailbox details which includes the Servername, databasename, username – ,maybe display name etc.

    I gave the command as follow.

    get-mailbox -database dbname -server servername. But getting ambigous error. Can you please help me out in this.

  72. Paul,

    Thanks for the great script. I modified the Total Item Size and Deleted Item Size ToGB() because of the size of the mailboxes I am dealing with. I was wondering how I could format the values to 2 decimal place ex 9.65 right now it is displayed as 9. I tried figuring this out on my own but I am a powershell noob.

    Thank you

  73. Is it possible to get this script to report on mailboxe sizes based on the Office the person(s) are located in?

    • Anything is possible with PowerShell mate ;-)

      I would encourage you to look at the script code. Look at how the parameters are defined. Look at how those parameters correspond with the Get-Mailbox commands. You should be able to quickly see how to add that functionality you want.

  74. Hei Paul,

    Is there a way to suppress the first row?
    Aka, only having in data in the file and not the property name on the first line.


  75. Paul

    Many thanks, your video was greatly helpful in understanding teh script’s functionality

  76. Rolando Rodriguez says:


    I’m trying to run the script, however my databases have users from 3 seperate child domains. The report runs through for the local domain where the Exchange servers are hosted, but throws errors about not being found on the Domain Controller. I have a similar issue when I have to do exports and actually define the DC for the other child domain to pull an export. Any way this can be addressed in the script?

    • At about line 130 in the script is the series of Get-Mailbox commands for the various all/server/database scenarios. You can modify those lines to specify a DC if you need to.

      Interesting that you’re having that problem at all. The script is designed to ignore default scope and search the entire forest, so it should find any mailbox regardless of child domains.

      • Rolando Rodriguez says:

        Once it ran against the whole Server, it DID pull me back the info for the mailbox size and item count, but it didn’t pull back the AD info for the mailbox except mailbox user name. At the end, it did what I really needed, so THANK YOU!

  77. The script is perfect the only thing that would make it even better for me is to include the following: IssueWarningQuota, ProhibitSendQuota, ProhibitSendReceiveQuota. Any chance you could do it?

  78. Hey Paul. Great script outside of a couple minor suggestions.

    If the script requires a specific version of PowerShell; include the following:

    #requires -version 2
    write-host “Can only run on v2.”

    Also, it may be a better choice to use, “Set-ExecutionPolicy RemoteSigned” instead of “Set-ExecutionPolicy Unrestricted”


  79. Great Script, i love it…..

    I am new in Powershell World.

    But how can change the Field Separator from “,” to “;”.

  80. Hi Paul!
    Thanx for sharing a script. One question. Is there a solution to add another value for get-mailbox with prohibitsendquota option. It would be usefull to get that info with all this usefull info.


  81. This is really handy. Thanks!

  82. To setup a monthly mailbox report just create a cmd batch file with the following command line in it, then set it as a task on the exchange server to run each month:

    C:\Windows\System32\WindowsPowerShell\v1.0\powershell.exe -command “. ‘C:\Program Files\Microsoft\Exchange Server\V14\bin\RemoteExchange.ps1′; Connect-ExchangeServer -auto | “C:\scripts\Get-MailboxReportMin.ps1 -all

    All the Beast Matt

  83. Thank you much and great work as always. Anyone know a way to add the Sent Items to the report? TotalSentItemSize to the Select-Object line and $userObj | Add-Member NoteProperty -Name “Sent Item Size (Mb)” -Value $stats.TotalSentItemSize.Value.ToMB() to the PS object. The script runs fine but does not output the Sent Items value.



  84. I have customers who have multiple databases for their mailbox. Is there a way to alter the -database paremeter to analyze all databases that begin with a specific set of characters?

    • I think I’ve found a way to resolve my issue. I added these lines in the appropriate places in the script:

      [Parameter(ParameterSetName='CustomAttribute1')] [String]$CustomAttribute1,

      if($CustomAttribute1){ $mailboxes = @(Get-Mailbox -Resultsize Unlimited | where {$_.CustomAttribute1 -eq $CustomAttribute1} ) }

      This allows me to report on a subset of my users regardless of what database their mailbox is in. It does take a while to gather the matching users before processing but if I schedule this and other variations to run at night it should not put a crunch on the server. I already run nightly scripts to set the proper value for CustomAttribute1 for users.

      This is a really nice script that is well documented and I truly appreciate it.

  85. Hey,

    Great script. I am trying to figure out how to get one more field added, all SMTP addresses (aliases) for all users. How can I accomplish this.

    I typically do the following:Get-Mailbox | Select DisplayName, Alias,PrimarySMTPAddress, @{Name=’EmailAddresses’;Expression={[string]::join(“;”, ($_.EmailAddresses))}}

    I am not sure how to integrate that here.

    Thanks for the help!

    • At about line 185 add these lines:

      $emailaddresses = [string]::Join(“;”,($mb.EmailAddresses))
      $userObj | Add-Member NoteProperty -Name “SMTP Addresses” -Value $emailaddresses

  86. John Panicci says:

    Love the script…Is it possible to add Online Archive MB as a column? I’d like to determine the size of each Archive MB as well.

  87. Another Paul says:

    Getting her late to the party but a very awesome script! Great dialog in the thread as well for situation-specific needs!


  88. Great information on all your posts.
    I’m getting this error:
    WARNING: Error initializing default drive: ‘Unable to find a default server with Active Directory Web Services running.’.

  89. Oleg Tarasov says:

    Hi Paul,

    I have modified your script to give information on online Archive if one is enabled. Insert my code in $userobj section:

    $userObj | Add-Member NoteProperty -Name “Database” -Value $mb.Database
    #========Online Archive code================
    if ($mb.ArchiveDatabase)
    $astats=$mb | Get-MailboxStatistics -Archive
    $userObj | Add-Member NoteProperty -Name “Archive Item Size (Mb)” -Value $astats.TotalItemSize.Value.ToMB()
    $userObj | Add-Member NoteProperty -Name “Archive Deleted Item Size (Mb)” -Value $astats.TotalDeletedItemSize.Value.ToMB()
    $userObj | Add-Member NoteProperty -Name “Archive Items” -Value $astats.ItemCount
    $userObj | Add-Member NoteProperty -Name “Archive Server” -Value $astats.ServerName
    $userObj | Add-Member NoteProperty -Name “Archive Database” -Value $astats.Database
    } else {
    $userObj | Add-Member NoteProperty -Name “Archive Item Size (Mb)” -Value “”
    $userObj | Add-Member NoteProperty -Name “Archive Deleted Item Size (Mb)” -Value “”
    $userObj | Add-Member NoteProperty -Name “Archive Items” -Value “”
    $userObj | Add-Member NoteProperty -Name “Archive Server” -Value “”
    $userObj | Add-Member NoteProperty -Name “Archive Database” -Value “”
    #=====Online Archive code ends==================

    Also to support non-latin characters in your report and to be able to open straight with MS Excel change your export command to
    #========New export code=================
    $report | Export-Csv -Path $reportfile -NoTypeInformation -delimiter “;” -encoding “utf8″
    #========New export code end=================

  90. Had some trouble getting this to work. When you typed Get-M it autocompleted the rest for you, It did not do this for me, I tried typing out the whole command but kept getting an error that it could not find the script. I had to type out


    with the .\ in front before it would run. spent about 10mins before I figured that out…… Sure was much easier when you could open exchange 2003 and it told you how big the mailboxes where in a GUI.

    Good article though, thanks for the help.

  91. Hi Paul,

    Great script and have been using it for a couple years.

    Over the past couple days I have been getting the following error;

    Parameter cannot be resolved using the specified named parameters. At line:1 char:24

    Any ideas?


    • Have you modified the script or upgraded your version of PowerShell or something like that?

      Note also that some combinations of parameters can’t be used. Eg, you can’t use -Server and -Database together.

      • thanks for the quick reply.

        it ended up being UAC settings set too high.


        • Shane Bryan says:

          I’m getting this same error now as well.

          No updates on the mail server. No PowerShell upgrades but when I try and run it, I get;

          [PS] C:\psscripts>.\Get-MailboxReport.ps1
          C:\psscripts\Get-MailboxReport.ps1 : Parameter set cannot be resolved using the specified named parameters.
          At line:1 char:24
          + .\Get-MailboxReport.ps1 <<<<
          + CategoryInfo : InvalidArgument: (:) [Get-MailboxReport.ps1], ParameterBindingException
          + FullyQualifiedErrorId : AmbiguousParameterSet,Get-MailboxReport.ps1

        • You need to specify at least one parameter, -all, -server, -database, etc.

  92. How can i get the first name & email address of the users in the csv file?

  93. This script is great, a real time saver. I do have one question. We have 2 MB servers that are in a DAG. When I run against one I only get about 1/4 of the mailboxes returned. I know they’re all on both as we flip back and forth on mount points when we need to to perform maintenance (and the DB sizes are the same on both). Any idea why only one would return full results and the other incomplete?


    • The -Server parameter for the script isn’t really suited to DAGs. That is probably because when I first wrote it there were no DAGs in the environment I was working in.

      The ServerName on a mailbox that is hosted on a DAG is misleading. I believe it gets stamped with the server name that the database was active on at the time the mailbox was created, but doesn’t update as active databases switchover.

  94. Shane Bryan says:

    thanks Paul. what happened is i have a few scripts set to run automatically via task scheduler, i inadvertently deleted the task that run this one – which had all the parameters so it would run as intended.

    i was trying to run it manually, without those – sorry about that :-)

    Cheers Shane.

  95. Evan Barrett says:

    Hi Paul.

    First off, GREAT script!

    Is there a way to break down the stats by date range per mailbox? Example:
    Items 0-15 days, Size 0-15 days, Items 16-30 days, Size 16-30 days, etc.?

  96. Can the script be modified to include the active directory distinguished name (ID and container) ?

  97. Todd Nelson says:

    I LOVE THIS SCRIPT! I’ve been using it for a while and it helps me to identify “dead” mailboxes, their sizes, etc. However, I recently ran into an issue that I am unable to figure out.

    If I run the script against my lab environment (or most any other for that matter) with Exchange 2010 SP3, I receive information for all of the headers…

    “DisplayName”,”Title”,”Department”,”Office”,”Enabled”,”Expires”,”Last Mailbox Logon”,”Last Logon By”,”Item Size (KB)”,”Deleted Item Size (KB)”,”Items”,”Type”,”Server”,”Database”

    But, I ran into a situation where two of the headers do not show in the report. And these headers (and info) are quite important to determine our migration strategy. The two headers that do not show are…

    “Item Size (KB)”,”Deleted Item Size (KB)”

    I am running the same command and the same switches (using server name) but the results are different in this particular environment.

    Paul, any ideas why this might be occurring?


  98. I’ve been successful a few months back in manually running your excellent script but tried again today and nothing happens. No errors but no CSV files appear. Command line looks like this:
    PS C:\scripts>”.\get-mailboxreport -all” or “.\get-mailboxreport” are accepted without any feedback.
    I am running this on the active mailbox server against a DAG in Exchange 2010. I must be missing something really simple! Advice?

    • Todd Nelson says:


      Does the account you are running the script with a member of the “Organization Management” group? I don’t feel the account needs Enterprise Admins membership but may since the script seems to query AD.


      • My account is a domain admin and a member of the Exchange Organization Administrators. I can try adding myself to the Organization Management group to see if that makes any difference. Will update in a few. Thank you.

  99. Todd,

    No difference. Here is an example of what I see in the EMS – the command seems to simply echo back but no CSV files or even errors or additional info is generated:
    PS C:\scripts> “.\get-mailboxdatabase -all”
    .\get-mailboxdatabase -all
    PS C:\scripts>

    • Typo – please excuse me. Here is the actual text from the screen ….

      PS C:\scripts> “.\get-mailboxreport -all”
      .\get-mailboxreport -all
      PS C:\scripts>


    • Todd Nelson says:

      One thing that I see is very curious. The name of the script referred to in this thread is “Get-MailboxReport.ps1″. Therefore, the command being run should be “.\get-mailboxreport -all”. So, I feel this is probably a typo.

      If it is still not running for you, I cannot think of anything else but to make certain the file is unblocked from running and that the report output is being sent to a folder that isn’t set to read-only.

      I am running Exchange 2010 SP3 hosted on WS2008R2SP1 with PowerShell 2.0.

      When I run the command, this is what I see…

      [PS] C:\Tools\Get-MailboxReport>.\Get-MailboxReport -all
      WARNING: Active Directory server settings remained unchanged.
      Collecting mailbox list
      Collecting report data
      WARNING: The user hasn’t logged on to mailbox ‘red.local/Users/DiscoverySearchMailbox {D919BA05-46A6-415f-80AD-7E09334BB852}’
      (’5631bcc1-7f67-4600-9fcb-82e652b92d2f’), so there is no data to return. After the user logs on, this warning will no longer appear.
      Report written to MailboxReport-20130509-1346-1rFbV8.csv in current path.

      Directory: C:\Tools\Get-MailboxReport

      Mode LastWriteTime Length Name
      —- ————- —— —-
      -a— 5/9/2013 1:46 PM 2594 MailboxReport-20130509-1346-1rFbV8.csv

      [PS] C:\Tools\Get-MailboxReport>

    • Todd Nelson says:

      Another thing I could recommend is to download the script again but to a new/different folder on your mailbox server and try to run again.

      • Todd,
        Thank you very much for all of your replies. Yes, there was a typo that you picked up. I’ve tried running:

        PS C:\> cd scripts
        PS C:\scripts> .\get-mailboxreport -all
        Collecting mailbox list
        Collecting report data
        No mailboxes were found matching that criteria.

        And tried running:

        PS C:\scripts> “.\get-mailboxreport -all”
        .\get-mailboxreport -all

        And you see the results. Tried another download to another directory with the same results. Permissions are all fine. I am running Exchange 2010 SP1 rollup 8 on Windows Server 2008 R2 Datacenter with SP1 and powershell V1.

        Here’s what I see after a fresh download to the C:\Tools directory (newly created directory with permissions rechecked):

        PS C:\tools> get-executionpolicy
        PS C:\tools> .\get-mailboxreport -all

        Security warning
        Run only scripts that you trust. While scripts from the internet can be useful, this script can potentially harm your
        computer. Do you want to run C:\tools\Get-MailboxReport.ps1?
        [D] Do not run [R] Run once [S] Suspend [?] Help (default is “D”): R
        Collecting mailbox list
        Collecting report data
        No mailboxes were found matching that criteria.

        Interesting. Different info on the screen this time though.

        Database names in the DAG are DAGDB1 and DAGDB2. Calling them in the -database variable doesn’t change anything either.

        • You need to run it in the Exchange Management Shell or at least a PowerShell window where you’ve loaded the Exchange snapin.

          If you just open plain PowerShell and run it then you get no results, as you’re seeing.

          The next version of the script will account for that and give a more useful error if the snapin can’t be loaded.

  100. Paul, that was exactly the problem I was having. I was opening the Exchange Management Shell and then typing powershell to bring up the PS> prompt that I was seeing in the video. Running it strictly from the EMS works perfectly.
    Todd and Paul, thanks again for all your help. Great stuff and great script!

  101. BLeonard says:

    Thanks for this script Paul. It works very well, and is a great foundation for learning more PS Exchange scripting techniques.

  102. Jim Zaino says:

    I have a question the spreadsheet that is created with the -all parameter. I am being asked about the items column. What do the numbers in that column relate too.



  103. Sachin Kumar Singh says:

    Hi Paul,

    Thanks a lot for this script.

    I need to use this script with -Server parameter, want to schedule this script to run on specific time and generated .CSV file should automatically sent to desired SMTP address. Your help to configure it.

  104. Peter Raychev says:

    This script very useful. Thank you Paul.

  105. Dennis Hartmann says:


    phenomenal script! I did, however, run into a weird thing. When I filtered the spreadsheet to display the archives of users it only showed one, versus at least 15-20 people’s archive on my Exchange 2010 SP3 server, Any clue as to why this could display wrong data?

    • I’m assuming you’ve made a customization to collect the archive info?

      Take a look at this article that shows why Get-Mailbox -Archive doesn’t work as you’d expect it to. If that is how you’re trying to grab the archive info that is probably the reason why you’re getting unexpected results.

      • Dennis Hartmann says:

        Thanks Paul,

        I simply ran the -all condition to get as much info out of our Exchange environment as possible. We have 4 DBs, 3 with quota on mailbox size and one dedicated as the “Archive DB” with no quota. in addition what your script provides, I’d like to see how my archive DB is growing in size. So far, we only have company executives Archive enabled, fearing the DB would grow out of proportion if it were enabled for all users.

        Again, thanks Paul!


        • I see. What you’re getting then is regular mailboxes that are sitting on your archive DB.

          I’ve got a newer version of the script that does include archive mailbox stats in the results. I’ll tidy it up a bit and release an update soonish :)

  106. James Arellano says:

    Hello Paul, this script is a great help…. question, is there any way to incorporate

    “Get-MailboxFolderStatistics –FolderScope Inbox,SentItems,DeletedItems”

    into this reporting script? ive tried but failed with piping.



  107. Dear Paul, Excellent script 7 thank you for your effort, sharing it freely for public.

    I have a request – Is there a possibility to add a column to fetch email ID in the script?

    • I could add that to a future version, but I really encourage people to feel free to customize the scripts to suit their own needs. It is a good way to learn PowerShell if you are not already experienced with it.

  108. Thanks for wonderful script. Worked like charm. Keep up good work Paul!

  109. Paul,

    Thank you for this great script. I am trying to tweak the powershell to get it to show me the StorageLimitStatus but cannot seem to get it to work. I have added Storage LimitStatus to the $stats list (Line 154) and added a new row like the others (Line 179). The heading shows up on my CSV, but I get no data. The two lines as I have them in my code are as follows:

    154: $stats = $mb | Get-MailboxStatistics | Select-Object TotalItemSize,TotalDeletedItemSize,ItemCount,LastLogonTime,LastLoggedOnUserAccount,StorageLimitStatus

    179: $userObj | Add-Member NoteProperty -Name “Limit Status” -Value $mb.StorageLimitStatus

    Any help is greatly appreciated, and thank you again for this great script!

  110. Hi Paul

    Thanks for the great script – works like a charm. Can you point me in the right direction to add two extra columns? I would like to add forwarding address & all other smtp addresses (maybe seperated by a colon or similar). I’ve managed to do this in my own script but it’s fairly primitve and ideally would like to intergrate into your script but I’m not sure how to go about this. Cheers

  111. sorry – should have been clearer with what I was chasing above. i can get the user to where this is forwarding by putting in the following line:

    $userObj | Add-Member NoteProperty -Name “Forwarding Address” -Value $mb.ForwardingAddress

    but ideally I would like to have the actual email smtp address but I don’t know how to get it using the ForwardingSmtpAddress property (seems I need to get this from Get-Mailbox instead of Get-Mailboxstatistics??)

    Also, I can get all the smtp addresses by using:

    $emailaddresses = [string]::Join(“;”,($mb.EmailAddresses | Where-Object {$_.PrefixString -ceq “smtp”})

    which is fine but I’d ideally like to remove the smtp: part from the start of each email address. Maybe I’m just being picky on this one… Thanks.

  112. Tim McCarty says:

    Paul – thanks for this – I am wondering about running this script in very large environments. I am presently working in an environment with over 80,000 mailboxes and the script is taking a very long time to run (in excess of 4 hours) and the working set (RAM) after 4 hours is 7 GB. I am also seeing this error in the console ” Processing data for a remote command failed with the following error message: Objects cannot be added to a closed buffer. Make sure the buffer is open for Add and Insert operations to succeed. For more information, see the about_Remote_Troubleshooting Help topic.
    + CategoryInfo : OperationStopped: (System.Manageme…pressionSyncJob:PSInvokeExpressionSyncJob) [], PSRe motingTransportException + FullyQualifiedErrorId : JobFailure”

    Anyway the point and my question – have you considered any improvements for the script when working with very large data sets and/or can you point me to any helpful resources for improving the script myself?

    Thank you for your time and attention!

    • In a similarly sized environment (where I developed early versions of that script) I never ran it for the entire organization in one go because yes, it takes forever, and yes, it eats a huge amount of RAM.

      Instead I would run it using the -Server or -Database parameters to just get the specific info I needed.

      Perhaps there are more memory-efficient PowerShell techniques that could be used to handle very large scenarios like that but I haven’t looked into it.

  113. Tim McCarty says:

    Paul – I made some additions / changes to your script – if you would like I would be happy to send it to you for your review / use.

    Thanks again for providing such a stellar script.

    In the interest of full disclosure – i will say that the changes I made do NOT improve the functionality (memory use, etc.) of the script – I mostly have it collecting more data – and added an option for quickly testing in new environments.

    -Thanks again, Tim

  114. I wonder if it is possible for this script to run for only the users with hidden mailboxes? I’ve tried altering the script and have had no success. I’m trying to find all of the hidden addresses with who has full and/or read permissions to the hidden addresses listed, but I could do the permissions part manually.

  115. Dhillan says:

    Paul – thanks for this wonderful script. I have used it over the past 2 years now on a number of deployments that i have done and clients are really appreciative of this.

    I however have been trying to run the same script on an Exchange 2013 deployment, the script runs fine except that I do not get information on the StorageLimitStatus. My understanding that there has been changes made to the store and Exchange Server 2013 Information Store does not cache the values of mailbox quotas.

    I am not the best at powershell and have seen that there are ways to get around this but have not been successful. Is there a chance that you will update this script so that it would work on Exchange 2013?

    • You’re right, that status is no longer reported in Exchange 2013. To get the answer you’d need to compare the mailbox size value to the quota (if any is set) on the mailbox (which can be set on the mailbox or the mailbox database).

  116. Hi Paul,

    are there any command to export all shared mailboxes with size?
    Seems like Get-mailbox -RecipientTypeDetails sharedmailbox -Resultsize unlimited with parameter totalitemsize is not valid.
    Get-MailboxStatistics doesnt support receipienttype/type (so i can filter user or sharedmailbox) either,
    Kinda stuck in between!

    • Get-Mailbox doesn’t return TotalItemSize, but Get-MailboxStatistics does. So the answer is to pipe the output from Get-Mailbox into Get-MailboxStatistics.

      • PeterPhi says:

        Hi Paul,

        When i run this script on windows 2012 powershell i have the problem, please help. ((with exchange management shell is ok),

        Cannot process argument transformation on parameter ‘Identity’. Cannot convert value “test01″ to type
        “Microsoft.Exchange.Configuration.Tasks.UserIdParameter”. Error: “Cannot convert hashtable to an object of the
        following type: Microsoft.Exchange.Configuration.Tasks.UserIdParameter. Hashtable-to-Object conversion is not
        supported in restricted language mode or a Data section.”
        + CategoryInfo : InvalidData: (:) [Get-User], ParameterBindin…mationException
        + FullyQualifiedErrorId : ParameterArgumentTransformationError,Get-User
        + PSComputerName : ex13

  117. Thanks Paul.

    But if we run on Windows Powershell , it will be faster in Exchange Management Shell. I tested with windows 2008 r2

  118. Hi Paul,

    Any idea why I would get “Starting a command on 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.”

    This only happens on some users. When this happens, the csv file will be missing info related to Title, Department, Office, OU.


Leave a Comment


We are an Authorized DigiCert™ SSL Partner.