Some tips and cmdlets to use during the migration from Exchange 2013 to Exchange 2016


During the move from Exchange 2013 to 2016 you will need to migrate mailboxes from one mailbox database to another because you cannot mix Exchange 2013 and Exchange 2016 servers in one DAG. In this post I decided to mention some best practices and useful cmdlets you may need during the move.

Some users may have large mailboxes if you are not limiting the size, that is why some our mailboxes were greater than 20GB and even 30GB. It is a good idea to ask these users to delete left junk emails. One of my users removed nearly  20GB of mails and items after my request. That was great but the size of this mailbox did not reduce because all these deleted items were moved to the Recoverable Items folder. So, here is the first best practice: ask your users to delete all unnecessary mails before the move from one database to another. If you do not want to clean up the Recoverable items folder manually it would be useful to check the retention period of the source mailbox database. If the retention period is set to 14 days, ask your users to perform a deletion in 15 days or more before the planned move. Give them some time because they are always busy and may need more time to take a look and to delete something.

Some users may clean mailboxes but it will be not enough time to clean up Recoverable Items folders and you will need to do it manually. Here is a cmdlet to check the number of deleted items in all the mailboxes:
 Get-Mailbox | Get-MailboxStatistics | Sort-Object -Descending DeletedItemCount | ft DisplayName, ItemCount, DeletedItemCount, TotalItemSize, TotalDeletedItemSize -autosize  

You may notice that the amount of deleted items for the first user in the list is quite huge (23517 items). We can check what is located in the Recoverable items folder of this user by running the following cmdlet:
 Get-MailboxFolderStatistics -Id <username> -FolderScope RecoverableItems | ft Name, FolderPath, ItemsInFolder, FolderAndSubfolderSize  

I was not able to wait for the retention period end and had to remove these items manually. To accomplish this task you need to use this cmdlet:
 Search-Mailbox -Id <username> -SearchDumpsterOnly -DeleteContent  

When you are satisfied with the mailbox sizes, you can start the migration process. You will create mailbox move requests from ECP and wait until they end. However, you may need to check how the process is going. There is a cmdlet to check all the move requests and their status details below. If you wanna check the status of Mailbox move requests which are not finished yet, you mail filter the output as shown in the second line.
 Get-MoveRequest | Get-MoveRequestStatistics | Select DisplayName, SourceDatabase, TargetDatabase, TotalMailboxItemCount, ItemsTransferred, PercentComplete, StatusDetail, TotalMailboxSize, MRSServerName | Sort-Object -Descending PercentComplete | ft -autosize  
 Get-MoveRequest | Get-MoveRequestStatistics | ?{$_.PercentComplete -ne 100} | Select DisplayName, SourceDatabase, TargetDatabase, TotalMailboxItemCount, ItemsTransferred, PercentComplete, StatusDetail, TotalMailboxSize, MRSServerName | Sort-Object -Descending PercentComplete | ft -autosize  

All these move requests were suspended because I was in need to stop the migration for a while. Here is the second best practice: do not run too much move requests and always check the amount of free space on the target server. During the move Exchange 2016 will generate a lot of mailbox database logs and your servers may run out of space. The most significant part is adding your new databases to your backups and performing full backups with log truncation. In case you need to suspend any move request just use one of the following cmdlets:
 To stop all unfinished move requests: Get-MoveRequest | ? {$_.PercentComplete -ne 100} | Suspend-MoveRequest.  
 To stop any specific move request: Get-MoveRequest | ? {$_.DisplayName -eq "<user_displayname>"} | Suspend-MoveRequest   
 To resume a specific move request: Get-MoveRequest | ? {$_.DisplayName -eq "<user_displayname>"} | Resume-MoveRequest   

I resumed one of the move requests and here is a result:

When you finish the move from Exchange 2013 to 2016, check all databases on Exchange 2013 and check if they contain any user mailboxes. If you run the following cmdlet you may notice that all users that were moved from the Exchange 2013 database are still there.
 Get-MailboxDatabase | Get-MailboxStatistics | select Displayname, ItemCount, Database | ft -autosize  

This is because these users are softdeleted from the database. You can verify that they are softdeleted by running the cmdlet shown below:
 Get-MailboxStatistics -Database MDB01 | where {$_.DisconnectReason -eq "SoftDeleted"} | select DisplayName, MailboxGUID, DisconnectReason, Database, LastLogonTime | ft -autosize  

Check the LastLogonTime column and you will find out that the last logon was before the move from one database to another was finished. You may want to remove these softdeleted mailboxes from the mailbox database. Here is a cmdlet to perform this task:
 Get-MailboxStatistics -Database MDB01 | ?{$_.DisconnectReason -eq "SoftDeleted"} | foreach {Remove-StoreMailbox -Database $_.database -Identity $_.mailboxguid -MailboxState SoftDeleted}

You need to run the cmdlet on an Exchange 2013 Server. If you run it on Exchange 2016, you will get an error, stating that the mailbox with the following GUID does not exist in the database. During the cmdlet execution you will receive confirmation request for all these mailboxes. You need to confirm each one by one because "Yes for all" option is not working.

Now you are ready to clean up Exchange after a move. Check if all migration user objects created during the move from mailbox databases on Exchange 2013 to mailbox databases on Exchange 2016 do not exist anymore. This is useful if you will need to move a user from one MDB on Exchange 2016 to another. If you do not remove migration users you will not be able to perform such move later. If you remove a migration batch these migration users should be removed but it is always a good idea to verify. Use Get-MigrationUser cmdlet to find out if any migration user exists on Exchange.

Comments