Let Go of Get-Mailbox; It’s had its Time
Recently I wrote about the New-DistributionGroup cmdlet to explain why I think distribution lists are still so valuable, despite Microsoft’s best efforts to convince the world that Microsoft 365 Groups are better. Today, I want to discuss an even more fundamental cmdlet for many peoples’ experience of working with Exchange through PowerShell: Get-Mailbox. Or to be more precise, the new and improve Get-ExoMailbox.
Microsoft introduced Get-ExoMailbox as one of the nine initial cmdlets upgraded in 2019 to use the REST APIs (like the Microsoft Graph) instead of Remote PowerShell (RPS) for a very good reason. Fetching sets of mailboxes to process is a fundamental activity for any Exchange administrator. Get-Mailbox works, but it’s slow and prone to error, especially when dealing with large sets of objects. In this respect, it shares the same flaws as other Remote PowerShell cmdlets. The fact that Get-Mailbox is used so often to process so much data makes it appear more problematic than its peers. It’s not really. Instead, Get-Mailbox reveals all the flaws inherent in depending on a connection to a named remote server which might or might not remain available for an entire session.
Three Steps to Exchange Online PowerShell Happiness
In any case, by now, you should have converted Exchange Online scripts to:
- Use the Exchange Online Management module instead of Remote PowerShell.
- Use the Connect-IPPSSession cmdlet to connect to the compliance endpoint. The current version of Exchange Online Management module allows concurrent sessions connected to Exchange management and compliance.
- Switch out Get-Mailbox to use Get-ExoMailbox instead and switch other important cmdlets at the same time. The three most pressing switches to make are Get-ExoMailboxStatistics, Get-ExoMailboxFolderStatistics, and Get-ExoMailboxPermission.
The Exchange Online Management module and the REST-based cmdlets don’t exist for Exchange on-premises. The way Exchange Online’s infrastructure works revealed some of the flaws in Remote PowerShell that just don’t happen in on-premises deployments, so Microsoft hasn’t moved the new cmdlets there yet. Will this ever happen? I don’t know, but if I was forced to guess, I’d say no. But never say never.
Version 2.0.5 of Exchange Online Management
Speaking of versions, Microsoft released V2.0.5 of the Exchange Online Management module on May 10. They still haven’t updated the release notes for the module, so we don’t know what’s in the new version. In any case, I’ve been running 2.0.5 for the last week and all appears stable. 70,000-odd others have downloaded 2.0.5 and I haven’t heard of any problems so far.
Optimizing Mailbox Data
Getting back to Get-ExoMailbox, the big upgrade issue that I hear of time and time again is the need to specify Properties when fetching mailbox data. This is a change in behavior over Get-Mailbox implemented to optimize the fetching of mailbox data. The problem is that the properties of a mailbox span hundreds of different items, some of which need to be fetched or validated with Azure AD. If you do something like:
Get-Mailbox -Identity TRedmond
You fetch every property for the mailbox. But if you run:
Get-ExoMailbox -Identity TRedmond
Exchange Online retrieves only 15 properties. These are the most important, like the display name, user principal name, email addresses, and the much-underused ExternalDirectoryObjectId. This is the pointer (GUID) to the Azure AD account which owns the mailbox. All Exchange Online mail-enabled objects connected to Azure AD have this property to make it easy to connect to Azure AD. Using GUIDs to reference objects is very common within Office 365, notably in every Graph API call to fetch data about an object, so it’s good to become accustomed to using GUIDs.
For example, I can do this:
Get-AzureADUser -ObjectId ((Get-ExoMailbox -Identity Tony.Redmond@office365itpros.com).ExternalDirectoryObjectId) | Select ObjectId, DisplayName
f1dbb86a-69bf-4245-8bc7-5e1d09d9d8cc Tony Redmond (Office 365 for IT Pros)
I can take the ObjectId returned by Azure AD and use it with Get-ExoMailbox:
Get-ExoMailbox -Identity f1dbb86a-69bf-4245-8bc7-5e1d09d9d8cc
Because Get-ExoMailbox is careful about what it fetches, you often need to include requests to fetch individual properties or property sets in your calls (a property set is a collection of properties common to some purpose, like quotas). For instance, the WhenCreated property is not one of the basic 15, so if I want to use it, I must include it in the call:
Get-ExoMailbox -Identity TRedmond -Properties WhenCreated
The benefits of moving to Get-ExoMailbox include:
- Better performance, especially when processing large numbers of mailboxes. Your mileage will vary depending on what you do, but when I tested the new cmdlets in public at Microsoft Ignite 2019, the speed increase was between three and four times faster to process thousands of mailboxes. You won’t see much benefit if you only ever fetch a couple of mailboxes. And at the other end of the scale, to process very large quantities of mailboxes, the Graph APIs might be a better solution.
- Better reliability. Get-ExoMailbox and the other REST-based cmdlets are better able to handle server issues. If you’re in the middle of fetching thousands of mailboxes, the last thing you want is for Exchange Online to switch domain controllers (it happens, even in the cloud). Remote PowerShell will fail. Get-ExoMailbox will probably complete successfully (errors are always unpredictable).
The executive summary is that some short-term pain in converting scripts to use the new cmdlets will be repaid many times over with long-term gains in performance and reliability. It’s just the right thing to do, and anyone who proposes that they write code using the old cmdlets should be asked to reconsider their options with just a hint of forcefulness.
And have I mentioned that the Exchange Online Management module supports Ubuntu Linux? Well, maybe that’s not so important for this audience, but it’s true.