Migrating public folders during an Exchange upgrade can be very intimidating. There are so many scripts and PowerShell commands that if something is missed it can cause you some pretty serious headaches. Exchange 2013 and 2016 both support public folders in the modern public folder format, but to migrate from legacy to modern public folders requires us to run a batch migration. Previously, Microsoft supported a serial migration, but that has been depreciated and is no longer supported by Microsoft. The batch migration method is now how we have to accomplish the migration.
A batch migration has a few requirements that we should be aware of.
- The source public folders have to be running on Exchange 2010 SP3 RU8 or greater.
- 500,000 public folders is the max number of public folder moves able to be moved in a single batch migration.
- You need to be a member of the Organization Management role group to perform the migration.
- You should move all users to Exchange 2013/2016 first as mailboxes hosted on Exchange 2010 can’t access public folders hosted on Exchange 2013/2016.
Now that we have the requirements, we can look at the actual migration. There are several steps required to perform the public folder migrations. In summary the process is as follows:
- Download the public folder migration scripts.
- Prepare your organization for the migration.
- Create the .csv files required for the migration.
- Create the public folder mailboxes on the destination server.
- Start the migration
- Lock down the public folders on the legacy server for final migration.
- Finalize the public folder migration.
- Test access and unlock the public folders.
Step One: Download the migration scripts
Download the migration scripts from Microsoft, and place them on the legacy Exchange server. All the scripts except for one will be run from the legacy server using the EMS. I will point out which script to move to the destination server when I come to it.
Step Two: Prepare your Organization
Legacy Exchange Server
We will start by running three separate commands on the legacy Exchange server to create some .XML files with the structure, statistics and permissions of the public folders. We can use these files once the migration is complete to verify a successful migration.
[PS] C:\> Get-PublicFolder -Recurse | Export-Clixml C:\temp\legacy_pfstructure.xml
[PS] C:\> Get-PublicFolderStatistics | Export-Clixml C:\temp\legacy_pfstatistics.xml
[PS] C:\> Get-PublicFolder -Recurse | Get-PublicFolderClientPermission | Select-Object Identity,User -ExpandProperty AccessRights | Export-CliXML C:\temp\legacy_pfpermissions.xml
During the migration, any public folders that have a backslash ‘\’ in the name will be placed in the root public folder by default. Microsoft recommends that you rename any folders that contain a backslash in the name.
[PS] C:\> Get-PublicFolderStatistics -ResultSize Unlimited | Where {$_.Name -like "*\*"} | Format-List Name, Identity
[PS] C:\> Set-PublicFolder -Identity PFidentity -Name newPFname
Now we need to make sure there aren’t any previous records of public folder migrations:
[PS] C:\> Get-OrganizationConfig | Format-List PublicFoldersLockedforMigration, PublicFolderMigrationComplete
[PS] C:\> Set-OrganizationConfig -PublicFoldersLockedforMigration:$false -PublicFolderMigrationComplete:$false
You should note, that if you had to change the values from True to False, there can be up to a 2 hour wait before the settings are fully propagated in your environment.
Destination Exchange Server
The first thing that we will need to know if is there has been any previous public folder migration requests on our destination Exchange server. Chances are that you will know this answer, but if you are unsure we can check for both batch migrations or for older unsupported serial migrations.
[PS] C:\> Get-PublicFolderMigrationRequest | Get-PublicFolderMigrationRequestStatistics -IncludeReport | Format-List
[PS] C:\> Get-MigrationBatch | ?{$_.MigrationType.ToString() -eq "PublicFolder"}
If there are previous migrations of either type, we have to remove them or our current migration will fail.
[PS] C:\> Get-PublicFolderMigrationRequest | Remove-PublicFolderMigrationRequest
[PS] C:\> $batch = Get-MigrationBatch | ?{$_.MigrationType.ToString() -eq "PublicFolder"}
[PS] C:\> $batch | Remove-MigrationBatch -Confirm:$false
Now that we have cleaned up any previous migration requests, we need to make sure the destination server is ready and doesn’t have any existing public folders. Since we are moving to modern public folders a public folder mailbox is required.
[PS] C:\> Get-Mailbox -PublicFolder
If this command doesn’t return any mailboxes then we can move on to step three.
[PS] C:\> Get-PublicFolder
If there are any existing public folders returned, we will have to remove them in order to continue. Before proceeding, make sure you save all the info in the public folders by exporting the data to a .pst as they will be be permanently deleted.
[PS] C:\> Get-Mailbox -PublicFolder | where{$_.IsRootPublicFolderMailbox -eq $false} | Remove-Mailbox -PublicFolder -Force -Confirm:$false
[PS] C:\> Get-Mailbox -PublicFolder | Remove-Mailbox -PublicFolder -Force -Confirm:$false
Step Three: Create the .CSV files
To create the .CSV files for the migration we will have to use the scripts that we downloaded to the legacy Exchange server earlier.
[PS] C:\PFMigration> .\Export-PublicFolderStatistics.ps1 C:\PFMigration\SizeMap.csv EX10
[PS] C:\PFMigration> .\PublicFolderToMailboxMapGenerator.ps1 5000000000 c:\PFMigration\SizeMap.csv c:\PFMigration\MailboxMap.csv
Step Four: Create the public folder mailboxes on the destination Exchange server
To create the public folder mailbox on the destination server we will use the Create-PublicFolderMailboxesForMigration.ps1 script downloaded earlier. Move that script and the MailboxMap.csv file to the destination Exchange server. If you want to rename the databases from the default names the script creates, you can open the MailboxMap.csv file and rename the databases there.
[PS] C:\PFMigration> .\Create-PublicFolderMailboxesForMigration.ps1 -FolderMappingCsv MailboxMap.csv -EstimatedNumberOfConcurrentUsers 5
Step Five: Start the batch migration
[PS] C:\> New-MigrationBatch -Name PFMigration -SourcePublicFolderDatabase (Get-PublicFolderDatabase -Server EX10) -CSVData (Get-Content C:\PFMigration\MailboxMap.csv -Encoding Byte) -NotificationEmail mkrause@leenu.net
[PS] C:\> Start-MigrationBatch PFMigration
[PS] C:\> Get-MigrationBatch PFMigration
Step Six: Lock down public folders on the legacy Exchange server for the final migration
This step requires downtime for public folders. Clients will no longer be able to access the public folders during this process. Any mail sent to mail enabled public folders will be queued until the migration is complete.
[PS] C:\> Set-OrganizationConfig -PublicFoldersLockedForMigration:$true
Step Seven: Finalize the public folder migration
[PS] C:\> Set-OrganizationConfig -PublicFoldersEnabled Remote
[PS] C:\> Complete-MigrationBatch PFMigration
Step Eight: Test access and unlock the migration
[PS] C:\> Set-Mailbox -Identity ablake@leenu.net -DefaultPublicFolderMailbox PublicFolders
We can now log in using this account to make sure the migrated public folders are working correctly. We will want to verify:
- The public folder hierarchy.
- The public folder permissions.
- The ability to create/delete public folders.
- The ability to create and delete content in the public folders.
[PS] C:\> Get-Mailbox -PublicFolder | Set-Mailbox -PublicFolder -IsExcludedFromServingHierarchy $false
[PS] C:\> Set-OrganizationConfig -PublicFolderMigrationComplete:$true
[PS] C:\> Set-OrganizationConfig -PublicFoldersEnabled Local
To determine if the migration worked, we can run the same scripts from step 1 on the destination Exchange server and compare them to the .xml files created from the legacy server. If everything matches we know the migration was successful.
Now that everything has been confirmed working and we have determined a successful migration was performed, go back to the legacy server and remove the public folder databases.
How to roll back
If something goes wrong you may need to roll back the migration. To accomplish this, we just need to unlock the legacy public folders, remove the failed public folders on the destination server, and tell the environment that the migration is not complete.
You should be aware, that any mail send to mail-enabled public folders, or content added to public folders will be lost when you delete the public folders. If you need to keep this data, you should export the data to a .pst and then import the data to the legacy public folders after the rollback has been completed.
[PS] C:\> set-OrganizationConfig -PublicFoldersLockedForMigration:$false
[PS] C:\> get-Mailbox -PublicFolder | Where{$_.IsRootPublicFolderMailbox -eq $false} | Remove-Mailbox -PublicFolder -Force -Confirm:$false
[PS] C:\> Get-Mailbox -PublicFolder | Remove-Mailbox -PublicFolder -Force -Confirm:$false
[PS] C:\> Set-OrganizationConfig -PublicFolderMigrationComplete:$false