blog.powershell.no

On Windows PowerShell and other admin-related topics

Retrieve number of mailboxes per database in Exchange Server 2010

Mailbox databases in Exchange Server 2010 doesn`t contain any information regarding the numbers of mailboxes stored in them. A common approach to retrieve this information is using the Exchange Management Shell.

Two examples

 1: #Example 1

 

 2: (Get-MailboxDatabase) | ForEach-Object {Write-Host $_.Name (Get-Mailbox -Database $_.Name).Count}

 

 1: #Example 2

 

 2: (Get-MailboxDatabase) | Select-Object Name,@{Name="Number of users";Expression={(Get-Mailbox -Database $_.name).Count}}

 

Either of these works fine if you want to get the number of mailboxes quick and dirty. However, in larger environments, these one-liners may run for a while.

I did a quick measurement using the Measure-Command cmdlet; Example 1 ran for 36 seconds and example 2 ran for 30 seconds. The environment I ran this in got 5 mailbox databases and approximately 1300 mailboxes.

When running these as one-liners from the Exchange Management Shell, or as part of a scheduled task, the performance might not be an issue.

A colleague of mine was using the Cmdlet Extension Scripting Agent to provision new mailboxes to the mailbox database with the least number of mailboxes in it. In this scenario the performance is key. To achieve better performance, we used an LDAP-query using System.DirectoryServices.DirectorySearcher.

Get-MDBMailboxCount function

I created a PowerShell function to retrieve the number of mailboxes per mailbox database using the DN of a mailbox database as an argument.

 function Get-MDBMailboxCount ([string]$DN) {

 

$Searcher = New-Object System.DirectoryServices.DirectorySearcher

 

$Searcher.SearchRoot = New-Object System.DirectoryServices.DirectoryEntry ("LDAP://$(([system.directoryservices.activedirectory.domain]::GetCurrentDomain()).Name)")

 

$Searcher.Filter = "(&(objectClass=user)(homeMDB=$DN))"

 

$Searcher.PageSize = 10000

 

$Searcher.SearchScope = "Subtree"

 

$results = $Searcher.FindAll()

$returnValue = $results.Count

#dispose of the search and results properly to avoid a memory leak
 $Searcher.Dispose()
 $results.Dispose()

return $returnValue

 

}

 

A problem we stumbled upon was that wildcards didn`t seem to work on the homeMDB-attribute, so we couldn`t use *Mailbox Database Name* for this value.

When looking up on MSDN, it turned out that wildcards are not supported on LDAP DN`s:

For queries that include attributes of DN syntax in a filter, specify full distinguished names. Wildcards (for example, cn=John*) are not supported.

That`s the reason for the function taking DN as an argument, and not the name of a mailbox database.

The function runs the query against the current domain, and hence you don`t need to specify a domain for the LDAP-query.

Back to the performance part, I now ran Measure-Command against the following one-liner:

 1: (Get-MailboxDatabase) | ForEach-Object {Write-Host $_.Name (Get-MDBMailboxCount -DN $_.DistinguishedName)}

 

This time the performance was 3,7 seconds, almost 10x faster. Actually, using a foreach-loop instead of Foreach-Object also makes it slightly faster; 3,5 seconds. You can read up on the difference between these two approaches here.

Get-MDBMailboxCount script

Having the Get-MDBMailboxCount function, I also decided to create a script using this function, which generates a CSV-file.

The script uses a foreach-loop to go through each database in the Exchange-organization, and then creates a custom object for each database containing the name and number of mailboxes. The custom objects are added to an array which can be used for other things like determining the smallest/largest database. You could also use this information to generate graphs like I showed in this blog-post.

Note that I`ve only tested the above against Exchange Server 2010. I suppose it also should work against Exchange Server 2007, if someone can verify this it would be nice if you could leave a comment below.

Update 04.08.2011: The function has been updated  to avoid a memory leak when the function is called multiple times. Thanks to Weston McNamee for the tip (see his comment below).

November 21, 2010 Posted by | Exchange Server 2010, Exchange Server management, Scripting, Windows PowerShell | | 15 Comments