Generate Exchange Environment Reports using Powershell


Update 16th September – V1.6.1 – Exchange 2016 support and various bug fixes (see here for more information)

Update 2nd February – V1.5.8 – Exchange 2013 CU and SP support, HTTPS and CAS array names shown, initial Office 365 Hybrid support (see here for more information)

Update 19th January – V1.5.6 – Exchange 2013 support and bug fixes (see here for more information)

Update 17th August – V1.5.4 – New features and bug fixes (see here for more information)

Update 24th July – V1.5.3 – Bug fixes (see here for more information)

Update 21th July – V1.5 – Re-write with new features including Exchange 2003 support for mixed environments and more detailed information (see here for more information)

Update 21th June – V1.1 – Bug fixes, Exchange 2007-only support in addition to 2010/2010+2007, and new features.

As an Exchange administrator, there’s times when it’s useful to have a visual, straightforward and concise document that gives you a good overview of your environment. Although with tools like Visio and Word you can make such a document, it’s hard to keep these documents up to date or use previous versions to track and check changes.

This script, inspired by the output of an Exchange TAP tool, aims to automatically generate a report that gives you an overview of your environment, Exchange 2003, 2007, 2010, 2013 and 2016 servers and database availability groups – in particular:

    • Total Servers per Exchange version & service pack
    • Total Mailboxes per Exchange version & service pack, plus Office 365 remote mailboxes
    • Totals for Exchange roles across the environment
    • A site-by-site breakdown for the following:
      • Mailboxes per site
      • HTTPS FQDNs used for Internal, External and SCP URLs
      • CAS array names
      • Exchange servers, version, update rollup and version, service level, highlighted installed roles, OS version and service pack


    • A breakdown of each Database Availability Group including:
        • DAG name, member count and member list
        • Database information such as
          • Name
          • Mailboxes per database and Average Size
          • Archive mailboxes per database and Average Size only shown if a DB includes Archive mailboxes
          • Database and whitespace size
          • Database and log disk free space percentage
          • Last full backup date/time (new) – only shown if at least one DAG DB has had a full backup
          • Circular Logging state (new) only shown if at least one DAG DB has circular logging enabled
          • Server hosting the active copy
          • List of servers hosting copies and copy count
    • A breakdown of Non-DAG databases including Exchange 2007 and 2003 DBs, including the database information above, along with Storage Group name (where applicable).

The script doesn’t support detailed information about Exchange 2007/2003 CCR/SCC clusters, but these are shown as ClusMBX in the output. At the moment, the script doesn’t show Public Folder information but if there is interest I can add extra features; and of course the source is provided should you wish to alter it to your own needs.

To be able to execute the script, you need to use the Exchange Management Shell (the latest version for your environment, with Powershell 2.0) and be able to get information about AD Sites, Exchange Servers, Mailboxes, Database Availability Groups and Databases. It uses WMI to retrieve OS information and detect Exchange 2007 clusters and calculate Exchange 2007 database size and Remote Registy calls to get Update Rollup information. A normal Exchange administrator should be able to perform these tasks.

Executing the script is straightforward – the only setting you need is to specify where to write the HTML file:

.\Get-ExchangeEnvironmentReport -HTMLReport c:\report.html

If you want it to email the results, the follow parameters are available to allow the report to be sent directly from the script:

.\Get-ExchangeEnvironmentReport -HTMLReport c:\report.html -SendMail:$true

As usual, the script is provided to download as-is without any warranties, at the bottom of this post. Comments and suggestions are always welcome.

Download Get-ExchangeEnvironmentReport.ps1



663 thoughts on “Generate Exchange Environment Reports using Powershell

  1. Pingback: Technology is so much easier when everyone shares their knowledge - Cybercon Services Knowledge Log

  2. Pingback: The most amazing “Exchange 2010 Dashboard Report” Script Monitor | Ammar Hasayen - Blog

  3. Pingback: Generating Exchange 2010 reports with PowerShell | Thoughtsofanidlemind's Blog

  4. Pingback: Exchange Dashboard Organization – “Email Report” PowerShell Script | Ammar Hasayen - Blog

  5. Great Script, Thanks Steve. One issue that I now have is that running the script under Task Scheduler with Windows 2012 R2 is no longer functioning properly. I am getting an error (0x1) every time. Same scripts works great under Windows 2008 R2. Running the script manually works well but not with Task Scheduler for Win 2012 R2, any idea?

    • Hi Robert, I hit the same issue as well in our environment (see my comments below as well). In order to fix I ended up creating a separate script to call my existing script (not efficient I know)!

      ##############script called execute_Get-ExchangeEnvironmentReport.ps1
      ## Add EMC SnapIn
      Add-pssnapin Microsoft.Exchange.Management.PowerShell.E2010

      ## Call script
      B:\location\Get-ExchangeEnvironmentReport.ps1 -HTMLReport .\report.html -SendMail:$true

      I then created the scheduled task with the following info:

      Program/Script: C:\Windows\System32\WindowsPowerShell\v1.0\powershell.exe
      Arguments: B:\location\execute_Get-ExchangeEnvironmentReport.ps1
      Running as ‘SYSTEM’ account/Run with highest privledges

      • Thanks Mason, worked great for me. Hope Steve will fix it with his future versions.

  6. Quick note for anyone having issues… if the script suddenly breaks and starts spitting back empty fields, make sure the system you’re running it on is patched to match the newest version of Exchange in your environment. We patched one system with Exchange 2013 SP1 and it broke the script because I didn’t patch the desktop system it was running from. As soon as I patched the desktop to update the shell and admin tools, it started working again.

    • Hiya. That may not be an issue with the script – you should be patching the desktop tools at the same time if you plan on performing admin on Exchange using them.

  7. Pingback: My Favorite Scripts to Use with Exchange | Oddytee

  8. Thanks Steve, the script runs awesome and the output exactly what I need in our company. However I do have one minor issue that I’m hoping maybe someone else also hit. I can execute any part of the script successfully via both the PowerShell console or the ISE…..BUT when I schedule it as a task the schedule task will never execute. It shows a ‘Last Run Result’ of “Incorrect Function. (0x80070001)” This is on a Windows 2012 Server Standard machine. I’m running the task with one of my Exchange svc accounts that also runs multiple other scheduled tasks. Any ideas are welcome!

    • Just incase anyone hits issue I had, here is how I got around it. I ended up creating a separate script to call my existing script (not efficient I know)!

      ##############script called execute_Get-ExchangeEnvironmentReport.ps1
      ## Add EMC SnapIn
      Add-pssnapin Microsoft.Exchange.Management.PowerShell.E2010

      ## Call script
      B:\location\Get-ExchangeEnvironmentReport.ps1 -HTMLReport .\report.html -SendMail:$true

      I then created the scheduled task with the following info:

      Program/Script: C:\Windows\System32\WindowsPowerShell\v1.0\powershell.exe
      Arguments: B:\location\execute_Get-ExchangeEnvironmentReport.ps1
      Running as ‘SYSTEM’ account/Run with highest privledges

  9. Hi Steve,

    The Code is not working for me, and I Badly need to be done, Please Help me

    Exception calling “Join” with “2” argument(s): “Value cannot be null.
    Parameter name: value”
    At C:\Users\Administrator\Desktop\Exchange.ps1:568 char:42
    + $ExtNames = [system.String]::Join <<<< (",",$ExtNames)
    + CategoryInfo : NotSpecified: (:) [], MethodInvocationException
    + FullyQualifiedErrorId : DotNetMethodException

  10. Pingback: Top 8 Migration Tips for Office 365 - Dice News

  11. Hi,
    Great script, have it working in several Exchange 2007 environments.
    Tried it in a 2010 environment, and while it mostly works, it doesn’t report on non-DAG DBs under Exchange 2010? Just doesn’t display any DB info at all

    Also having issues with multiple recipients on SendMail, tried a few different formats, comma, semi colon, space/no space, wrap it in quotes. Most gave a formatting error, one did appear to work, but only the first named address received the email.

    Have read back through pages of comments and noticed a couple of others having the same issue, but didn’t see a resolution.
    Anything obvious I’m missing?


    • I have not been able to figure out why but if I only had one DB no database info was show. The minute I added a second DB I got the info like white space and the like. DO you have only one DB ?

      • Yep, you’re right, only one DB in that environment.
        I was assuming it was due to it being non-DAG, didn’t consider the number.
        I can’t easily add a new DB to that environment, but will take a skim through the script to see if anything stands out that may be connected to the number of DBs.

        And the multiple recipients was my own stupidity, got lost in the combinations i was trying, seperating addresses with a comma and a space works fine.

  12. I am having the same problem Marc is having. No matter what I do I get the following when running the script

    Missing expression after unary operator ‘-‘.
    At line:1 char:2

    Any ideas?

  13. Hi Steve,

    Thanks for the awesome script, we need to implement the viewentireforest parameter in our environment.
    We’ve tried to add it but it doesn’t work. Can you enlighten me?


  14. Thanks Steve for a great script. I am having a problem with it recognizing 4 of my Exchange servers (there are 5 total). The script is able to identify one of the servers as an Exchange 2010 server. The other 4 it is identifying them as pre-2007 servers and not identifying their roles. The difference between the 4 servers and the 1 servers is that the one server has only the CAS and HUB roles while the other 4 servers have all 3 roles (CAS, HUB, mailbox). How come the script isn’t able to identify these 4 servers correctly?

  15. This script is great. I am using it to keep track of our 58 Databases. I am running the script daily, but before running it, renaming the previous days report with the date. I would like to find a way to get trending information out of the 390 days worth of reports I have saved.

  16. Steve,

    Great, great script.

    I have seen a few users ask if there’s a way to avoid the Edge Servers, I have the same problem. Reason is from Lines 345 on, it tries to detect the OS info via WMI for the Edge servers and predictably, it fails. The script then exits at that point and doesn’t get past it.

    Has anyone figured out if there is a way to:

    1. Add some errorr handling at this point – Line 345 on?
    2. Or modify the script to only look at a single server or a list of MBX servers?

    Many thanks again!!

  17. Would there be away to flag (or color) the free space on the database’s? would like to see green, yellow or red based on free space left.

  18. Hi Steve first thanks for your great and amazing script, second i got the following in Services one of my servers colored with read and remarked with 1, could you please explain what this mean.

  19. Pingback: Exchange Environment Report v1.5.8 now available | Steve Goodman's Exchange & Office 365 Blog

  20. Hi,

    Does anyone knows how to change the script to search only for a determined DAG name.

    We have a big infrastructure with exchange 2003, 2007 and 2010 between local and remote sites and there are some WMI and comunications questions and the script, as it is, takes along time to complete and returns a lot of errors.

    I Just want to have this information regarding one DAG.

    Thank you.

      • Hi,

        I’ve tried that but i must be doing anything wrong because it doesn’t work.

        I’ve tried to put de first the first seven letters plus * and still goes looking for all servers in exchange organization.

        Thank you,

  21. Thanks for the excellent script. I ran the script in my environment, I did not get mailbboxes details. output report mailboxes values shows empty but i get remaining details. Please suggest how to get the mailboxes count in the output report.

  22. When I run this scripts works fine but it asked me to write me the file name and path but what I wanted is if I run this script it just create the output defined within the scrip. So what do I need to change in the script please can you help.

  23. doing the same with v 1.5.4 does the correct output, and I get the Database Infos too.

    faulty version 1.5.6?

  24. Hi,

    I tried the script running on ex 2k7 and a 2k10 environment w/o DAG, so it only displays the servers and role assignment, no avg. mailbox size etc., what am I doing wrong?

  25. Hi all,
    The cript hang on “getting Exchange Server Information” and I have no log or errors to debug. It’s running for 1 hour and still hang. Account rights, Wmi and Remote registry are fine.
    Any suggestion ?!?

  26. HI Steve, what would be the best way to limit the results to only servers in a certain site or by naming convention? For example, | where { $ -like “123???456???789” } Where would i locate it?
    Thanks in Advance!

  27. Hi, i have wrong error on average mailbox size hosted on Exchange Server 2003…
    Results for average mailbox and DB whitespace are wrong.
    Can you help me? Any ideas?

  28. I am trying to run the script from my W7 box w/pshell 2. My exchange 2007 sp3 server is still running pshell1 and I can’t jump thru the hoops to upgrade right now. In any case, I get this error when running the script:

    You cannot call a method on a null-valued expression.
    At c:\get-exchnangeenvironmentreport.ps1:322 char:64

    What am I missing? Thx!

  29. Pingback: Quelques outils pour votre infrastructure

  30. I tried to run the script on a new exchange 2013 CU2 install and get this error: “The file C:\Users\administrator.BCNAZ\Downloads\Get-ExchangeEnvironmentReport.ps1 is not digitally signed”

  31. Looks great, but I am getting an Out-file : Access to path d:\temp is denied.
    I am logged in as administrator…
    any ideas?

  32. Any one run into an issue where they dont get specific dag data in the report? I can see the servers associated with my dag. However I do not see specific like who is the active server and white space, etc

  33. Is there any way I can exclude all but my 2010 environment servers. We have a some 2007 and PF servers. I just want to see our new 2010 stuff.

  34. Sorry guys… my Poweshell exchange was in D: and not in C:
    I changed to c:\scripts; c:\scripts\Get-ExchangeEnvironmentReport.ps1 and everything started to work.

    • Marc, I’m having the exact same issue as you. I tried your fix but i always get the following…

      Missing expression after unary operator ‘-‘.
      At line:1 char:2

      Any ideas?

  35. I am getting really frustrated with the script via Task Scheduler.

    Windows 2008 R2
    Exchange 2010

    Problem >>
    I have two environments:
    Lab Environment: It works via Task Scheduler and when I run manually.
    Production Environment: Only if I run the scripts manually. Not via Task Scheduler.

    The user I am using on my production environment is a member of Domain Admins + Organization Management.
    If I log in the Production Environment I can run my scripts manually successfully.

    How my Task is configured:
    Run whether user is logged or not – checked
    Run with high privileges – checked

    Program/script: C:\Windows\System32\WindowsPowerShell\v1.0\powershell.exe
    Argument: -c “push c:\scripts; c:\scripts\Get-ExchangeEnvironmentReport.ps1 -HTMLReport c:\scripts\report.html -SendMail:$true

    No matter what I do, the task seems to complete(according the history of the task – no erros whatsoever) but it does not send the report.

    Initially I thought was my SMTP server, but if I run the script manually works….like:
    .\Get-ExchangeEnvironmentReport.ps1 -HTMLReport c:\scripts\report.html -SendMail:$true

    I already ran:
    Set-ExecutionPolicy Unrestricted
    Set-ExecutionPolicy RemoteSigned
    No difference!

    If I run manually it works. The same happens with another script (Test-ExchangeServerHealth). If I run manually it works. If I try to run via Task Scheduler, nothing happens.
    I reckon it is a permission issue. But to be honest I am running out of ideas.

    Any ideas?
    Please help ;-(

  36. I am trying to run it in a pure E2K3 Organization. Error “Exchange Management shell can not be loaded”. Its a Exchange 2003 environment and doesn’t have exchange management shell. Is there anyway to get the reports from Pure E2K3 Org?

    • Wow no ! Objects used in the script can’t be called without Shell or in 2003. For Exch2003 most scripts are on VBS but they are not so detailed like this. Sorry 🙂

      • Yep that’s right.. It can report on Exchange 2003 only if you have Exchange 2007 or above within your organisation. The typical reason for this might be if your migrating from Exchange 2003 and wish to see how your migration is progressing

  37. Hello, script is running like a charm. I’m using it for quite some time now. I have a question – how can I get report only for Exchange 2010, or only for certain servers without digging the whole network for all servers ?


      • Cannot overwrite variable true because it is read-only or constant.
        At C:\Users\grantlj\Downloads\Get-ExchangeEnvironmentReport.ps1:106 char:134
        + … ewEntireForest=$true,
        + ~~~~~~
        + CategoryInfo : WriteError: (true:String) [], SessionStateUnauthorizedAccessException
        + FullyQualifiedErrorId : VariableNotWritable

        Property ‘ViewEntireForest’ cannot be found on this object; make sure it exists and is settable.
        At C:\Users\grantlj\Downloads\Get-ExchangeEnvironmentReport.ps1:774 char:2
        + $global:AdminSessionADSettings.ViewEntireForest = $ViewEntireForest
        + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
        + CategoryInfo : InvalidOperation: (:) [], RuntimeException
        + FullyQualifiedErrorId : PropertyNotFound

        As well as the html output is blank. I am having difficulty getting the email to send as well.

        • “SessionStateUnauthorizedAccessException” – maybe your account does not have needed access right ? Are you executing this with account that has Exchange rights and also you run this from the Exchange server itself ? Try removing the $ViewEntireForest from the script.

          I have the feeling this is permission issue as the script runs well if you have enough access. Also for a sending server you should select a HUB/SMTP server which to authorize your address “-From”, if it’s open relay it;s not needed to have a mailbox, but if it’s just a HUB server with no relay connector you should have corresponding mailbox associated to the From address.

          • If I run the snippet Send-MailMessage -Attachments $HTMLReport -To “” -From “” -Subject “Exchange Environment Report” -BodyAsHtml $Output -SmtpServer “” it sends the message. When I hover over $SendMail it reads as False. Even though I have the values set to true. Any ideas?

            Also when I run it directly from the exchange server in powershell the report come out blank. Both accounts I have tried with have exchange rights.

  38. Hi Steve, Awesome work! I have been using your script for quite some time now, however i would ask if it is relative straight forward to get the script to sort via database name?

  39. Hello Steve, thanks for the script, just a small info.. we have Edge Server is DMZ and the credetials what we are using to run the script does not go with Edge Severs , so is there any work around to get or gather the details for Edge Servers also.. Thanks

  40. Pingback: Office 365 Migration Tools | pickettsproblems's Blog

  41. What a great script!

    Would be great if the “Database Disk Free” also worked properly with mount point volumes. At the moment they all report the same free space as it looks at the host disk and not the mount point.

    • would love to hear if anyone is able to fix this issue – we have mount points as, which worked right up to the time that we added drive letters to the mounts.

    • We also use mount points for the log and database volumes since we are using DAGs, and this makes keeping the paths consistent easier. With the latest version of the script, v1.5.8, the database white space and disk free percent stats are correct for our environment, but the log volumes are wrong. It is looking at the root volume instead of the mount point. Example: it looks at L: instead of L:\dbname, where the logs actually reside.

      The script is very useful, regardless of the issue.

      • To fix the issue with the log disk free showing the same value for mounted volumes on directories, make the following change to the script:

        Search for “LogFolderPath”:
        Original code:
        if ($Database.LogFolderPath.PathName -like “$($Disk.Name)*”)
        $FreeLogDiskSpace = $Disk.FreeSpace / $Disk.Capacity * 100
        New code:
        $LogPathName = $Database.LogFolderPath.PathName + “\”
        if ($LogPathName -like “$($Disk.Name)*”)
        $FreeLogDiskSpace = $Disk.FreeSpace / $Disk.Capacity * 100

        Note: You can use whatever variable name you like, I just used $LogPathName.

Comments are closed.