There is a lot of information and guides out there about ‘Modern Public Folder” migrations, this post is steps recorded during a live migration of a public folder from Exchange 2007 to Exchange 2013.
This blog is to a real world view of migrating public folders to Exchange 2013.
Preparation
Create two folders on your ‘Legacy’ Server called “PFScripts” and “PFMigration”, I choose to keep these on the root of the C:\
Download the migration scripts:
- Export-PublicFolderStatistics.ps1
- Export-PublicFolderStatistics.strings.psd1
- PublicFolderToMailboxMapGenerator.ps1
- PublicFolderToMailboxMapGenerator.strings.psd1
Download Link Prepare for Migration
It’s recommend to take a snapshot of the current Public Folder deployment, run the following command to take a snapshot of the original source folder structure:
## Get Public Folder Structure
Get-PublicFolder -Recurse | Export-CliXML C:\PFMigration\Legacy_PFStructure.xml
Run the following command to take a snapshot of public folder statistics of the public folders:
## Get Public Folder Statistics
Get-PublicFolderStatistics | Export-CliXML C:\PFMigration\Legacy_PFStatistics.xml
Run the following command to take a snapshot of the permissions:
## Get Public Folder Permissions
Get-PublicFolder -Recurse | Get-PublicFolderClientPermission | Select-Object Identity,User -ExpandProperty AccessRights | Export-CliXML C:\PFMigration\Legacy_PFPerms.xml
If the name of a public folder contains a backslash “\” the public folders will be created in the parent public folder when migration occurs. Before you migrate its recommend that you rename any public folders that have a backslash in the name.
Locate public folders with a backslash in Exchange 2007 and 2010:
## Public Folder with “\” Exchange 2007
Get-PublicFolderDatabase | ForEach {Get-PublicFolderStatistics -Server $_.Server | Where {$_.Name -like "*\*"}}
## Public Folders with “\” Exchange 2010
Get-PublicFolderStatistics -ResultSize Unlimited | Where {$_.Name -like "*\*"} | Format-List Name, Identity
If and folders are returned it’s recommended to rename them:
## Rename Public Folder
Set-PublicFolder -Identity <public folder identity> -Name <new public folder name>
Make sure there isn’t a previous record of a successful migration. If there is, you’ll need to set that value to $false
. If the value is set to $true
the migration request will fail.
## Check for previous migration
Get-OrganizationConfig | Format-List PublicFoldersLockedforMigration, PublicFolderMigrationComplete
If the status of the PublicFoldersLockedforMigration or PublicFolderMigrationComplete properties is $true
, run the following command to set the value to $false
.
## Change PF migration status
Set-OrganizationConfig -PublicFoldersLockedforMigration:$false -PublicFolderMigrationComplete:$false
NOTE: After resetting these properties, you must wait for Exchange to detect the new settings, This may take some time to replicate.
Prerequisites for Exchange 2013
Make sure there are no existing public folder migration request:
## Check Exchange 2013 for migration request
Get-PublicFolderMigrationRequest | Remove-PublicFolderMigrationRequest -Confirm:$false
Confirm there are no public folders on Exchange 2013:
## Check Exchange 2013 has no public folders
Get-Mailbox -PublicFolder
Get-PublicFolder
If public folders are returned, run the following command to remove them:
## Remove Exchange 2013 Public Folders
Get-Mailbox -PublicFolder | Where{$_.IsRootPublicFolderMailbox -eq $false} | Remove-Mailbox -PublicFolder -Force -Confirm:$false
Get-Mailbox -PublicFolder | Remove-Mailbox -PublicFolder -Force -Confirm:$false
Generate the CSV file for migration
On the legacy Exchange server, run the Export-PublicFolderStatistics.ps1
script to create the folder name-to-folder size mapping file:
## Generate CSV file for migration
.\Export-PublicFolderStatistics.ps1 <CSV File Name> <FQDN of source server>
Run the PublicFolderToMailboxMapGenerator.ps1
script to create the public folder-to-mailbox mapping file:
## Exchange 2013 Public Folder mapping
.\PublicFolderToMailboxMapGenerator.ps1 <Maximum mailbox size in bytes> <Folder to size map path> <Folder to mailbox map path>
i.e.
.\PublicFolderToMailboxMapGenerator.ps1 1GB PFStats.csv FolderToMailbox.csv
Copy the generated file to the Exchange 2013 server
Create the public folder mailboxes on Exchange 2013
Create a new public folder mailbox on 2013:
## Exchange 2013 new public folder
New-Mailbox -PublicFolder <Name> -HoldForMigration:$true
The migration I was working wasn’t very big, so I only required a single public folder mailbox, if you require additional mailboxes run:
## Exchange 2013 additional public folder mailboxes
$numberOfMailboxes = x;
for($index =1 ; $index -le $numberOfMailboxes ; $index++)
{
$PFMailboxName = "Mailbox"+$index; if($index -eq 1) {New-Mailbox -PublicFolder $PFMailboxName -HoldForMigration:$true -IsExcludedFromServingHiearchy:$true;}else{NewMailbox-PublicFolder $PFMailboxName -IsExcludedFromServingHierarchy:$true}
}
Public Folder migration
Legacy system public folders such as OWAScratchPad and the schema-root folder subtree in Exchange 2007 won’t be recognized by Exchange 2013 and will be treated as bad items. This will cause the migration to fail. As part of the migration request, you must specify a value for the BadItemLimit parameter. This value will vary depending on the number of public folder databases you have. The following commands will determine how many public folder databases you have and compute the BadItemLimit for the migration request.
## Get 2007 Public Folder
$PublicFolderDatabasesInOrg = @(Get-PublicFolderDatabase)
## Set Bad Items
$BadItemLimitCount = 5 + ($PublicFolderDatabasesInOrg.Count -1)
Start Public folder migration (Exchange 2007):
## Start Public Folder Migration – Exchange 2007
New-PublicFolderMigrationRequest -SourceDatabase (Get-PublicFolderDatabase -Server <Source server name>) -CSVData (Get-Content <Folder to mailbox map path> -Encoding Byte) -BadItemLimit $BadItemLimitCount
Start Public folder migration (Exchange 2010):
## Start Public Folder Migration – Exchange 2010
New-PublicFolderMigrationRequest -SourceDatabase (Get-PublicFolderDatabase -Server <Source server name>) -CSVData (Get-Content <Folder to mailbox map path> -Encoding Byte)
To check the migration has started, run the following command:
## Check public folder migration
Get-PublicFolderMigrationRequest | Get-PublicFolderMigrationRequestStatistics -IncludeReport | Format-List

Once the migration reached the AutoSuspended state as shown below, proceed to the next steps, otherwise you must wait as this may take some time based on your PF size.
Lock down the public folders on the legacy Exchange server for final migration (Downtime required)
On the legacy Exchange server run the following command:
## Lock Public Folders
Set-OrganizationConfig -PublicFoldersLockedForMigration:$true
Resume\Complete the public folder migration on the Exchange 2013 server, run the following command:
## Complete public folder migration
Set-PublicFolderMigrationRequest -Identity \PublicFolderMigration -PreventCompletion:$false
Resume-PublicFolderMigrationRequest -Identity \PublicFolderMigration
I found once I started the completion process the StatusDetail reported back as StalledDueToMailboxLock:

To get this started again I restarted the ‘Information Store’ on the legacy Exchange server:

The final status changes you should see are:

and

Test and unlock
After the final migration has completed, you should test to make sure the public folder hierarchy\permissions\content are correct, create additional folders and post content to folders to confirm folders are working.
To tell a mailbox to look at the new modern folders, run the following command:
## Exchange 2013 set mailbox to modern PF
Set-Mailbox -Identity <Test User> -DefaultPublicFolderMailbox <Public Folder Mailbox Identity>
Once test have been completed and you can confirm public folders are working as they should be, you can unlock the folders for the rest of the organisation, run the following command:
## Exchange 2013 Unlock PF’s
Set-OrganizationConfig -PublicFolderMigrationComplete:$true
Modern public folder migration complete !!!
Disclaimer: All scripts and other PowerShell references on this blog are offered "as is" with no warranty. While these scripts are tested and working in my environment, it is recommended that you test these scripts in a test environment before using in your production environment.