10 min read

The concept of the mailbox is the core feature of any Exchange solution, and it’s likely that almost everything you do as Exchange administrator will revolve around this component. Change 2010 SP1 includes several new cmdlets that make life much easier for any Exchange administrator, allowing you to do just about anything you can think of when it comes to managing mailboxes through scripts and one-liners. This includes tasks such as moving, importing, exporting, removing, and reconnecting mailboxes, just to name a few.

Read more: 

Performing some basic steps

To work with the code samples in this article, follow these steps to launch the Exchange Management Shell:

  1. Log onto a workstation or server with the Exchange Management Tools installed.
  2. Open the Exchange Management Shell by clicking on Start | All Programs | Exchange Server 2010.
  3. Click on the Exchange Management Shell shortcut.

Reporting on the mailbox size

Using cmdlets from both the Exchange Management Shell and Windows PowerShell gives us the ability to generate detailed reports. In this recipe, we will use these cmdlets to report on all of the mailboxes within an organization and their total size.

How to do it…

  1. Use the following one-liner to generate a report of each mailbox in the organization and the total mailbox size:

    Get-MailboxDatabase | Get-MailboxStatistics |
    ?{!$_.DisconnectDate} |
    Select-Object DisplayName,TotalItemSize

  2. Pipe the command even further to export the report to a CSV file that can be opened and formatted in Excel:

    Get-MailboxDatabase | Get-MailboxStatistics |
    ?{!$_.DisconnectDate} |
    Select-Object DisplayName,TotalItemSize |
    Export-CSV c:mbreport.csv -NoType


How it works…

In both commands, we’re using the Get-MailboxDatabase cmdlet to pipe each database in the organization to the Get-MailboxStatistics cmdlet . Notice that in the next stage of the pipeline we are filtering on the DisconnectDate propert y. Inside the filter we are using the exclamation (!) character, which is a shortcut for the -not operator in PowerShell. So we are basically saying, give me all the mailboxes in the organization that are not in a disconnected state. This can be standard mailboxes as well as archive mailboxes. We then select the DisplayName and TotalItemSize properties that give us the name and total mailbox size of each mailbox.

There’s more…

When using the first example to view the mailboxes and their total size, you will see the output in the shell is similar to the following screenshot:

Microsoft Exchange Server 2010 Windows PowerShell tutorial

Here you can see that we get the total size in megabytes as well as in bytes. If you find that this additional information is not useful, you can extend the previous one-liner using a calculated property:

Get-MailboxDatabase | Get-MailboxStatistics |
?{!$_.DisconnectDate} |
Select-Object DisplayName,
@{n=”SizeMB”;e={$_.TotalItemSize.value.ToMb()}} |
Sort-Object SizeMB -Desc

Running the preceding one-liner will provide output similar to the following:

Microsoft Exchange Server 2010 Windows PowerShell tutorial

Notice that we now have a custom property called SizeMB that reports only the mailbox size in megabytes. We have also sorted this property in descending order and the mailboxes are now listed from largest to smallest. You can continue to pipe this command down to the Export-CSV cmdlet to generate a report that can be viewed outside of the shell.

Working with move requests and performing mailbox moves

Even if you performed mailbox moves with PowerShell in Exchange 2007, it’s important that you understand that the process is completely different in Exchange 2010 SP1. There is a new set of cmdlets available for performing and managing mailbox moves, and the previously-used Move-Mailbox cmdlet no longer exists. The architecture used by Exchange to perform mailbox moves uses a new concept known as move requests, which have been implemented in this latest version. In this recipe, you will learn how to manage move requests from the Exchange Management Shell.

How to do it…

To create a move request and move a mailbox to another database within the Exchange organization, use the New-MoveRequest cmdlet, as shown next:

New-MoveRequest -Identity testuser -TargetDatabase DB2

How it works…

Mailbox moves are performed asynchronously with this new method and, unlike using the Move-Mailbox cmdlet in Exchange 2007, the New-MoveRequest cmdlet d oes not perform the actual mailbox move. Mailbox moves are handled by Client Access Servers (CAS) that run the Mailbox Replication Service (MRS). This is a major improvement because mailbox data does not move through an administrative workstation when performing a move; instead, the CAS servers are responsible for transferring the data from one database to another. Not only does this make mailbox moves faster, but it also allows you to kick off one or more mailbox moves from any machine in the organization. You can later check on the status of those move requests from any other machine with PowerShell or the Exchange Management Tools installed.

When you create a new move request with the New-MoveRequest cmdlet, the command places a special message in the target mailbox database’s system mailbox. The MRS scans the system mailboxes on a regular basis looking for queued mailbox move requests and, once they are found, the MRS will start the move process. Once the move has been completed, a record of the mailbox move is saved and can be viewed using the Get-MoveRequest cmdlet.

This recipe only covers local move requests that are performed within an Exchange organization. It is possible to use the New-MoveRequest cmdlet t o perform a mailbox move across Active Directory forest boundaries. For more details, see Managing Remote Move Requests on TechNet at the following URL: http://technet.microsoft.com/en-us/library/ff841978.aspx.

If you will be automating mailbox moves using the Exchange Management Shell, it is likely that you will be doing so in bulk. The following example shows how you can move all of the mailboxes from one database to another:

Get-Mailbox -Database DB1 | New-MoveRequest -TargetDatabase DB2

In this example, we are retrieving all of the mailboxes in the DB1 database and creating a new move request for each one that will then be moved to the target database of DB2. The -TargetDatabase parameter is actually an optional parameter. If you have multiple mailbox databases in your organization, you can omit the -TargetDatabase parameter in the previous command, and the mailboxes will be moved evenly across the available mailbox databases, as long as those databases have not been suspended or excluded from provisioning and as long as the Mailbox Resources Management Agent is enabled, which is the default setting.

There’s more…

In order to view detailed information about move requests, you can use the Get-MoveRequestStatistics cmdlet. This will return a great deal of useful information for a given move request such as the move status, percent complete, the total bytes transferred, and more. You can also use the -IncludeReport, switch parameter when running the cmdlet to provide a debug level details for mailbox moves. This can be very beneficial when troubleshooting an issue.

One of the greatest uses of this cmdlet is reporting on the current status of mailbox moves in progress, especially during large migrations. The following one-liner can be used to gather the statistics for the currently-running mailbox moves and can be run periodically throughout the migration to check the status:

Get-MoveRequest |
?{$_.Status -ne ‘Completed’} |
Get-MoveRequestStatistics |
select DisplayName,PercentComplete,BytesTransferred

The preceding command would produce an output for each mailbox similar to the following screenshot:

Microsoft Exchange Server 2010 Windows PowerShell tutorial

In this example, we’re selecting just a few of the properties from the output of the command. Alternatively, it may be useful to export this information to a CSV file or to mail the results to an administrator mailbox. Either way, it gives you a method for monitoring the status of your mailbox moves interactively in the shell or through an automated script.

If you just want to do some basic interactive monitoring from the shell to determine when all moves are complete, you can use the following code:

while($true) {
Get-MoveRequest| ?{$_.Status -ne ‘Completed’}
Start-Sleep 5

The output from this command will give you a view of all the incomplete move requests and will refresh every five seconds. This is done by using an endless while loop th at runs Get-MoveRequest, waits for five seconds, clears the screen, and starts over again. Once all moves are completed, just press Ctrl + C to break out of the loop.

Removing the move requests

You cannot perform a move request for a mailbox if there is an existing move request associated with that mailbox. This is true regardless of the move request status, whether it is complete, pending, cancelled, or failed. You can use the Remove-MoveRequest to delete an existing move request for a single mailbox, using the following syntax:

Remove-MoveRequest -Identity testuser -Confirm:$false

If you perform frequent moves you may find it necessary to regularly delete all existing move requests in the organization. To do this, use the following command:

Get-MoveRequest -ResultSize Unlimited |
Remove-MoveRequest -Confirm:$false

Keep in mind that stored move requests can provide detailed information that can be used for monitoring or generating reports for mailbox moves. Make sure you no longer need this information before removing these move requests from your organization.

Moving the archive mailboxes

Consider the following example. The testuser account has a mailbox in the DB1 database, and also a personal archive mailbox in the DB1 database. We can use the following command to move testuser to DB2:

New-MoveRequest testuser -TargetDatabase DB2

In this case, both the primary mailbox and the archive mailbox will be moved to DB2. We can customize this behaviour by using some additional parameters made available by the New-MoveRequest cmdlet. For example, if we wanted to only move this user’s primary mailbox and leave the archive mailbox in its current location, we could use the following command:

New-MoveRequest testuser -TargetDatabase DB2 -PrimaryOnly

This command adds the -PrimaryOnly switch parameter, w hich will indicate to the New-MoveRequest cmdlet th at we do not want to move the archive mailbox but we do want to move the primary mailbox to the DB2 database. Use the following command to move only the archive mailbox:

New-MoveRequest testuser -ArchiveOnly -ArchiveTargetDatabase DB2

This time, we have added the -ArchiveOnly switch parameter so that only the archive mailbox will be moved. The -ArchiveTargetDatabase is also used to specify that we want to move the archive mailbox to the DB2 database.

Moving the mailboxes in batches

When performing migrations or moving multiple mailboxes in bulk, it can be useful to move them in batches. The New-MoveRequest cmdlet pr ovides a -BatchName parameter to group multiple mailbox moves into a single, logical collection. Let’s say that we are migrating multiple mailboxes to several different databases and we want to easily track the mailbox moves based on a certain criteria:

$mailboxes = Get-Mailbox `
-RecipientTypeDetails UserMailbox `
-Database DB1 |
Get-MailboxStatistics |
?{$_.TotalItemSize -gt 2gb}
$mailboxes | %{
New-MoveRequest -Identity $_.DisplayName `
-BatchName ‘Large Mailboxes’ `
-TargetDatabase DB2

Here we are retrieving all mailboxes in the DB1 database that are larger than two gigabytes and storing the results in the $mailboxes variable. We then pipe the $mailboxes object to the ForEach-Object cmdlet (u sing the % alias) and loop through each item. As each mailbox in the collection is processed within the loop, we create a new move request for that mailbox, indicating that it should be included in the Large Mailboxes batch and moved to the DB2 database. At this point, we can easily track the moves in the batch using a simple one-liner:

Get-MoveRequest -BatchName ‘Large Mailboxes’

The preceding command will return each move request included in the Large Mailboxes batch and will provide several details including the display name, move status, and target database.

Moving mailboxes with corrupt items

When migrating from a previous version of Exchange, or when migrating large mailboxes, it’s not uncommon to run into problems with users that have corrupted items in their mailbox. You can use the -BadItemLimit parameter to specify the acceptable number of corrupt, or “bad”, items to skip when performing a mailbox move. Keep in mind that if you set the -BadItemLimit parameter to a value higher than 50 then you need to also use the -AcceptLargeDataLoss switch parameter, as shown in the following example:

New-MoveRequest -Identity testuser `
-BadItemLimit 100 `
-AcceptLargeDataLoss `
-TargetDatabase DB2

When executing this command, a move request will be created for the testuser mailbox. Up to 100 corrupt items in the source mailbox will be allowed in order to perform a successful move to the new database. You will see a warning in the shell when using these parameters and any corrupt items found in the source mailbox will be skipped when the mailbox is moved.

Subscribe to the weekly Packt Hub newsletter

* indicates required


Please enter your comment!
Please enter your name here