0

Balance Exchange 2016 MailboxDBs

I cannot take credit for this script, but thought that I would share it as it is a fantastic script which worked a treat for me.

This script should create the same amount of Exchange Mailboxes into each MailboxDB.

<# .SYNOPSIS Generates a Powershell file containing Mailbox Move Cmdlets to help balance mailbox databases, based on mailbox count, not size. .DESCRIPTION Using a list of Databases, works out the average number of mailboxes there should be per DB, then generates move commands to run seperately. By Steve Goodman .PARAMETER DBs Databases to use The result of a Get-MailboxDatabase cmdlet. Eg. (Get-MailboxDatabase -Server name) .PARAMETER OutputPowershellFile The filename to write, for example C:\output.ps1 or .\output.ps1 .PARAMETER Exchange2010 By default, true. Set to $false to generate Exchagne2007 move-mailbox commands .EXAMPLE Generate a move file based on all Exchange 2010 Databases .\Generate-BalanceMoveRequests.ps1 -DBs (Get-MailboxDatabase) -OutputPowershellFile .\moves.ps1 .EXAMPLE Generate a move file based on Exchange 2007 Databases located on a single server "servername" $o=Get-MailboxDatabase -Server servername .\Generate-BalanceMoveRequests.ps1 -DBs $o -OutputPowershellFile moves07.ps1 -Exchange2010:$false .EXAMPLE Generate a move file based on Exchange 2007 Databases located on two servers, "serverone" and "servertwo" $o=Get-MailboxDatabase | where {$_.Server -eq "serverone" -or $_.Server -eq "servertwo"} .\Generate-BalanceMoveRequests.ps1 -DBs $o -OutputPowershellFile moves07.ps1 -Exchange2010:$false #>
param(
[parameter(Position=0,Mandatory=$true,ValueFromPipeline=$false,HelpMessage="Mailbox database object")][array]$DBs,
[parameter(Position=1,Mandatory=$true,ValueFromPipeline=$false,HelpMessage="Filename for output Powershell script")][string]$OutputPowershellFile,
[parameter(Position=2,Mandatory=$false,ValueFromPipeline=$false,HelpMessage="Is this for Exchange 2010")][bool]$Exchange2010=$true
)

# Check for Exchange cmdlets
if (!(Get-Command Get-MailboxDatabase -ErrorAction SilentlyContinue))
{
throw "Exchange Cmdlets not available";
}
# Check input object
if ($DBs[0].GetType().Name -ne "MailboxDatabase")
{
throw "Object is not an array of mailbox databases"
}
if ($DBs.Count -eq 1)
{
throw "You can't balance a single database";
}

# Check file does not exist
if ((Test-Path $OutputPowershellFile))
{
throw "File $($OutputPowershellFile) already exists";
}

# Initialise file
"# Mailbox Mail Powershell Script File, generated $(date)`r`n"|Out-File -FilePath $OutputPowershellFile -NoClobber
if (!(Test-Path $OutputPowershellFile))
{
throw "Could not write to $($OutputPowershellFile)";
}

# Initialise Variables
[int]$TotalMailboxes=0; # Total Mailboxes
[int]$BalancedCount=0; # Balanced Number of Mailboxes per DB
[array]$DBCounters[email protected](); # Array with DB Id, Mailbox Count and Mailbox listing
[array]$UA_DBCounters[email protected](); # Under allocated list from above, populated later
[array]$OA_DBCounters[email protected](); # Over allocated list from above, populated later
[array]$PA_DBCounters[email protected](); # Perfectly allocated list from above, populated later
[string]$Output=""; # Variable to write output text to

# Gather initial mailbox counts
Write-Host "Gathering Mailbox Counts"
for ($i = 0; $i -lt $DBs.Count; $i++)
{
Write-Progress -activity "Gathering Mailbox Counts" -status "Processing Database $($DBs[$i].Identity)" -PercentComplete (($i / $DBs.Count) * 100)
$Mailboxes = (Get-Mailbox -Database $DBs[$i].Identity -ResultSize Unlimited | select Identity)
$DBCounters=$DBCounters+1;
$DBCounters[$DBCounters.Count-1] = New-Object Object
$DBCounters[$DBCounters.Count-1] | Add-Member NoteProperty Database $DBs[$i].Identity
$DBCounters[$DBCounters.Count-1] | Add-Member NoteProperty Total $Mailboxes.Count
$DBCounters[$DBCounters.Count-1] | Add-Member NoteProperty Mailboxes $Mailboxes
$TotalMailboxes+=$Mailboxes.Count
}
Write-Progress -Activity "Gathering Mailbox Counts" -Completed -Status "Completed"
Write-Host "DB Counts are as follows:"
$DBCounters|Select Database,Total
$BalancedCount = $TotalMailboxes / $DBs.Count
Write-Host "Found $($TotalMailboxes) mailboxes across $($DBs.Count) databases. Aiming for $($BalancedCount) mailboxes per database."

Write-Host "Sorting Databases into over, under and perfectly allocated."
# Sort DBs into under-allocated, over-allocated and perfectly allocated
for ($i = 0; $i -lt $DBCounters.Count; $i++)
{
Write-Progress -activity "Sorting Databases into over, under and perfectly allocated" -status "Processing Database $($DBCounters[$i].Database)" -PercentComplete (($i / $DBCounters.Count) * 100)
if ($DBCounters[$i].Total -lt $BalancedCount)
{
$UA_DBCounters=$UA_DBCounters+1;
$UA_DBCounters[$UA_DBCounters.Count-1] = $DBCounters[$i];
} elseif ($DBCounters[$i].Total -gt $BalancedCount) {
$OA_DBCounters=$OA_DBCounters+1;
$OA_DBCounters[$OA_DBCounters.Count-1] = $DBCounters[$i];
} else {
$PA_DBCounters=$PA_DBCounters+1;
$PA_DBCounters[$PA_DBCounters.Count-1] = $DBCounters[$i];
}
}
Write-Progress -activity "Sorting Databases into over, under and perfectly allocated" -Completed -Status "Completed"

Write-Host "Found $($OA_DBCounters.Count) over, $($UA_DBCounters.Count) under and $($PA_DBCounters.Count) perfectly allocated";
# Make move list
Write-Host "Generating Powershell File '$($OutputPowershellFile)' to Balance DBs."
for ($i = 0; $i -lt $OA_DBCounters.Count; $i++)
{
Write-Progress -activity "Generating Powershell File '$($OutputPowershellFile)' to Balance DBs" -status "Processing Database $($OA_DBCounters[$i].Database)" -PercentComplete (($i / $OA_DBCounters.Count) * 100)
# Get the mailbox list
[array]$OA_Mailboxes = $OA_DBCounters[$i].Mailboxes
$UA_DBPointer=0;
for ($j=$BalancedCount; $j -lt $OA_Mailboxes.Count; $j++)
{
# Move to next underallocated DB if required
if ($UA_DBCounters[$UA_DBPointer].Total -ge $BalancedCount -and $UA_DBPointer -lt $UA_DBCounters.Count-1)
{
$UA_DBPointer++;
}
Write-Progress -activity "Generating move commands" -status "Processing $($OA_Mailboxes[$j].Identity)" -PercentComplete (($j / $OA_Mailboxes.Count) * 100)
# Generate a Powershell command for the move request
if ($Exchange2010)
{
$Output+="New-MoveRequest -Identity '$($OA_Mailboxes[$j].Identity)' -TargetDatabase '$($UA_DBCounters[$UA_DBPointer].Database)' -Confirm:" + '$false' + "`r`n";
} else {
$Output+="Move-Mailbox -Identity '$($OA_Mailboxes[$j].Identity)' -TargetDatabase '$($UA_DBCounters[$UA_DBPointer].Database)'`r`n";
}
$OA_DBCounters[$i].Total--; # Take one mailbox of the total on the overallocated DB
$UA_DBCounters[$UA_DBPointer].Total++; # Add one mailbox tot the total of the current underallocated DB

}
Write-Progress -activity "Generating move commands" -Completed -Status "Completed"
}
Write-Progress -activity "Generating Powershell File '$($OutputPowershellFile)' to Balance DBs" -Completed -Status "Completed"
Write-Host "DB Counts will be as follows after executing $($OutputPowershellFile):"
$OA_DBCounters|Select Database,Total
$UA_DBCounters|Select Database,Total
$PA_DBCounters|Select Database,Total
Write-Host "Writing Powershell file '$($OutputPowershellFile)'"
$Output | Out-File -FilePath $OutputPowershellFile -NoClobber -Append

Niall

Leave a Reply

Your email address will not be published.