March 25 2009

SCOM Maintenance Mode GUI

A colleague of mine has created an excellent Maintenance Mode GUI for System Centre Operation Manager based on Powershell forms. Head over to blog.tyang.org to find out more.



----------------------------------------------------------------------------
I use a maximum of one Google Ad per post to help offset some of my blog hosting costs.

----------------------------------------------------------------------------

March 12 2009

Balance mailboxes across databases – Exchange 2007

There is a fantastic script on Kurtdepauw’s blog (http://kurtdepauw.wordpress.com/2007/11/10/dbbalancer-load-balance-your-exchange-mailbox-databases/) to assist in evenly balancing your Exchange 2007 databases so they are of similar size.

I have customized it slightly and highlight the 2 lines below as useful modifications:

Line 78 – added ‘| Where-Object {$_.Name -notlike “Archive Storage Group”}’ – this is very useful if you want to exclude certain databases from being touched by the balancing script

$DBs = Get-MailboxDatabase -Server $Global:hshParameters.MailboxServer | Where-Object {$_.Name -notlike "Archive Storage Group"}

Line 130 – added -PreserveMailboxSizeLimit switch – you will need to add this so that you can move mailboxes that exceed the database default limits

Move-Mailbox -Identity $Mailboxes[$intRandomMailbox] -TargetDatabase $Global:strSmallestDB.Split(";")[0] -PreserveMailboxSizeLimit -Confirm:$false

———-

Update 04/11/2009

I’ve been alerted that the link to Kurtdepauw’s blogis broken. I’ve posted the entire code below:

# DBBalancer Version 1.1
# Written by BoerLowie (sammybog@gmail.com)
# Modified by www.danovich.com.au - 12/03/2009 - www.danovich.com.au
#
# This script is used to maintain a balance between your different Exchange 2007 Mailbox Databases
#
# Configuration/Installation
# --------------------------
#
# To install the application, just place the script and the config file in C:Program FilesDBBalancer
#
# The configuration is stored in DBBalancer.xml  Use the line below as a reference XML Config file (just paste it in notepad and save it as DBBalancer.xml
#
# <Objs Version="1.1" xmlns="http://schemas.microsoft.com/powershell/2004/04"><Obj RefId="RefId-0"><TN RefId="RefId-0"><T>Deserialized.System.Collections.Hashtable</T><T>Deserialized.System.Object</T></TN><DCT><En><S N="Key">ThresholdInGB</S><I32 N="Value">5</I32></En><En><S N="Key">MailboxServer</S><S N="Value">S-BE-KI-EX</S></En></DCT></Obj></Objs>
#
# You can run the script in foreground or schedule it.  To schedule it, create a task using the following command line:
#
# PowerShell.exe -PSConsoleFile "C:Program FilesMicrosoftExchange ServerBinexshell.psc1" -Command "C:DBBalancerDBBalancer.ps1"
#
# Make sure your account is at least an Exchange Server Administrator on the Mailbox Server.
#
# The following values are used in the xml file:
#  - ThresholdInGB:  The script will start to balance you databases if the difference between the biggest
#                    DB and the smallest DB exceeds this value.  This should be set to something like 5 GB.
#  - MailboxServer:  The MailboxServer to balance.  The script can be run from every machine with Exchange 2007 Management Tools
#                    installed on, so it needs to know which Mailbox Server it needs to connect to.  The script will balance all DB's on this
#                    mailbox server.
#
# Processing
# ----------
#
# The script will move a RANDOM mailbox from the Biggest DB to the Smallest DB until all DB are within the Threshold limit.  So if you
# set the Threshold to 5 GB, all DB's will be equally loaded with a maximum difference of 5 GB.
# Only one mailbox at a time will be moved to minimize user downtime.
#
# Logging
# -------
#
# You can follow the progress of the script in the Application Log.  Look for events of Source DBBalancer.
# Every mailbox move will be listed in the eventviewer.
#
# When all Mailbox Databases are balanced, the following will be displayed in the Event Viewer:
#  All Mailbox databases are balanced within the Threshold limit.

$ErrorActionPreference = "SilentlyContinue"

$Global:hshParameters = @{}
$Global:strBiggestDB = ""
$Global:strSmallestDB = ""
$Global:blnExecute = $True

Function Start-Init
{
$Global:hshParameters = Import-Clixml "C:Exchange_Maintenance_ScriptsDBBalancerDBBalancer.xml"
$Global:objEventLog = New-Object System.Diagnostics.EventLog("Application")
$Global:objEventLog.MachineName = "."
$Global:objEventLog.Source = "DBBalancer"
$Global:objEventLog.WriteEntry("Application Started." + [System.Environment]::NewLine + [System.Environment]::NewLine + `
"Target Mailbox Server :" + $Global:hshParameters.MailboxServer + [System.Environment]::NewLine + `
"Threshold in GB :" + $Global:hshParameters.ThresholdInGB)
}

Function Check-Prerequisites
{
If ((Get-MailboxDatabase -Server $Global:hshParameters.MailboxServer | Measure-Object).Count -gt 1)
{
Return $true
}
Else
{
Return $false
}
}

Function Get-BiggestandSmallestDB
{
Process
{
$DBs = Get-MailboxDatabase -Server $Global:hshParameters.MailboxServer | Where-Object {$_.Name -notlike "Archive Storage Group"}
$blnFirstRun = $true
foreach ($DB in $DBs)
{
$lonDBSize = (Get-MailboxStatistics -Database $DB.Identity | Measure-Object -Property TotalItemSize -Sum).Sum
If ($blnFirstRun -eq $true)
{
$Global:strBiggestDB = $DB.ServerName + "" + $DB.Name + ";" + $lonDBSize
$Global:strSmallestDB = $DB.ServerName + "" + $DB.Name + ";" + $lonDBSize
$blnFirstRun = $false
}
Else
{
If ($lonDBSize -lt $strSmallestDB.Split(";")[1])
{
$Global:strSmallestDB = $DB.ServerName + "" + $DB.Name + ";" + $lonDBSize
}
If ($lonDBSize -gt $strBiggestDB.Split(";")[1])
{
$Global:strBiggestDB = $DB.ServerName + "" + $DB.Name + ";" + $lonDBSize
}
}
}
}
}

Function Check-Threshold
{
If (([Long]$Global:strBiggestDB.Split(";")[1] - [Long]$Global:strSmallestDB.Split(";")[1]) -gt ($Global:hshParameters.ThresholdInGB * 1000000000))
{
Return $True
}
Else
{
Return $False
}
}

Function Do-MainLoop
{
While ($Global:blnExecute -eq $True)
{
Get-BiggestandSmallestDB
If (Check-Threshold -eq $True)
{
[Long]$lonDataToMove = ([Long]$Global:strBiggestDB.Split(";")[1] - [Long]$Global:strSmallestDB.Split(";")[1]) / 2
$Mailboxes = Get-Mailbox -Database $Global:strBiggestDB.Split(";")[0] -ResultSize "Unlimited"
$intRandomMailbox = New-Object System.Random
$intRandomMailbox = $intRandomMailbox.Next(0, ($Mailboxes.Count - 1))
$Global:objEventLog.WriteEntry("Moving " + $Mailboxes[$intRandomMailbox] + " from database " + $Global:strBiggestDB.Split(";")[0] + `
" to database " + $Global:strSmallestDB.Split(";")[0] + "." + [System.Environment]::NewLine + [System.Environment]::NewLine + `
"The mailbox has a size of " + ((Get-MailboxStatistics -Identity $Mailboxes[$intRandomMailbox]).TotalItemSize) + "ytes.")
Move-Mailbox -Identity $Mailboxes[$intRandomMailbox] -TargetDatabase $Global:strSmallestDB.Split(";")[0] -PreserveMailboxSizeLimit -Confirm:$false
}
Else
{
$Global:blnExecute = $False
}
}
Return $True
}

Start-Init
If (Check-Prerequisites -eq $true)
{
If (Do-MainLoop -eq $True)
{
$Global:objEventLog.WriteEntry("All Mailbox databases are balanced within the Threshold limit.")
}
}
Else
{
$Global:objEventLog.WriteEntry("Prerequisites check failed.  You probably have only 1 Mailbox Database and therefor we can't move mailboxes around.")
}