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

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

Big Benefits

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.

About the Author

Tony Redmond

Tony Redmond has written thousands of articles about Microsoft technology since 1996. He is the lead author for the Office 365 for IT Pros eBook, the only book covering Office 365 that is updated monthly to keep pace with change in the cloud. Apart from contributing to Practical365.com, Tony also writes at Office365itpros.com to support the development of the eBook. He has been a Microsoft MVP since 2004.


  1. Tony Razo

    Hello ! I am having a hard time getting the Get-EXOMailboxFolderStatistics to export the user’s userprincipalname.

  2. Keith

    Hi Tony,

    Thanks for the post. I would really like to move away from the old cmdlets to the new, but the problem I seem to have with the REST based cmdlets is when using pipelines. They just straight up fail without giving me a meaningful error. Here’s an example that I regularly need to run… Find all the users in the tenant who have full access permissions to a mailbox. With the old cmdlet, this is easy…

    Get-Mailbox -ResultSize Unlimited | Get-MailboxPermission -User “John.Doe@acmecorp.com” | Select Identity,User,AccessRights

    With the EXO cmdlets this gives a generic error

    Get-EXOMailbox -ResultSize unlimited | Get-EXOMailboxpermission -User “John.Doe@acmecorp.com” | Select Identity,User,AccessRights

    Get-EXOMailboxpermission : An error occurred while processing this request..

    Many of us simply don’t have or are not given the time to trawl around google posts figuring out how to make the REST cmdlets work when the PS ones already work fine.

    Any suggestions or any good resources that you know of that might reduce the pain?


    1. Avatar photo
      Tony Redmond

      First, if you hit errors with cmdlets, please make sure that you file a formal support incident with Microsoft. It’s the only way that Microsoft will pay any real attention (i.e., assign an engineer to find out why the problem happened).

      Second, with respect to this problem, I think I would try and use the strengths of the REST cmdlet in terms of fetching large numbers of objects fast and reliably while avoiding any lurking rocks which you might have discovered. In this instance, it could be that the pipeline is not being read correctly. So I would do:

      [array]$Mbx = Get-ExoMailbox -ResultSize unlimited
      ForEach ($M in $Mbx) {
      $Perms = Get-ExoMailboxPermission…
      If $Perms add to set of rights…

  3. Dan

    Old habits die hard though Tony, it’ll be like losing a family member of I get rid of Get-Mailbox ?? 😉

    Great info as always!

    1. Avatar photo
      Tony Redmond

      After 14 years of Get-Mailbox, isn’t it time to move on? (rhetorical)

  4. Mike Bakeler

    I appreciate the information within your article.

    Thank you.

Leave a Reply