Quick Powershell Stuff 31

After Microsoft switched over to Modern Public Folders, I never thought I would have to worry or dig into the underworkings as much as we did in Exchange 2010 and before. I have been proven wrong twice now. My current issue is a corruption issue where I am unable to currently move certain mailboxes, even the main Primary Hierarchy mailbox, to another database. The server is displaying all the classic signs of a storage/hard drive problem with ESE errors and write or read errors in the Application log.

What I wanted to showcase here were a couple of sample PowerShell one-liners and scripts used to move Public Folder mailboxes and Public Folders as well as monitoring the progress of these moves.

Move Public Folder Mailbox
This is an easy one to work with. If we have a Public Folder mailbox and we need to move this mailbox to another database, possible on another DAG in the Exchange environment, the move cmdlet is very similar to that of a regular mailbox move:

New-MoveRequest -Identity PFMailbox01 -TargetDatabase PF1 -SuspendWhenReadyToComplete -BadItemLimit 10

Now, in my case, we were having issues with moving mailboxes and database corruption and thus wanted these moves to go as fast as possible. This required an additional parameter which adjusts the job priority to a state of ‘Emergency, like so:

New-MoveRequest -Identity PFMailbox01 -TargetDatabase PF1 -Priority emergency -SuspendWhenReadyToComplete -BadItemLimit 10

Additionally, if you want to ignore any corrupt items and there are a lot of these, we can raise the BadItemLimit to 50 possibly. If the BadItemLimit is raised to far we also need to add a switch called ‘AcceptLargeDataLoss’ which would look like this:

New-MoveRequest -Identity PFMailbox01 -TargetDatabase PF1 -Priority emergency -SuspendWhenReadyToComplete -BadItemLimit 100 -AcceptLargeDataLoss

Move Public Folders
Now while we can move entire mailboxes, sometimes we need to move just folders. Within Modern Public Folders there is a set of PowerShell cmdlets to handle this. One thing to keep in mind is that there can only be one Public Folder move request at a time in Exchange. You need to wait for that request to complete before it can be deleted and a new one can be created. There is also a limit to how many Public Folders that can be moved at a time as well. The move limit is ambiguous, but when you reach the limit, you will know:

I was not able to find exactly the limit, but this error occurred with 1700 and 3000 folders chosen for a single move. I eventually was able to reduce the size of the request and got past this. How did I do this? By selectively moving Public Folders by name like so:

$Folders = get-publicfolder '\' -recurse | where {$_.ContentMailboxName -eq 'PFMailbox01'} | Where {$_.Name -like "a*"}
New-PublicFolderMoveRequest -TargetMailbox PFMailbox05 -Folders $Folders -BadItemLimit 10

After cycling though the letters of the alphabet, the folders that were left numbered around 1000 and then I was able to take all of the folders left in the Public Folder mailbox and moved them. Don’t forget to clear out old Public Folder move requests:

Get-PublicFolderMoveRequest | Remove-PublicFolderMoveRequest

Public folder Migration Script
If you want a more visual way to monitor the progress, you can use a script like this:

$Counter = 1
Do {
    $Stats = Get-PublicFolderMoveRequest | Get-PublicFolderMoveRequestStatistics
    $Status = $Stats.Status
    $StatusDetail = $Stats.StatusDetail
    $SyncStage = $Stats.SyncStage
    $BadItems = $Stats.BadItemsEncountered
    $BadItemLimit = $Stats.BadItemLimit
    If ($Status -eq 'Completed') {
        Write-Host ' '
        Write-Host 'COMPLETED!!' -ForegroundColor Green
        Write-Host ' '
    If ($Status -eq 'Failed') {
        Write-host ' '
        Write-host 'FAILED!' -ForegroundColor Red
        Write-host ' '
        Get-PublicFolderMoveRequest | Get-PublicFolderMoveRequestStatistics | ft status*,Failure* -auto
        Write-host ' '

    $Report = Get-PublicFolderMoveRequest | Get-PublicFolderMoveRequestStatistics -IncludeReport | Select Report
    $Test = $Report.Report.Entries
    $Test2 = $Test.LocalizedString
    $AllEntries = $Test2.LocalizedString | select LocalizedString

    #Last Lines
    $LastEntry = $AllEntries[-1]
    $AllSplit = $LastEntry -Split(' ')

    Write-Host 'Current Status:' -ForegroundColor Green
    $Value1 = $AllSplit[8]
    $Value2 = $AllSplit[9]
    $Value3 = $AllSplit[-3]
    $Value4 = $AllSplit[-2]

    $Test = $Value1 -match "[0-9]\.[0-9]*"
    # Write-Host "Value1 is $Value1"
    # Write-Host "Test = $Test"
    # $Test = $True
    If ($Test) {

        Write-Host "$Status --> $StatusDetail" -ForegroundColor Cyan
        Write-Host "Data Copied:      $Value1 $Value2" -ForegroundColor White
        Write-Host "Folder progress:  $Value3 $Value4" -ForegroundColor White
        Write-Host "Bad Items Found:  $BadItems" -ForegroundColor Yellow
    If (!$Test) {
        $EndValueCheck = '*Percent complete: 95.'
        $EndValueCheck2 = '*Final sync has started.'
        If (($LastEntry -like $EndValueCheck) -or ($LastEntry -like $EndValueCheck2)) {
            Write-Host 'Migration at 95%.  Folder migrations are finalizing....' -ForegroundColor Yellow
            Write-Host "$Status --> $StatusDetail" -ForegroundColor Cyan
            $NFCounter = 0
            $FCounter = 0
            $FolderList = (Get-PublicFolderMoveRequest |Get-PublicFolderMoveRequestStatistics ).FolderList
            $TotalFolders = $FolderList.Count
            Foreach ($Line in $FolderList) {$TestValue = $Line.IsFinalized;If ($TestValue -like 'Tr*') {$FCounter++}}
            Foreach ($Line in $FolderList) {$TestValue = $Line.IsFinalized;If ($TestValue -like 'Fa*') {$NFCounter++}}
            Write-Host  "$FCounter / $TotalFolders Folders are completed ..." -ForegroundColor Green
            Write-Host "$NFCounter folders remain to be completed ..." -ForegroundColor Yellow
        } Else {
            Write-Host "$Status --> $StatusDetail" -ForegroundColor Cyan
            Write-Host 'Waiting to begin processing folders....' -ForegroundColor Yellow

    $InnerCounter = 0

    # Time indicator:
    Do {
        Write-Host '.' -NoNewline -ForegroundColor Yellow
        Start-sleep 1
    } While ($InnerCounter -lt 30)

    $Time = $Counter*30
    Write-Host "$Time Seconds have passed." -ForegroundColor Green

} While ($Counter -lt 10000)

This provides visual elements like the below:

Watching the end of the migration, with the various stages and status messages that are relayed:

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Google photo

You are commenting using your Google account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s