Handle Exchange 2007 mailbox-limits using Powershell and Customattribute15 (ADS)

In my last job, I was responsible for our exchange-environment (Exchange 2007), where we've had a lot of users with HUGE mailboxes. They kept requesting new/adjusted limits all the time, so instead of 'wasting' our 'engineers-time' for all the requests, we've came up with a pretty nice solution; we've handed this task over to our 1st level support, but without giving them access to the exchange-environment. I instead wrote a script, that applies predefined limits according to the 'Customattribute15' (CA15) in Activedirectory.

The Script

[cc lang="powershell" lines="-1"]

#########################################################
# Author: Raphael Hoegger
# Source: http://pfuender.net/?p=156
# License: This file is licensed under the GPL v2.
# Latest change: 2010.01.12 09:10:58 CEST
# Version: 1.05

#########################################################
## VARIABLES
\$logfile="log.txt"

## empty logfile
remove-item \$logfile
new-item -itemtype file -path \$logfile >\$null
\$Error.Clear()

## FUNCTION -- Apply pre-defined limits
Function apply_limits (\$mailbox){
switch (\$mailbox.Customattribute15) {
## 1.5GB limit
10 {
\$lim_warn = "1350MB"
\$lim_noS = "1500MB"
\$lim_noSR = "1650MB"
\$lim_dbdef= \$false
}

## 3.0GB limit
20 {
\$lim_warn = "2700MB"
\$lim_noS = "3000MB"
\$lim_noSR = "3300MB"
\$lim_dbdef= \$false
}

## 4.5GB limit
30 {
\$lim_warn = "4500MB"
\$lim_noS = "5000MB"
\$lim_noSR = "5500MB"
\$lim_dbdef= \$false
}

## 5.5GB limit
40 {
\$lim_warn = "5000MB"
\$lim_noS = "5500MB"
\$lim_noSR = "6000MB"
\$lim_dbdef= \$false
}

## DB default limit -- for those who don't have the CA15 set
default {
\$lim_warn = "unlimited"
\$lim_noS = "unlimited"
\$lim_noSR = "unlimited"
\$lim_dbdef= \$true
}
}

## Check for inconsistencies between ADS/Exchange and the proposed values of the CA15
## log-changes + adjust accordingly
## Adjust issuewarningquota
if (\$mailbox.issuewarningquota -ne \$lim_warn)
{
\$temp = \$mailbox.issuewarningquota.value
echo "\$mailbox --- Adjusting-Warning: \$temp --new \$lim_warn" >> \$logfile
\$mailbox | Set-Mailbox -IssueWarningQuota \$lim_warn
}

## Adjust Prohibitsend
if (\$mailbox.ProhibitsendQuota -ne \$lim_noS)
{
\$temp = \$mailbox.Prohibitsendquota.value
echo "\$mailbox --- Adjusting-NoSend: \$temp --new \$lim_noS" >> \$logfile
\$mailbox | Set-Mailbox -Prohibitsendquota \$lim_noS
}

## Adjust Prohibitsendreceivee
if (\$mailbox.ProhibitsendReceiveQuota -ne \$lim_noSR)
{
\$temp = \$mailbox.prohibitsendreceivequota.value
echo "\$mailbox --- Adjusting-NoSendReceive: \$temp --new \$lim_noSR" >> \$logfile
\$mailbox | Set-Mailbox -ProhibitsendReceivequota \$lim_noSR
}

## Adjust the 'usedatabasequotadefaults'
if (\$mailbox.usedatabasequotadefaults.tostring() -ne \$lim_dbdef.tostring())
{
\$temp = \$mailbox.usedatabasequotadefaults.tostring()
echo "\$mailbox --- Adjusting-usedbdefaults: \$temp --new \$lim_dbdef" >> \$logfile
\$mailbox | Set-Mailbox -UseDatabaseQuotaDefaults \$lim_dbdef
}
}

\$databases = Get-Mailboxdatabase | select identity
foreach (\$database in \$databases) {
switch -regex (\$database.Identity) {

## Process all databases of Switzerland
"Switzerland [a-z]" {
## cache mailboxes
\$mailboxes = Get-Mailbox -resultsize unlimited -database \$database.identity

## Apply the limits
foreach (\$mailbox in \$mailboxes) { apply_limits(\$mailbox) }
}

## Process all Swedish databases
"Sweden [a-z]" {
## cache mailboxes
\$mailboxes = Get-Mailbox -resultsize unlimited -database \$database.identity

## Apply the limits
foreach (\$mailbox in \$mailboxes) { apply_limits(\$mailbox) }
}
}
}

## Check for errors and append them to the log if there are some
if (\$Error.Count -gt 0)
{
echo "" >> \$logfile
echo "Errors occurred, please check below:" >> \$logfile
\$error.tostring() >> \$logfile
}
else
{
echo "" >> \$logfile
echo "No Errors occurred." >> \$logfile
}

## Generate a mail with the LOG
\$date = Get-Date -uFormat %Y.%m.%d
\$FromAddress = "admin@domain.com"
\$ToAddress = "admin@domain.com"
\$MessageSubject = "Exchange Limit Adjustments - \$date"
## generate mail-body
\$MessageBody = "Hello Exchange-Admins,`r`n`r`nFind below the adjustments that have been made to the Mailboxes:`r`n------------------------`r`n"
foreach (\$line in (cat log.txt)) { \$Messagebody += "\$line`r`n" }
\$MessageBody += "`r`n------------------------`r`nPlease note, this script runs daily on server XXX at 23:00 CET"
\$SendingServer = "smtp.domain.com"
\$SMTPMessage = New-Object System.Net.Mail.MailMessage \$FromAddress, \$ToAddress, \$MessageSubject, \$MessageBody
\$SMTPMessage.to.add("user_1@domain.com") ## Add extra recipients
\$SMTPMessage.to.add("user_2@domain.com") ## Add extra recipients

##Send the message
\$SMTPClient = New-Object System.Net.Mail.SMTPClient \$SendingServer
\$SMTPClient.Send(\$SMTPMessage)
[/cc]

Explanation

If you're in a rush, skip this part and continue reading on the next chapter...
There's no magic in the script, so don't be afraid to play with it! ...but please do so in your lab, and not your prod-environment :-p
The lines 17 - 59, define the limits, which will get applied. You can simply copy one of these blocks and adjust it to your limits. I've used here increments of 10, so I can always insert a new limit between the existing ones, without renumbering the existing ones. From line 20 to 26 is such a block, so if you want to create a new limit, copy it, and change your three warning-levels to whatever fits in your environment. Lines 52-57 is a bit special. It's setting the default limit, that every user should have (empty CA15 field). This will reset the three warning-levels, but enable the use of the 'database quota defaults', which of course must be set, else they won't have a limit at all.

The block from 61 until 94 is checking the current mailbox-limit and the proposed value (according to CA15). If the values are different, log it, and do the neccessary changes.

From line 96 until 118, it's gathering the neccessary information about your mailbox-dataabases. Once this is done, it'll check if there are rules for each one of them and apply the limits as discussed previously. I've used Switzerland and Sweden as examples. As you can see on both of them (line 101/110), it's using regular expressiosn, so you a db called 'switzerland a' will be processed, as well as a 'switzerland f'. To add a new db, just copy and modify lines 100-107.

And finally 121-150 is generating the email. No further comment, should be selfexplaining (else just ask).

How to run?

So to quickly sum it up, you need the following to get this script to work:

  • Some modified CustomAttribute15 in ADS
  • A modified script
  • - Create your own limits (lines 17-59) - Adjust it according to your db-naming conventions (lines 96-118) - Modify the from/to/subject/smtp-server for the logs (lines 121-150)
  • A machine with Powershell installed to run it (can also be an exchange server)
  • optional; a scheduled task to run it on a daily base

Further notes

If you've just made some modifications, and you want to do a 'dry-run', just comment-out the lines containing 'set-mailbox' (lines 68, 76, 84, 92) as well as the final mail (line 150).

Thanks for reading! Questions..? use the comments below.. ;-)

Cheers,
Raphi