Quantcast
Channel: Steve Goodman's Exchange & Office 365 Blog » exchangeserver2010
Viewing all articles
Browse latest Browse all 5

Balancing the number of mailboxes across Exchange 2010 and 2007 databases

$
0
0
Introduction

In Exchange 2010, you now have the option to allow mailboxes to be automatically distributed across databases. However, the algorithm used simply randomly allocates the new mailbox to your chosen databases – rather than ensuring the mailbox count is balanced, and doesn’t do anything about re-distributing mailboxes if you add new databases.

To help with this, and of course to help with any situation where you want to balance the number of mailboxes across a set of databases, I’ve written a simple script that help with moving mailboxes to balance out your databases.

Using Generate-DBBalanceScript.ps1

There’s nothing too complicated about the script- it doesn’t balance based on mailbox size (a future version), but simply creates a script with Move-Mailbox or New-MoveRequest  commands that once complete, balances based on mailbox counts across the databases. You pass it the results of a Get-MailboxDatabase command, along with an output file that will contain the Mailbox move commands.

First of all, lets see it in action:

Of course, my example was the simplest – across all databases. Here’s a few examples including the one above, and some others that show how to drill down to databases on specific servers:

Example One – Generate a move file based on all Exchange 2010 Databases:

.\Generate-BalanceMoveRequests.ps1 -DBs (Get-MailboxDatabase) -OutputPowershellFile .\moves.ps1

Example Two – Generate a move file based on  Exchange 2010 Databases located on a single server “servername”:


$o=Get-MailboxDatabase -Server servername
.\Generate-BalanceMoveRequests.ps1 -DBs $o -OutputPowershellFile moves07.ps1 -Exchange2010:$false

Example Three – 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

Download Generate-DBBalanceScript.ps1

You can download Generate-DBBalanceScript.ps1 here or view the script below.

Hope this helps!



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=@(); # Array with DB Id, Mailbox Count and Mailbox listing
[array]$UA_DBCounters=@(); # Under allocated list from above, populated later
[array]$OA_DBCounters=@(); # Over allocated list from above, populated later
[array]$PA_DBCounters=@(); # 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


Viewing all articles
Browse latest Browse all 5

Latest Images

Trending Articles





Latest Images