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 $}}


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

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

Add/remove e-mail addresses using Exchange Management Shell

Adding or removing e-mail addresses from mailboxes using the Exchange Management Shell in Exchange 2007/2010 isn`t a straightforward task, and are a common question in many Exchange/PowerShell-forums. PowerShell MVP Shay Levy has posted an excellent post on how to accomplish this using the Update-List cmdlet in Windows PowerShell 2.0.

To make this easier for Exchange administrators with less PowerShell experience, I decided to create two PowerShell advanced functions, which are available here.





As you can see, the Remove-EmailAddress accepts either –EmailAddress or –EmailDomain as parameters. Only one of the two can be specified. The –EmailDomain parameter removes all e-mail addresses containing the specified domain. Note that the PrimarySMTPAddress are never modified by either of the two functions. Also note that the functions require Windows PowerShell 2.0, since we are leveraging the Update-List cmdlet.

If you are running Exchange Server 2007 SP2, it is supported to install Windows PowerShell 2.0 (more info here).

To use the functions, you might use one of the following options:

Update 22.11.2010: Shay Levy has posted another blog-post on this topic: Managing email addresses in Exchange 2010. The technique used there are quite different (hash tables), so as you can see, PowerShell offers many different ways to accomplish the same task. What you choose is of course up to you.

November 14, 2010 Posted by | Exchange Server 2007, Exchange Server 2010, Exchange Server management, Windows PowerShell | | 8 Comments

Using Cmdlet Extension Agents to customize mailbox provisioning in Exchange Server 2010

Exchange Server 2010 introduced a new feature for automatically assigning a database while provisioning mailboxes, which uses the Mailbox Resources Management cmdlet extension agent. This feature are demonstrated and described in further detail in this blog post by Mike Pfeiffer.

While this new feature is a great enhancement to Exchange Server, it`s actually possible to customize it further by using another cmdlet extension agent named Scripting Agent.

There are several common ways to distribute mailboxes to databases:

  • Alphabetically
  • Per location
  • Per department
  • Random

My example will focus on using the alphabetically approach to distribute the mailboxes. I`ve re-used the regular expression switch I wrote in this blog post.

Before we proceed, you might want to read this blog post by Pat Richard on how the Scripting Agent work, as well as reading up on Cmdlet Extension Agents on the Exchange Server TechCenter on Microsoft TechNet.

1. Create a file named ScriptingAgentConfig.xml and save it to the CmdletExtensionAgents-folder which by default are C:\Program Files\Microsoft\Exchange Server\V14\Bin\CmdletExtensionAgents. You can find my sample ScriptingAgentConfig.xml here. You will need to customize the names of the databases, as well as the domain name and the Exchange organization name in the $user.database property. Then you would need to copy the ScriptingAgentConfig.xml to the CmdletExtensionAgents-folder on all Exchange 2010 servers in your organization.

2. From the Exchange Management Shell, run Enable-CmdletExtensionAgent “Scripting Agent”. This will enable the Scripting Agent, which will use the ScriptingAgentConfig.xml file we created.

3. From the Exchange Management Shell, run Disable-CmdletExtensionAgent “Mailbox Resources Management Agent”. The Mailbox Resources Management Agent must be disabled when we want to assign the database for the new mailbox using the Scripting Agent, else the Mailbox Resources Management Agent will take precedence. Alternatively we could have changed the priority of the Scripting Agent.

When the above configuration are in place, it`s time to test the new configuration, which of course should be done in a lab environment prior to putting it to production.

From the Exchange Management Console, create a new mailbox and be sure to not select “Specify the mailbox database rather than using a database automatically selected”:


Alternatively, if using the New-Mailbox cmdlet from the Exchange Management Shell, do not specify the “-Database” parameter.

When the test mailbox are created, verify that the database the new mailbox was assigned to is the expected one. For troubleshooting, I would recommend you to use the “–Verbose” parameter on the New-Mailbox cmdlet.

You can use the very same technique to customize database selection based on i.e. the per department approach, by accessing other properties from $provisioningHandler.UserSpecifiedParameters

October 17, 2010 Posted by | Exchange Server 2010, Exchange Server management, Scripting, Windows PowerShell | , | 1 Comment

Managing calendar permissions in Exchange Server 2010

In legacy versions of Exchange Server we could use PFDAVAdmin to manage calendar permissions, or alternatively the 3rd party tool SetPerm.
With Exchange Server 2010 calendar permissions can be managed using the *-MailboxFolderPermission cmdlets. While these cmdlets can be used to manage permissions on any mailbox folder, we`ll focus on calendar permissions.

In fact we got 4 *-MailboxFolderPermission cmdlets in Exchange Server 2010:

Since I`ll be focusing on managing default permissions , which is an existing ACL on the calendar folder, we need to use the Set-MailboxFolderPermission cmdlet:


To grant “Reviewer”-permissions for the “Default” user, we would run the following:


Some companies have a policy that everyone must share their calendars with all users. Since it`s now possible to manage calendar permissions using PowerShell, I`ve written a script to accomplish this task; Set-CalendarPermissions.ps1.

While this script could be scheduled to run on a regular basis, a better approach for managing calendar permissions for new mailboxes are the use of the Scripting Agent which is a part of the Cmdlet Extension Agents, a very useful feature introduced in Exchange Server 2010.

Pat Richards has posted an excellent post on how to automatically modify new mailboxes using the Scripting Agent.

September 20, 2010 Posted by | Exchange Server 2010, Exchange Server management, Scripting, Windows PowerShell | | 23 Comments

Script to spread Exchange mailboxes alphabetically across databases

I recently needed to write a script to spread mailboxes in Exchange Server 2010 alphabetically across databases. In my scenario there were 5 databases, and I used a regex switch in PowerShell to assign each mailbox to the correct database based on the first character in the user`s displayname:

switch -regex ($displayname.substring(0,1))
       “[A-F]” {$mailboxdatabase = “MDB A-F”}
       “[G-L]” {$mailboxdatabase = “MDB G-L”}
       “[M-R]” {$mailboxdatabase = “MDB M-R”}
       “[S-X]” {$mailboxdatabase = “MDB S-X” }
       “[Y-Z]” {$mailboxdatabase = “MDB Y-Z” }
        default {$mailboxdatabase = “MDB Y-Z” }

The reason for the un-even spreading of letters are that the Norwegian language contains 3 extra letters, and I just assign those as well as other non-letter characters to the last database.

The script are available from here. You may of course adjust the number of databases, the ranges of letters to use, which user attribute to sort against (e.g. lastname) and so on to fit your needs.

Although there are several common approaches to provisioning mailboxes across databases, be aware of the new mailbox provisioning load balancer in Exchange Server 2010. If you don`t specify a database when creating or moving a mailbox, the load balancer will automatically select the database with the least number of mailboxes. Check out this post by Mike Pfeiffer to see this feature in action.

May 14, 2010 Posted by | Exchange Server 2010, Exchange Server management, Scripting, Windows PowerShell | 2 Comments

Exchange Server 2010 Cross-Forest migration

In Exchange Server 2010 we can move mailboxes between forests when a forest trust are in place. This can be accomplished using the New-MoveRequest cmdlet from the Exchange Management Shell as well as from the Exchange Management Console. Note that remote mailbox moves from legacy Exchange versions only can be accomplished from the Exchange Management Shell.
Before any move requests can be made there are some preparation that needs to be done in the target forest. The users from the source forest must be created in the target forest as mail-enabled users with some specific attributes. The mandatory attributes in addition to several others are described in this article on the Exchange Server TechCenter.

Microsoft has published a sample script, Prepare-MoveRequest, to assist with the preparation in the target forest. The script will create new mail-enabled users in the target forest with the required attributes from the source forest. While this works quite well, many administrators wants to use alternate methods such as Active Directory Migration Tool (ADMT) or Microsoft Identity Lifecycle Manager (ILM) to preserve additional attributes. Especially SIDHistory and passwords are common.
When these tools are used, the Prepare-MoveRequest script got a parameter named –UseLocalObject which tells the script to convert the local object to the required mail-enabled user. While this might work fine depending on the environment, we`ve seen several administrators reporting problems when using the Prepare-MoveRequest script after ADMT-migration. When the script doesn`t find or match any local user due to some missing attributes it rather creates new mail-enabled users. There are no switch to disable the creation of new users if a local object to use aren`t found. I did a test in a lab-environment trying to use Prepare-MoveRequest with the –UseLocalObject parameter to prepare an ADMT-migrated object. This resulted in a new user being created with some random numbers added to the displayname and samaccountname.


As an alternative to using the Prepare-MoveRequest sample script I`ve created another PowerShell-script named Invoke-MoveRequest, available from here. This script are intended for scenarios where the user objects are already migrated using e.g. ADMT. Note that you must exclude Exchange-attributes when using ADMT, otherwise attributes like msExchHomeServerName which we don`t want to be migrated will come along. Using this script we will migrate the necessary Exchange-attributes.

The script will do the following:

  1. Copy the attribute Mail from the source object to the target object
  2. Copy the attribute mailNickname from the source object to the target object
  3. Copy the attribute msExchMailboxGUID from the source object to the target object
  4. Set the attribute msExchRecipientDisplayType to –2147483642
  5. Set the attribute msExchRecipientTypeDetails to 128
  6. Copy the attribute msExchUserCulture from the source object to the target object
  7. Set the attribute msExchVersion to 44220983382016
  8. Copy the attribute proxyAddresses from the source object to the target object
  9. Set the target objects attribute targetAddress equilent to the source object`s  mail attribute
  10. Set the attribute userAccountControl to 514
  11. Run the Update-Recipient cmdlet on the target mail-enabled user to set LegacyExchangeDN and other default Exchange-attributes
  12. Create a new move request
  13. Enable the target object and unset “User must change password on next logon”

The attributes copied and set are according to the list of mandatory attributes in the TechNet-article mentioned above. The mandatory attributes like DisplayName who not are added to the script are already migrated by ADMT. I also considered adding the LegacyExchangeDN from the target object as an X500 address to the source object`s proxyaddresses to keep mail-flow between the forests after migration, however, it turns out that this are taken care of by the New-MoveRequest cmdlet.
All variables in the “Custom variables”-section on the top of the script must be set before running. The script are set up to process all users in a specified Organizational Unit in the source domain, however, you may customize this for your needs by e.g. using a CSV-file or setup some filtering using the Where-Object cmdlet. You may also copy additional attributes mentioned in the TechNet-article.
The computer you`re running the script from must have the Exchange Management Tools for Exchange Server 2010 and the free Quest PowerShell Commands for Active Directory.

The script needs additional functionality regarding logging and error-handling, I`ll update this post when I`ve done so. Feel free to further enhance the script yourself, and please let me know in the comments below if you have any suggestions.

Update 19.08.2010: Since my writing the Exchange team have posted an excellent post on Exchange 2010 Cross-Forest Mailbox Moves on their blog.

April 23, 2010 Posted by | Exchange 2003, Exchange Server 2007, Exchange Server 2010, Exchange Server management, Scripting, Windows PowerShell | | 7 Comments

Installing Exchange Server 2007/2010 Update Rollups

Have you ever tried to install an Exchange Server Update Rollup which ended with an error message?

I recently did some troubleshooting on installing Exchange Server 2010 Update Rollup 3 and picked up some experiences I would like to share, in addition to provide some general guidelines for installing Exchange Update Rollups.

The installation may fail when installing either manually by downloading the installation package or by using Windows Update. Afterwards event 1024 are logged to the application log stating that the installation failed with the error code 1603:


This really doesn`t help much, and in addition to the failed installation all Exchange-related services are now stopped and disabled, leaving the server offline.

Start by restoring the service-state. First, enable and start Windows Management Service using an elevated Windows PowerShell prompt:

Get-Service Winmgmt | Set-Service –StartupType Automatic; Get-Service Winmgmt | Start-Service

Then run the ServiceControl.ps1 located in the Exchange bin-folder and the pass it the argument “AfterPatch”:


The server should now be restored to an operational state. Next, download the Exchange Update Rollup if you haven`t done that in the first installation attempt. Next, retry the installation from the elevated PowerShell promt using msiexec with the /lv parameter:

msiexec /lv c:\temp\ex-ur3-install.log /update C:\temp\Exchange2010-KB981401-x64-en.msp

This will instruct the Windows Installer service to log verbose output from the installation to the file specified. After the installation fails you will see an event with event ID 1023 logged to the Application log:


Next, open the log-file and look through it for error messages. The output in this file are really verbose, so you might want to ask for assistance in the Exchange Software Updates Forum on the Exchange Server TechCenter.

In my recent troubleshooting incident I found the following in the log-file:


This indicates that the servicecontrol.ps1 script failed to run correctly. As stated in KB-article 981474 this is caused by the defined PowerShell execution polices. For the installation to succeed, oddly enough, any execution policies must be temporarily undefined.

To see if any PowerShell execution polices are defined on the system, run Get-ExecutionPolicy –List:


In this case, an ExecutionPolicy was defined both locally and in a Group Policy Object. I first cleared the Group Policy setting and then the local setting using the following command:


Execute gpupdate /force and verify that all the ExecutionPolicies are set to “Undefined”:


Redo the steps described above to restore service-state and retry the installation. In this case the installation now succeeded:


At the end I will provide some general guidelines for installing Update Rollups in Exchange Server 2007/2010:

  1. Use elevated Administrator-privileges when running the installation either from Windows Update or by manually downloading the installation file.
  2. Verify that all Execution Policies are set to “Undefined”.
  3. Uninstall any interim Exchange hotfixes installed since the last Update Rollup.
  4. Verify that the ExchangeSetupLogs directory are present on the system-drive. The installer uses this directory for saving service-state information.

Please leave a comment below if you got any further guidelines. I will update this blog-post if I gather more information regarding installing Update Rollups.

April 20, 2010 Posted by | Exchange Server 2007, Exchange Server 2010, Exchange Server management, Windows PowerShell | | 10 Comments

Exchange Server 2010 beta available

As stated on many blogs and websites today, a beta version of Exchange Server 2010 are now available from this link on the Microsoft Download Center.

Exchange Server 2010 Documentation are available on TechNet.

Among the things that can be found there are “What`s New in Exchange Server 2010”, “Exchange 2010 System Requirements” and “Exchange 2010 Prerequisites”.

Also check out the Exchange Server TechCenter which are updated with new Exchange 2010 content, as well as the new Exchange Server 2010 forum.

For those of you who are interested in Exchange Server I would recommend to attend the following E-Learning from Microsoft: Collection 6899: Exploring Features of Exchange Server 2010

I installed the beta version on a virtual machine running on Hyper-V tonight. You can see some screenshots below.


I started by promoting the server (running Windows Server 2008 x64 Enterprise) as a Domain Controller in a new domain (for testing purposes).
I then installed the prerequisites and started setup.exe:













Administrative tools

After installation the following appeared on the Start-menu:


The structure of the Exchange Management Console are the same as in Exchange Server 2007:


The same are true for the Exchange Management Shell:


Compared to Exchange Server 2007, who got 394 PowerShell cmdlets for administration, Exchange Server 2010 got as many as 638:



Outlook Web Access

The Outlook Web Access are also improved:


The “Options” page:



New “Phone” features (Text Messaging):


When logged on as an Exchange administrator, it`s possible to choose to manage “My Organization” instead of “Myself”. Here Mailboxes, Groups, and External Contacts can be managed.





The beta version really looks exciting, and I`ll post follow-up posts when I explore new features. Stay tuned!

April 15, 2009 Posted by | Exchange Server 2010, Exchange Server management | Leave a comment

Outlook Web Access not working after applying an Exchange 2007 Update Roll-up

I`ve just installed Update Roll-up 7 for Exchange 2007 SP1, and afterwards the Outlook Web Access showed a blank page and there was a yellow exclamation mark in the bottom left corner, which stated “syntax error on line 6 of login.aspx”.

I first tried the solution Microsoft provided in this support forum thread, although it didn`t work for me.
I had to re-create the OWA Virtual directory.

I accomplished this using these two PowerShell commands from the Exchange Management Shell:



Actually the Microsoft Exchange Team stated the following reminder in the blog post regarding Update Roll-up 7:

“And finally, from the installation perspective, a friendly reminder that the roll-up installer will overwrite any OWA script files if required to ensure proper operation of OWA. So if you have customized the logon.aspx page or other similar OWA pages, you will need to redo any customization after installation of the roll-up.”

My recommendation would be to backup the C:\Program Files\Microsoft\Exchange Server\ClientAccess\OWA folder before installing an Exchange 2007 Update Roll-up.

March 23, 2009 Posted by | Exchange Server 2007, Exchange Server management | 1 Comment

Exchange 2007 e-mail address policy error

Today I was creating a new e-mail address policy on an Exchange 2007 server, and got this message when applying the new policy:


Failed to update recipient "domain.local/Department/User 1". The following exception occurred: Exchange Server 2007 server.domain.local returned an error -2147023653 from the Address List Service..

Failed to update recipient "domain.local/Department/Distribution List 1". The following exception occurred: A proxy generator DLL on server server.domain.local could not be found or failed to initialize.  Proxy addresses for the current recipient cannot be calculated.  Please ensure that all the proxy address generator DLLs have been installed on the target server..

Failed to update recipient "domain.local/Department/User 3". The following exception occurred: Exchange Server 2007 server.domain.local returned an error -2147023653 from the Address List Service..

Failed to update recipient "domain.local/Department/User 4". The following exception occurred: Exchange Server 2007 server.domain.local returned an error -2147023653 from the Address List Service..


I didn`t find any resolution when Googling for the error number.
I then tried changing the policy from a custom format to a standard format like, and then the policy applied successfully.

When reading things like “proxy genererator DLL” I started to fear that something was wrong with missing files on the server, so I do think that this error message could have been more decriptive like “Wrong syntax in policy” or something similar.

That being said, Exchange 2007 is a great product!

January 8, 2009 Posted by | Exchange Server management | 5 Comments