Generate Exchange Environment Reports using Powershell

image

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:

1
.\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:

1
.\Get-ExchangeEnvironmentReport -HTMLReport c:\report.html -SendMail:$true -MailFrom:you@example.com -MailTo:you@example.com -MailServer:smtp.example.com

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. Steve, I needed to change line 933:
    $Mailboxes = [array](Get-Mailbox -ResultSize Unlimited) | Where {$_.Server -like $ServerFilter}

    into:
    $Mailboxes = [array](Get-Mailbox -ResultSize Unlimited -Domaincontroller $DC) | Where {$_.Servername -like $ServerFilter}

    The filter was not working for me on the servers and after the change from server to severname it was.
    Also I have a multi domain environment and I needed to assign a DC to the command.
    same thing was trough with the remote mailbox request.

  2. running on 2003 std x64 SP2, Exchange 2007 SP3 UR17. HTML report has been generated but without DB sizes. Any idea?

    Exception calling “Join” with “2” argument(s): “Value cannot be null.
    Parameter name: value”
    At C:\Documents and Settings\Administrator.domain\Desktop\Get-ExchangeEnvironmentReport.ps1:584 char:42
    + $IntNames = [system.String]::Join <<<< (",",$IntNames)
    + CategoryInfo : NotSpecified: (:) [], MethodInvocationException
    + FullyQualifiedErrorId : DotNetMethodException

    Exception calling "Join" with "2" argument(s): "Value cannot be null.
    Parameter name: value"
    At C:\Documents and Settings\Administrator.domain\Desktop\Get-ExchangeEnvironmentReport.ps1:585 char:42
    + $ExtNames = [system.String]::Join <<<< (",",$ExtNames)
    + CategoryInfo : NotSpecified: (:) [], MethodInvocationException
    + FullyQualifiedErrorId : DotNetMethodException

    Thanks

  3. Currently running Exchange Server 2013 CU8, when I attempt to run from the EMS on one of the Exchange servers, the script errors (but still completes):
    A parameter cannot be found that matches parameter name ‘IncludePreExchange2010’.
    + CategoryInfo : InvalidArgument: (:) [Get-MailboxDatabase], ParameterBindingException
    + FullyQualifiedErrorId : NamedParameterNotFound,Get-MailboxDatabase
    + PSComputerName : OUREXCHANGESERVERNAME

    The resulting html file doesn’t have any information in it except for server names, and total number of mailboxes.

  4. I have removed the database that was not mounted as it was pointing to an outdated location. Now the script produces only a warning (WARNING: Active Directory server settings remained unchanged.) and the report is not full containing only the first table with the server details.

  5. Hi Steve, thank you for the great script. I’ve been using it to generate reports numerous times without issues and I think it is great. Unfortunately I came up across an environment with Exchange 2010 SP2 UR8 on Windows Small Business Server 2011 Std where it would always produce the following error:

    You cannot call a method on a null-valued expression.
    At C:\temp\Get-ExchangeEnvironmentReport.ps1:187 char:47
    + [long]$Size = $Database.DatabaseSize.ToBytes <<<< ()
    + CategoryInfo : InvalidOperation: (ToBytes:String) [], RuntimeException
    + FullyQualifiedErrorId : InvokeMethodOnNull

    You cannot call a method on a null-valued expression.
    At C:\temp\Get-ExchangeEnvironmentReport.ps1:188 char:65
    + [long]$Whitespace = $Database.AvailableNewMailboxSpace.ToBytes <<<< ()
    + CategoryInfo : InvalidOperation: (ToBytes:String) [], RuntimeException
    + FullyQualifiedErrorId : InvokeMethodOnNull

    Any help appreciated. That is the latest 1.6.1 version of the script and the error is on the following line:
    [long]$Size = $Database.DatabaseSize.ToBytes()

    I did also receive a Warning of one of the databases not being mounted or available. Is that what is causing the issue

  6. Pingback: Planning for an O365 Migration – The Painted Lady

  7. Steve,

    Thanks for sharing this. Do you have a version of this that would send the data in the tables to a .CSV file or SQL DB?

    Thanks,

  8. Same error as Pat along with version retrieval error on passive DAG

    Exception calling “OpenRemoteBaseKey” with “2” argument(s): “The network path was not found.

    At C:\Get-ExchangeEnvironmentReport.ps1:345 char:69
    + $RemoteRegistry = [Microsoft.Win32.RegistryKey]::OpenRemoteBaseKey <<<< ('LocalMachine', $ExchangeServer.Name
    );
    + CategoryInfo : NotSpecified: (:) [], MethodInvocationException
    + FullyQualifiedErrorId : DotNetMethodException
    \

  9. I get same error as Pat on Exchange 2013 DAG server with CU 10 and it looks like it fail to get version from passive server after first error with –

    Exception calling “OpenRemoteBaseKey” with “2” argument(s): “The network path was not found.

    At C:\Get-ExchangeEnvironmentReport.ps1:345 char:69
    + $RemoteRegistry = [Microsoft.Win32.RegistryKey]::OpenRemoteBaseKey <<<< ('LocalMachine', $ExchangeServer.Name
    );
    + CategoryInfo : NotSpecified: (:) [], MethodInvocationException
    + FullyQualifiedErrorId : DotNetMethodException

  10. Hi Steve ,

    We have an mixed environment Exchange 2010 SP3 and Exchange 2013 CU10 servers the scripts runs without any errors except that we dont have any info in the report in this lines:

    Server Database Name Mailboxes Av. Mailbox Size DB Size DB Whitespace

    Please advise.

    AB.

  11. Hi Steve,

    I may have found a little bug in your script.
    When it counts the average mailbox sizes, it has numbers counted for the Average(regular)MailboxSize column with the Archive databases as well, even if that DB does not contain a regular mailbox. It is also counting the average archive-mailboxes size, which is fine for the archive databases, but the numbers shown in the two average columns are near but not fully identical. (verified with several archive databases that has 0 regular mailboxes)

    The opposite direction works fine: if a mailbox database does not contain (a mistakenly placed) archive mailbox, then the archive-average is shown as 0.00
    and if the mailbox database has an archive mailbox, then the average archive size is shown properly for that only, along with other numbers are also OK for that mailbox DB.

    I think the mistake might be in the way how the mailboxes are handled within $Database. There is a need to verify each mailbox in each cycle
    to decide if it is archive or regular mailbox. If there is no mistakenly placed regular mailbox in the archive database, then the mailbox-average should be also 0.00. or if there is a mistakenly placed regular mailbox, then the mailbox average counter should show that only.

    Summarizing the above: the average mailbox size column should always reflect to the contained regular mailboxes only, excluding the archive mailboxes.

  12. Upgraded to 2013 CU11 and now get the following error:

    WARNING: Cannot detect database size via WMI for
    You cannot call a method on a null-valued expression.
    At C:\Scripts\ps\Get-ExchangeEnvironmentReport.ps1:214 char:2
    + @{Name = $Database.Name
    + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    + CategoryInfo : InvalidOperation: (:) [], RuntimeException
    + FullyQualifiedErrorId : InvokeMethodOnNull

    Index operation failed; the array index evaluated to null.
    At C:\Scripts\ps\Get-ExchangeEnvironmentReport.ps1:126 char:2
    + $MailboxStatistics = [array]($ExchangeEnvironment.Servers[$Database.Server.Name …
    + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    + CategoryInfo : InvalidOperation: (:) [], RuntimeException
    + FullyQualifiedErrorId : NullArrayIndex

    Index operation failed; the array index evaluated to null.
    At C:\Scripts\ps\Get-ExchangeEnvironmentReport.ps1:137 char:6
    + if ($ExchangeEnvironment.Servers[$Database.Server.Name].Disks)
    + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    + CategoryInfo : InvalidOperation: (:) [], RuntimeException
    + FullyQualifiedErrorId : NullArrayIndex

    You cannot call a method on a null-valued expression.
    At C:\Scripts\ps\Get-ExchangeEnvironmentReport.ps1:196 char:3
    + $Size = [long](get-wmiobject cim_datafile -computername $Database.Server.Name …
    + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    + CategoryInfo : InvalidOperation: (:) [], RuntimeException
    + FullyQualifiedErrorId : InvokeMethodOnNull

    WARNING: Cannot detect database size via WMI for
    (repeated for every DB)

  13. I’m running the latest version of the script but it seems to miss information. Like for instance. I dont get any DAG information. I am running exchange 2013 CU11. Is this expected?

    • Actually I suppose the better question is how can I execute this script as a scheduled task from a non exchange box? Basically I seem to need to be able to utilize the remote powershell. I’m coming from exchange 2007 with lots to learn. And to answer my previous post. It runs fine when run on an exchange server….doh!

      My big issue is I have a dedicated box that I use to keep all my automated tasks/reports etc. running on and would prefer to keep it that way.

  14. Dear All,

    Can anyone help me out to create a powershell script as per below requirements.
    1. We are planning to add new SMTP address to our existing users and so we want to set auto reply message as per below to all user mailbox.
    2. Script should take user display name with old email id and new email id and set below customize message on each of individual mailboxes
    3. Reply message should be as per below
    4. Script should take all BOLD content from excel sheet and set customize auto reply message to each individual mailboxes

    Dear Sender,

    Please note that my email id has been changed from abc@test.com to xyz@test.com , hence for the please send mail on new email id only…

    Regards,
    ‘User name’

    Note: We are having Exchange 2010 environment

  15. Pingback: In at the deep end – Exchange Hybrid Goodness Part 1 | The Painted Lady

  16. I have discovered a bug where the CAS servers are on a different CU version to the MBX servers.
    I realize this is not an ideal configuration and will be rectified shortly. CAS on CU5 and MBX on CU9 the report doesn’t generate any data.

Comments are closed.