In part 3 of the article series "Migration from Exchange 2016 to Exchange 2019", it's now time to migrate the data. Specifically, it is about moving the various mailboxes and public folders from Exchange 2016 to Exchange 2019.
I am moving the various mailbox types individually here; if no public folders or shared mailboxes (shares) are used, the corresponding points can of course be skipped. However, it is important to migrate the system mailboxes and of course the user mailboxes.
If there are only a few mailboxes, all mailboxes can be migrated in one go. The corresponding commands can then simply be entered one after the other. The MoveRequests described below are then processed accordingly.
Migration of system mailboxes
Before the mailboxes of the users and public folders are moved, the Exchange system mailboxes must first be moved to the new database. The following command can be used to display the mailboxes in the Exchange 2016 database:
get-mailbox -Database DB2016 -Arbitration
These mailboxes must now be moved to the Exchange 2019 database. The following command can be used for this:
get-mailbox -Database DB2016 -Arbitration | New-MoveRequest -TargetDatabase DB2019
The status can be checked with the following command:
Get-MoveRequest
After a short time, all MoveRequests should have the "Completed" status:
As the system mailboxes have now been moved, the move requests can be removed:
Get-MoveRequest | Remove-MoveRequest
Continue with the user mailboxes.
Migration of user mailboxes
Once the system mailboxes have been moved, you can start moving the user mailboxes.
I recommend separating user and shared mailboxes (including room and device mailboxes). As a rule, there are fewer problems when users with mailboxes on the newer Exchange version access shared mailboxes on the older Exchange version. I therefore move the shared mailboxes after the user mailboxes.
Mailboxes can generally be moved via Exchange Management Shell and Exchange Admin Center (EAC). I still use the CMDLet "New-MoveRequest" instead of the migration batches, as I have the impression that the MoveRequest is significantly faster than the migration batches (these are created by the EAC by default, but can also be created via the shell). In this example I use the shell and the CMDLet "New-MoveRequest", another example for migration batches can be found at the end of this section.
The following command can be used to display all user mailboxes in the Exchange 2016 database:
Get-Mailbox -Database DB2016 -RecipientTypeDetails UserMailbox
If all user mailboxes are to be moved from the Exchange 2016 database "DB2016" to the Exchange 2019 database "DB2019" in one go, the following command can be used:
Get-Mailbox -Database DB2016 -RecipientTypeDetails UserMailbox | New-MoveRequest -TargetDatabase DB2019
Alternatively, it is of course also possible to filter something, for example, if only user mailboxes from a specific OU are to be moved, the following command can be used:
Get-Mailbox -Database DB2016 -RecipientTypeDetails UserMailbox | where {$_.OrganizationalUnit -match "frankysweblab.de/FrankysWeb"} | New-MoveRequest -TargetDatabase DB2019
Using the WHERE-CMDLet, almost any constellation of MoveRequests can be put together here.
However the MoveRequests are set up, all user mailboxes of the Exchange 2016 databases must be moved to the Exchange 2019 databases and then also have the status "Completed":
In a fresh test environment, moving usually works without any problems, but in productive environments there are always faulty items in the mailboxes. Without the "BadItemLimit" parameter, a MoveRequest simply aborts at the first faulty item and the mailbox is not moved.
The "BadItemLimit" parameter can be used to define the number of tolerable errors; faulty items are then not copied to the new database. Defective items are therefore no longer available in the target mailbox and may have to be restored from the data backup. However, as defective items cannot be moved to the new database anyway, the only thing that usually helps here is to specify the "BadItemLimit" parameter (number of tolerable errors):
Get-Mailbox -Database DB2016 -RecipientTypeDetails UserMailbox | New-MoveRequest -TargetDatabase DB2019 -BadItemLimit 50
I have now moved all user mailboxes to the Exchange 2019 database via shell, alternatively the mailboxes can also be moved via EAC.
After the MoveRequests have been completed, they can be deleted:
Get-MoveRequest | where {$_.status -eq "Completed"} | Remove-MoveRequest
Alternative: Migration batches via EAC
Mailboxes can also be moved to the new database via the Exchange Admin Center (EAC). Here is a small example:
The mailboxes to be moved can now be selected from the list of mailboxes. With many mailboxes, this is of course quite tedious (it is therefore easier to create migration batches or MoveRequests via shell):
The new migration batch requires a freely selectable name and the target database:
Finally, you can select which user should receive a report of the migration batch. EAC already indicates that the migration batch is not for the impatient:
The new migration batch initially receives the status "Synchronization", patience is required here:
After completion, the migration batch then changes to the "Completed" status:
As soon as the migration batch is complete, it can be deleted.
Migration of shared mailboxes (including rooms and devices)
After the user mailboxes have been moved, shared mailboxes, room mailboxes and device mailboxes can also be moved. The procedure here is almost identical to the user mailboxes. Here is the command for displaying the corresponding mailboxes:
get-mailbox -Database DB2016 -RecipientTypeDetails Shared, Roommailbox, EquipmentMailbox
In this case, there is only one mailbox; a MoveRequest can now be created for this mailbox as well:
get-mailbox -Database DB2016 -RecipientTypeDetails Shared, Roommailbox, EquipmentMailbox | New-MoveRequest -TargetDatabase DB2019
As before, you can also filter or move the mailboxes via EAC if required, just like with the user mailboxes.
The MoveRequests for the shared mailboxes should also have the status "Completed" if they have been successfully moved:
The corresponding MoveRequest can now be removed again:
Get-MoveRequest | where {$_.status -eq "Completed"} | Remove-MoveRequest
Continue with the public folders.
Migration of public folders
First of all, the good news is that since there is no longer a public folder database, but public folder mailboxes were introduced with Exchange 2013, there is no longer any need to set up the annoying replication of public folders. The mailboxes for public folders can now also be easily moved using MoveRequest or Migration Batch.
The procedure is almost identical to user and shared mailboxes. Here is the command to display it:
get-mailbox -Database DB2016 -PublicFolder
And here is the command to move it:
get-mailbox -Database DB2016 -PublicFolder | New-MoveRequest -TargetDatabase DB2019
This MoveRequest also receives the status "Completed" as soon as all data has been migrated:
As soon as this was successful, this request can also be deleted:
Get-MoveRequest | where {$_.status -eq "Completed"} | Remove-MoveRequest
The only thing missing now is the Discovery Search Mailbox.
Migration Discovery Search Mailbox
The procedure for the Discovery Search Mailbox is also almost identical to the other mailboxes, here again the command for displaying:
get-mailbox -Database DB2016 -RecipientTypeDetails DiscoveryMailbox
And the move command:
get-mailbox -Database DB2016 -RecipientTypeDetails DiscoveryMailbox | New-MoveRequest -TargetDatabase DB2019
As soon as the MoveRequest has also been completed here, the request can be removed:
Get-MoveRequest | where {$_.status -eq "Completed"} | Remove-MoveRequest
All mailboxes on the Exchange 2016 server should now be moved.
Addendum
Moving the mailboxes was of course very quick for me, simply because there was hardly any data in the mailboxes. Normally, of course, moving the user, shared and possibly public folder mailboxes takes quite a long time. This depends on the items in the mailbox and the size of the mailbox. So that you can roughly estimate the speed, you should first move a few large test mailboxes. This makes it easier to estimate the total time required.
The following command also provides further statistics on the MoveRequests:
Get-MoveRequest | Get-MoveRequestStatistics
It is also not unusual for large mailboxes in particular to contain defective items; the tolerable number of defective items can be set using the "-BadItemLimit" switch. I would set the parameter to 10 items for each MoveRequest (see section "Migration of user mailboxes"). Incidentally, the value can also be set retrospectively, but this is part of the last part of this article series (coming soon).