To aid my memory and perhaps help others, I've decided to post snippets as I continue my journey toward improving my PowerShell skills (I hear that shaking Luc Dekens' and Alan Renouf's hand at the same time increases one's PS Mojo).
With that out of the way, onward and upward.
We are in the midst of migrating from Exchange Server 2003 to Office 365 as a Staged Migration. While not a particularly arduous task, it does involve pulling mailbox statistics and email addresses and using that information for the planning and creation of migration batches. It's tedious and error-prone.
Given a set of Exchange Servers, Domain Controllers, and a Universal Security Group, Get-MailboxSizes.ps1 generates a CSV containing mailbox names, server, size, number of items, office location, department, active mailbox flag, and string suitable for directly pasting into a Staged Migration CSV file.

The ActiveMbx column is TRUE if the user is not enabled or a member of a Universal Security Group used for tracking progress and automating other things.
The odd column header at the last column should be directly pasted into your Staged Migration CSV file as row 1. For successive entries, copy that column value in filtered rows as you plan the migration. Please note that this column assumes Active Directory Synchronization with Office 365.
We've been known to paste entries from the last column into Notepad for a quick Search-Replace of ",,FALSE" with ";". That yields a list that you can paste into the To field of a notification email or add members box of the Universal Security Group.
I’d like to thank Iain Brighton who lent a hand when I was stuck with Custom Objects. Yea Twitter!
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# Get-MailboxSizes.ps1 | |
# | |
# Requires Microsoft Active Directory module | |
If ((Get-Module | Where { $_.Name -eq "ActiveDirectory"}) -eq $null) { | |
Import-Module ActiveDirectory; | |
If ((Get-Module | Where { $_.Name -eq "ActiveDirectory"}) -eq $null) { throw "ActiveDirectory Module is required." } | |
} | |
$colServers = @("Server1", "Server2") # array of Exchange Servers to poll | |
$strGroup = "CN=O365-Migrated,CN=YourOU,DC=domain,DC=com" # dn of security group used to track those already migrated | |
$colDCs = @("domain1-dc") # one more more domain controllers -- in case spanning domains | |
$strCsvFile = "mailbox-sizes.csv" | |
# get all mailboxes, their size, their number of items | |
$colBoxes = @() | |
ForEach ($server in $colServers) { | |
Write-Host "Getting mailboxes from $($server)..." | |
$colBoxes += Get-WMIObject -namespace "root\MicrosoftExchangeV2" -class "Exchange_Mailbox" -Computer $server ` | |
-Filter "NOT MailboxDisplayName like 'System%' and NOT MailboxDisplayName like 'SMTP%'" ` | |
| Select-Object ServerName, MailboxDisplayName, @{N="Size";E={"{0:N0}" -f [int]($_.Size/1024)}}, @{N="Items";E={"{0:N0}" -f $_.TotalItems}} | |
} | |
# turn all of that into custom objects | |
$colDetails = @(); | |
$colBoxes | % { $colDetails += New-Object PSObject -Property @{ Server = $_.ServerName; Mailbox = $_.MailboxDisplayName; Size = $_.Size; ` | |
Items = $_.Items; Department = ""; Office = ""; ForCSV = ""; ActiveMbx = "" } } | |
Write-Host "Getting accounts. This can take a while." | |
$colDetails | ForEach-Object { | |
$mbx = $_ | |
$name = $mbx.Mailbox | |
ForEach ($strDC in $colDCs) { | |
$user = Get-ADUser -Server $strDC -Filter { DisplayName -like $name } -Properties DisplayName, MemberOf, Enabled, Department, Office, mail | |
if ($user) { | |
$mbx.Department = $user.Department | |
$mbx.Office = $user.Office | |
$mbx.ForCSV = "$($user.mail),,FALSE" | |
$mbx.ActiveMbx = ($user.Enabled -eq $true) -and ($user.Memberof -notcontains $strGroup) | |
break | |
} | |
} | |
} | |
$coldetails | Select-Object Mailbox, Server, @{N="Size (MB)";E={$_.Size}}, Items, Office, Department, ActiveMbx, ` | |
@{N="EmailAddress,Password,ForceChangePassword";E={$_.ForCSV}} | Sort-Object Mailbox | Export-Csv $strCsvFile | |
Write-Output Wrote $strCsvFile | |