Legacy Public Folder Migration

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 Microsft. 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:

  1. Download the public folder migration scripts.
  2. Prepare your organization for the migration.
  3. Create the .csv files required for the migration.
  4. Create the public folder mailboxes on the destination server.
  5. Start the migration
  6. Lock down the public folders on the legacy server for final migration.
  7. Finalize the public folder migration.
  8. 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 scipts 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.

List the structure of the Public Folders:
[PS] C:\> Get-PublicFolder -Recurse | Export-Clixml C:\temp\legacy_pfstructure.xml
List the statistics of the public folders:
[PS] C:\> Get-PublicFolderStatistics | Export-Clixml C:\temp\legacy_pfstatistics.xml
List the permissions of the public folders:
[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.

List any public folders that contain a backslash:
[PS] C:\> Get-PublicFolderStatistics -ResultSize Unlimited | Where {$_.Name -like "*\*"} | Format-List Name, Identity
Rename any public folders that are returned from the previous command:
[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
If the command returns anything other than False, there has been a migration previously and to continue, you will need to set the True value back to False:
[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.

To check for a serial migration:
[PS] C:\> Get-PublicFolderMigrationRequest | Get-PublicFolderMigrationRequestStatistics -IncludeReport | Format-List
To check for a batch migration:
[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.

To remove a serial migration:
[PS] C:\> Get-PublicFolderMigrationRequest | Remove-PublicFolderMigrationRequest
To remove a batch migration:
[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.

We’ll start by looking for an existing public folder mailbox:
[PS] C:\> Get-Mailbox -PublicFolder

If this command doesn’t return any mailboxes then we can move on to step three.

If the command returned any mailboxes, we need to see if any public folders exist.
[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.

Delete all public folder mailboxes:
[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.

Start by running the Export-PublicFolderstatistics.ps1 script.
[PS] C:\PFMigration> .\Export-PublicFolderStatistics.ps1 C:\PFMigration\SizeMap.csv EX10
Now we will run the PublicFolderToMailboxMapGenerator.ps1 script to calculate the correct number of public folder mailboxes. We need to have an idea of what we want the max size of each public folder mailbox to be. My test environment is very small so I will use a 5GB setting and it will create only one public folder mailbox. You can use the SizeMap.csv file we just generated to list the size of each public folder and decide on a good maximum mailbox size for the public folder mailbox.
[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.

Run the script using the MailboxMap.csv file and an estimate of the number of simultaneous connections:
[PS] C:\PFMigration> .\Create-PublicFolderMailboxesForMigration.ps1 -FolderMappingCsv MailboxMap.csv -EstimatedNumberOfConcurrentUsers 5

Step Five: Start the batch migration

On the destination Exchange server create the migration request:
[PS] C:\> New-MigrationBatch -Name PFMigration -SourcePublicFolderDatabase (Get-PublicFolderDatabase -Server EX10) -CSVData (Get-Content C:\PFMigration\MailboxMap.csv -Encoding Byte) -NotificationEmail mkrause@leenu.net
Start the batch migration:
[PS] C:\> Start-MigrationBatch PFMigration
Monitor the migration progress until the status shows “synced”:
[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.

Lock the public folders on the legacy server:
[PS] C:\> Set-OrganizationConfig -PublicFoldersLockedForMigration:$true

Step Seven: Finalize the public folder migration

On the destination Exchange server set the deployment type to remote:
[PS] C:\> Set-OrganizationConfig -PublicFoldersEnabled Remote
Complete the migration:
[PS] C:\> Complete-MigrationBatch PFMigration

Step Eight: Test access and unlock the migration

To test, we will set one mailbox in the new environment to use the newly migrated public folders:
[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.
If we discover any issues, we will need to roll back the migration. If the public folder looks and functions correctly, we can proceed to unlock the migrated public folders for all users:
[PS] C:\> Get-Mailbox -PublicFolder | Set-Mailbox -PublicFolder -IsExcludedFromServingHierarchy $false
On the legacy Exchange server mark the migration as complete:
[PS] C:\> Set-OrganizationConfig -PublicFolderMigrationComplete:$true
Finally, on the destination Exchange server run the command:
[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.

On the source server, unlock the legacy public folders:
[PS] C:\> set-OrganizationConfig -PublicFoldersLockedForMigration:$false
On the destination Exchange server, remove the public folders:
[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
Finally, make sure the legacy Exchange server knows the migration is not complete:
[PS] C:\> Set-OrganizationConfig -PublicFolderMigrationComplete:$false