Migrating Public Folders from 2010 to 2016

By Chris Blackburn

A little over 5 years ago I wrote a blog on how to migrate public folders from Exchange 2007 to 2010, hoping that that would be the last migration path that would be needed for the long standing public folder system. Surprise! Exchange 2013 brought along “Public Folder Mailboxes”, which brought new life into the age old structure, and killed off the dreaded replica process in lieu of DAG replication. On top of this new process has brought some new headache, as well as some old ones that have been around since Exchange 2003. We’re going to try and tackle those problems before we get down to the actual process of migration.

But let’s jump ahead before we come back and look at the age old issue of public folder migrations: mail-enabled public folders. The issue that has stemmed back to the older days of Exchange is how the Alias field allowed use of what are now seen as invalid characters. Sure the Technet article for migrating public folders gives us a script for searching for forward slashes but not invalid characters, which you may still see from environments migrated from Exchange 2003


When you mail-enable a public folder pre-Exchange 2010, it would create these as Public Folder objects in Active Directory under the Default naming context | Microsoft Exchange System Objects. As you can see on the left in the Public Folder Management Console, the mail enabled public folders, indicated by a folder with an envelope on it, correspond to the object on the left in AD.


If we open Exchange Powershell on Exchange 2010, we can find these any folders with illegal characters rather quickly:

Get-MailPublicFolder -ResultSize Unlimited | Where-Object{$_.alias -match ‘\s’}

Error: Property expression “RA (Malcolm) 2009-19” isn’t valid. Valid values are: Strings formed with characters from A to Z (uppercase or lowercase), digits from 0 to 9, !, #, $, %, &, ‘, *, +, -, /, =, ?, ^, _, `, {, |, } or ~. One or more periods may be embedded in an alias, but each period should be preceded and followed by at least one of the other characters. Unicode characters from U+00A1 to U+00FF are also valid in an alias, but they will be mapped to a best-fit US-ASCII string in the e-mail address, which is generated from such an alias.

This can quickly return a LOT of errors that correspond not only to illegal characters. Some of these are completely normal and have to do with the original Offline Address Book and it’s traditional Public Folder distribution method.


Others can also return issues with the public folders themselves. One in particular that I found was:

WARNING: Could not convert property OnPremisesObjectGuid to type Guid. Byte array for GUID must be exactly 16 bytes long.


Sure enough, these were mail-enabled folders as well. I’m not sure what the origin of these are but in this instance the Public Folder AD object also had a numerical string behind it.


In this case, it was easiest just to Mail Disable the folder itself. These folders had not been used in a long time and my guess is thru moving these between the hierarchy to different folders caused some issues.


Thanks to https://technicallycreative.wordpress.com/2010/09/27/remove-spaces-from-mail-enabled-public-folder-aliases/ there’s a great little script that can do a lot of the Alias cleanup for you

ForEach ($folder in (get-mailpublicfolder -ResultSize Unlimited | Where-Object{$_.alias -match ‘\s’}))

#check for a space
if ($folder.alias -match ‘\s’)
#determine new alias
$newAlias = $folder.WindowsEmailAddress.replace(“@domain.com”,””)
$newAlias = $newAlias -replace ‘\s|,|\.|\-‘;$_

#resize long PF aliases to below 32 characters
if($newAlias.Length -gt 31) { $newAlias = $newAlias.Substring(0,31)}

#rename PF alias
Set-MailPublicFolder -Identity $folderObject.WindowsEmailAddress -Alias $newAlias

Before you start the public folder migration, and before you even start migrating mailboxes, set your organization config to use remote public folders. The public folders listed here would be mailboxes that exist on a database that also exists on your public folder servers. In some cases, you may need to deploy and configure the CAS role as well as create a mailbox. I go into this in  one of my other blogs

Run the following Powershell commands from the Exchange 2016 management shell!

Set-OrganizationConfig -PublicFoldersEnabled Remote -RemotePublicFolderMailboxes ProxyMailbox1,ProxyMailbox2,ProxyMailbox3

This way your moved users can still access public folders from the same database that your non-moved users exist on.

Once this has been completed we can start on the migration process!

Create a folder on the Exchange 2010 & Exchange 2016 server called PFMIgration.
This is where we’ll dump the migration files to.

Download the public folder migration scripts to C:\PFMigration on each server
Grab these from:

The first 3 commands perform a backup of the structure in case we need to validate against any issues later on.

Run the following Powershell commands from the Exchange 2010 management shell

The first command takes the public folder structure and exports it to XML

Get-PublicFolder -Recurse | Export-CliXML C:\PFMigration\Legacy_PFStructure.xml

The second command takes the public folder statistics and exports it to XML

Get-PublicFolderStatistics -Resultsize Unlimited | Export-CliXML C:\PFMigration\Legacy_PFStatistics.xml

The third command takes the public folder permissions and exports it to XML

Get-PublicFolder -Recurse | Get-PublicFolderClientPermission | Select-Object Identity,User -ExpandProperty AccessRights | Export-CliXML C:\PFMigration\Legacy_PFPerms.xml

Now let’s run our scripts to export the configuration data.
Change to the C:\PFMigration in Powershell (if you haven’t already)

The first command exports the folder structure and size.
Be sure to enter your Exchange Public Folder server’s FQDN:

./Export-PublicFolderStatistics.ps1 “c:\PFMigration\FolderSize.csv” “EXCHANGE.DOMAIN.COM

Now here’s the tricky part, and it’s each Public Folder mailbox size. Based on how large you set this will determine how big the Public Folder mailboxes are. And based on how much data you have, this will determine how many mailboxes it creates. It reads the FolderSize.csv to determine how many mailboxes to create, which gets set in PFMailbox.csv.

./PublicFolderToMailboxMapGenerator.ps1 20000000000 “c:\PFMigration\FolderSize.csv” “c:\PFMigration\PFMailbox.csv”

The next piece takes the number of estimated Public Folder mailboxes and creates the migration path. Take your rough number of users in the environment.and divide this by the number of mailboxes listed in PFMailbox.csv

Run the following Powershell commands from the Exchange 2016 management shell!

.\Create-PublicFolderMailboxesForMigration.ps1 -FolderMappingCsv c:\PFMigration\PFMailbox.csv -EstimatedNumberOfConcurrentUsers:200

Finally we create our migration batch.
Be sure to enter your Exchange Public Folder server’s FQDN:

New-MigrationBatch -Name PFMigration -SourcePublicFolderDatabase (Get-PublicFolderDatabase -Server EXCHANGE.DOMAIN.COM) -CSVData (Get-Content “c:\PFMigration\PFMailbox.csv” -Encoding Byte)

With the batch’s created, now we start the process of filling the Public Folder mailboxes with the content from the Exchange 2010 server.

Start-MigrationBatch PublicFolderMigration

And now we come around full circle. Based on how the migration batch runs it will either run until it hits a Synced state, or come back with errors due to the folder structure as we discussed. Troubleshoot here as necessary.

When synced, we lock the public folder hierarchy.

Run the following Powershell commands from the Exchange 2010 management shell

Set-OrganizationConfig -PublicFoldersLockedForMigration:$true

Next, the Technet article calls for you to set your public folders to remote but doesn’t have you specify the public folder mailbox. But if you followed the guidance here on to do this BEFORE starting the process, you’re ahead of the game and ready to finish the process.

Run the following Powershell commands from the Exchange 2016 management shell!

Complete-MigrationBatch PublicFolderMigration

Then, configure your test mailbox to use the public folder mailbox. The Public Folder Mailbox Identity here is typically Mailbox1 but you can find this thru the Exchange Admin Center under Public Folder / Public Folder Mailbox.

Set-Mailbox -Identity <Test User> -DefaultPublicFolderMailbox <Public Folder Mailbox Identity>

Run thru the gamut of testing here – make sure the folders are accessible, permissions are in place, mail-enabled public folders still accept email, etc.

If all is good, flip over the public folders

Get-Mailbox -PublicFolder | Set-Mailbox -PublicFolder -IsExcludedFromServingHierarchy $false

Now, Run the following Powershell commands from the Exchange 2010 management shell

Set-OrganizationConfig -PublicFolderMigrationComplete:$true

Then finally, Run the following Powershell commands from the Exchange 2016 management shell!

Set-OrganizationConfig -PublicFoldersEnabled Local

Once this is done’ you’re ready to decommission that old Exchange 2010 server  😎

Share your thoughts