Generating User Distribution Reports
Reports
that list user mailbox distribution across all mailbox stores can be
helpful to know if the user load is balanced in the organization. The
following .ps1 example shows how to produce a report listing
the total number of mailbox stores, the number of mailboxes in each
store, and the total number of mailboxes.
This .ps1
script contains comments, variables, and error trapping. Comments begin
with the “#” symbol and are useful for administrators to understand
what the script or cmdlet is doing and are ignored by EMS/PowerShell.
Variables always start with the “$” symbol and are used to assign
values or collections. Error trapping handles exceptions or errors that
can occur in the script so the script will continue to run.
#Get all mailbox stores in the organization and assign them to the $MailboxStores array variable
$MailboxStores = get-mailboxdatabase
write-host "There are" $MailboxStores.Count "Mailbox Stores in the organization."
write-host ("-"*70)
#Get each database and assign it to the $Database array variable
foreach ($Database in $MailboxStores) {
#Derive the Mailbox server name from the database
$MailboxServer = $Database.server.name
#Derive the database name from the database
$Database = $Database.name
#Assign the full database name to the $FullDatabaseName variable
$FullDatabaseName = "$MailboxServer" + "\" + "$Database"
#Get the mailboxes for this database
$mailbox = get-mailbox -database $FullDatabaseName
write-host "There are" $mailbox.Count.toString("#,#") "mailboxes in" $FullDatabaseName
#The trap statement traps the NullException error which occurs when a database has
no mailboxes
trap{
write-host "There are no mailboxes in" $FullDatabaseName;
continue
}
}
write-host ("-"*70)
#Get all mailboxes in the organization
$mailboxes = get-Mailbox
write-host "The total number of mailboxes in the organization is"
$mailboxes.count.tostring("#,#")
Using This Data to Rebalance Mailbox Distribution
EMS
can also be used to redistribute users equally across all mailbox
stores in the organization. The script is based on the previous example
and redistributes existing mailboxes evenly across all mailbox
databases in the organization.
The script
makes use of a dynamic array and operators that provide the addition
and subtraction functions for building the array.
#Get all mailbox databases and assign them to the $MailboxDatabases array variable
$MailboxDatabases = get-mailboxdatabase
write-host ("There are " + $MailboxDatabases.Count + " Mailbox Databases.")
#Get all mailboxes in the organization and assign them to the $Mailboxes array variable
$Mailboxes = get-mailbox
write-host ("There are " + $Mailboxes.Count + " mailboxes in total.")
#Derive the desired number of mailboxes per database by dividing the number of
mailboxes by the number of databases, less the remainder
$DesiredNumber = ($Mailboxes.Count - ($Mailboxes.Count % $MailboxDatabases.Count))
/ $MailboxDatabases.Count
write-host ("Desired number of mailboxes per database: " + $DesiredNumber + " mailboxes.")
write-host ("="*70)
$MailboxesInDatabase
[int] $MailboxesToMove = 0
#Create a dynamically expanding ArrayList object to hold the mailboxes that can be moved out
[System.Collections.ArrayList] $MailboxesOut = new-object System.Collections.Arraylist
#Loop through each database to build a list of excess mailboxes
foreach($mailboxDatabase in $MailboxDatabases){
#Find out how many mailboxes are in each database by using a filter
$MailboxesInDatabase = get-mailbox | where{$_.DataBase -like $MailboxDatabase.ID}
write-host $mailboxDatabase.Name "has" $MailboxesInDatabase.Count.ToSTring("#,#") "mailboxes."
#Calculate the number of mailboxes that need to be moved in or out
$MailboxesToMove = $MailboxesInDatabase.Count - $DesiredNumber
#If mailboxes need moving out of this database add them to the $MailboxesOut ArrayList
if($MailboxesToMove -gt 0 ){
write-host $MailboxesToMove "mailboxes can be moved out."
write-host ("-"*70)
for($i=0;$i -ne $MailboxesToMove;$i++){
$count = $MailboxesOut.Add($MailboxesInDatabase[$i])
}
}else{
write-host ($MailboxesToMove*-1) "mailboxes can be moved in."
write-host ("-"*70)
}
#The trap statement traps the NullException error which occurs when a database has
no mailboxes
trap{
write-host $mailboxdatabase.Name "has no mailboxes.";
continue
}
}
if($MailboxesOut.Count -gt $Mailboxes.Count % $MailboxDatabases.Count){
write-host
write-host "Moving" $MailboxesOut.Count "mailboxes."
write-host
}else{
write-host
write-host "All mailboxes are balanced."
write-host
}
#Loop through each database to locate databases that need more mailboxes and move
excess mailboxes into these databases
foreach($mailboxDatabase in $MailboxDatabases){
#Find out how many mailboxes are in each database by using a filter
$MailboxesInDatabase = (get-mailbox | where{$_.DataBase -like $MailboxDatabase.ID})
#Calculate the number of mailboxes that need to be moved in or out
$MailboxesToMove = $MailboxesInDatabase.Count - $DesiredNumber
#If this database needs more mailboxes move the required number from the
ArrayList holding excess mailboxes
if($MailboxesToMove -lt 0 ){
for($i=0;$i -ne $mailboxesToMove;$i--){
write-host "Moving Mailbox" $MailboxesOut[$i].Alias "to" $MailboxDatabase.Name
move-mailbox -TargetDatabase ($MailboxDatabase.ID) -Identity ($MailboxesOut[$i].ID)
}
}
}
write-host ("="*70)
write-host "Script completed successfully!"
As
demonstrated by this example, the Exchange Management Shell can easily
do things that would be much more difficult from the Exchange
Management Console GUI.
Working with Event Logs
Exchange
administrators work often with Windows event logs to troubleshoot
issues. Because EMS runs in the PowerShell environment, the
administrator can take advantage of PowerShell’s Get-Eventlog cmdlet to
work with event logs.
This example
displays all events in the Application Event Log where the source
begins with the word “Exchange.” The output is exported to a CSV file
for easy manipulation in Microsoft Excel.
get-eventlog Application | where {$_.Source -ilike "Exchange*"} | export-csv c:\events.csv