Programmatically Reading and Converting Database Sizes With Exchange 2013 Powershell
Author Name • July 11, 2014 02:56 PM
For quite a while I've had automated PowerShell scripts that monitor our Exchange database sizes. I set this up so we could see weekly/monthly/annual growth patterns for different departments in the company. We weren't really concerned about running out of space on the backend servers, but it would be good to have a rouch idea of the trajectory. And more data is always better, right?
To start, here is how you get the database size in Exchange PowerShell:
> Get-MailboxDatabase -Status <databaseName> | select DatabaseSize
DatabaseSize
------------
8.063 MB (8,454,144 bytes)
That size format is a bit odd, but in Exchange 2010, PowerShell would let me convert that to gigabytes, using the ToGB() function on the DatabaseSize property. So, I set up a script to iterate through all of our databases, convert each DatabaseSize to GB, and then enter that data into a database.
ForEach ($db in $arr) {
Get-MailboxDatabase -Status $db | select DatabaseSize | ForEach {
$size = $_.DatabaseSize.ToGB()
$query = "INSERT INTO ``sizes`` (``timestamp``, ``database_id``, ``size``) VALUES (DATE(NOW()),(SELECT id FROM ``databases`` WHERE db_name LIKE `'$db`'),$size)"
Write-Host $query
$Rows = WriteMySQLQuery $conn $query
}
}
The WriteMySQLQuery at the end is just a function defined elsewhere that executes the MySQL query.
After we upgraded to Exchange 2013, these scripts stopped working. I tried running the script manually so that I could see errors, and I saw a bunch of these:
ForEach : Method invocation failed because [System.String] doesn't contain a method named 'ToGB'.
At C:\exchangescripts\db_sizes.ps1:99 char:58
+ Get-MailboxDatabase -Status $db | select DatabaseSize | ForEach {
+ ~~~~~~~~~
+ CategoryInfo : InvalidOperation: (:) [ForEach-Object], RuntimeException
+ FullyQualifiedErrorId : MethodNotFound,Microsoft.PowerShell.Commands.ForEachObjectCommand
I don't know the exact reason, or I at least can't find any documentation indicating that Microsoft changed anything. However, in my search for a solution, I found this forum post, which gave me the fix. I inserted these two lines at the top to load the Exchange Data dll:
$dll = "C:\Program Files\Microsoft\Exchange Server\V15\Bin\Microsoft.Exchange.Data.dll"
[Reflection.Assembly]::LoadFile($dll)
Then I used a ByteQuantifiedSize object to hold the DatabaseSize property, like so:
[Microsoft.Exchange.Data.ByteQuantifiedSize]$obj = $db.DatabaseSize
Working this concept into the original script above, it now looks like this:
ForEach ($db in $arr) {
Get-MailboxDatabase -Status $db | select DatabaseSize | ForEach {
[Microsoft.Exchange.Data.ByteQuantifiedSize]$rawSize = $db.DatabaseSize
$size += $rawSize.ToGB()
$query = "INSERT INTO ``sizes`` (``timestamp``, ``database_id``, ``size``) VALUES (DATE(NOW()),(SELECT id FROM ``databases`` WHERE db_name LIKE `'$db`'),$size)"
Write-Host $query
$Rows = WriteMySQLQuery $conn $query
}
}
This is how I got my data out of Exchange. I also set up a task in Task Schedular to run this every night. Over time this generates a nice bit of data that can be charted. Once I have a bunch of data, maybe I will come back and edit this post with some of those visulations.