After a company has effectively migrated to Microsoft 365 and adopted new cloud services, the number of objects, like users, guests, and groups in a tenant is constantly growing. The same applies to Exchange Online.

Even if you’ve followed guidance for Microsoft 365 group expiration or identity lifecycle management, the result is comparable – the number of objects that you are managing is increasing, becoming more of a challenge for administrators. In this article, we’ll examine how to manage Exchange Online at scale using PowerShell.

Maintaining large sets of objects

As we’re all aware, Microsoft is constantly developing different portals and admin centers for admins to use daily for managing the service. Recently, Microsoft announced the new admin center for Exchange as generally available.

One of the drivers for the new portal is performance and the ability to perform bulk operations. It is REST-based and shaped for minimizing your wait time, reducing errors, and much more. Simply put – it can improve your experience as an administrator.

PowerShell can empower

Despite the improvements to the new admin center for Exchange, it remains limited in terms of functionality and leaves room for performance gains. To see improvements, you must move away from the admin center and use PowerShell. For Exchange Online specifically, you want to install and make use of the Exchange Online PowerShell (EXO) V2 module.

This module combines the legacy as well as the new cmdlets. As of today, nine new cmdlets leverage the new REST-based architecture. Nine may not seem like that much – but think about that in relation to the operations you perform daily, and they are quite sufficient.

Most commands that you use are for retrieving mailbox or recipient attributes or statistics – such as information about the mailbox or all folders within a mailbox.

The new cmdlets allow you to reduce the number of requested attributes, which results in less data transferred over the wire. The ability to do this is called Property sets, which is described in more detail here.

Combining the new cmdlet architecture with smaller improvements like using Property Sets can lead to increased performance. However, since Property Sets are not defined automatically you need to be aware of what you’ll need to retrieve when updating your scripts to the new cmdlets.

Aside from a new architecture, the usage of PowerShell unlocks several tasks. You can easily perform bulk operations based on your filtering, and it also allows you to gather properties that are not even visible in the new Exchange admin center.

Server-side filtering is more important than you might realize

It’s important to emphasize that currently, Microsoft recommends using client-side filtering for optimal performance using the Exchange Online V2 module. However, this applies only to this module.

Below is a brief example, highlighting the difference:

# client-side filtering
Get-EXOMailbox -ResultSize 20000 | Where-Object -FilterScript {$_.RecipientTypeDetails -eq 'UserMailbox'}

# server-side filtering
Get-EXOMailbox -ResultSize 20000 -RecipientTypeDetails UserMailbox 

In the first example, the filtering takes place after your client has received all the items. The second example asks the server to filter on the cloud side, and then send the result to the client. This has at least two implications that mean the results from each example provide different output.

First off, we specified the parameter “-ResultSize 20000.” This means we will receive 20000 mailboxes, however, it is likely the collection contains several types of objects in addition to UserMailbox. For example:

Manage Exchange Online at Scale

Secondly, this demonstrates another issue – you might not retrieve all objects you expect. As you can see in the example above only 13219 are UserMailbox.

When using the server-side filter, however, we will receive the correct result:

Manage Exchange Online at Scale

Therefore, it can be worth taking a performance hit when using the server-side filter to ensure you receive accurate results.

Use Microsoft Graph with PowerShell for maximum performance

It should be noted that if you need to modify objects using PowerShell, you are limited to the Exchange Online V2 PowerShell module. Unfortunately, Microsoft Graph currently does not provide a way for altering Exchange Online attributes.

However, that does not mean you cannot use Microsoft Graph at all. Since it is intended to retrieve data quickly, you can bypass the overhead of the Exchange Online V2 module for filtering data you want to retrieve.

When you do this, you must make sure that the filter you want to use is supported by Microsoft Graph. But for most scenarios, you should be able to. The full list of query parameters supported by Microsoft Graph is available on Microsoft Docs.

Before you do combine the use of the Exchange Online V2 module with Graph scripting, you need to consider whether it’s worthwhile. To give some insight as to when this will make a difference, consider that overhead for certain modules can make a huge difference.

In an on-premises environment, you can leverage LDAP queries with a filter and passing the result to Exchange. With this, you improve dramatically the overall performance as LDAP is optimized for queries. The same principle applies to Microsoft Graph.

Here is an example of a query using the Exchange module and the corresponding using Microsoft Graph:

# Exchange command
Get-User -Filter {Department -like 'Reta*'} 
# Microsoft Graph request$filter=StartsWith(Department,'Reta')

Multi-threading your PowerShell scripts provides another option for performance improvement

While this technique is more advanced, it can improve performance to a level you have not yet seen.

Multi-threading, put simply, means that you fork several threads (which you could think of as a sub-process) from your running PowerShell script and have every thread running your code on both your client and on the server-side. This technique is primarily useful for gathering data. The advantage is that you perform a scale-out for your job and several threads work in parallel instead of sequential order for you. The Exchange Online V2 PowerShell module uses this in the architecture. To give you an idea of the power of using multi-threading, take a look at the first single-threaded example:

Manage Exchange Online at Scale

In the second example using multi-threading we see a 44% improvement in retrieval time:

Manage Exchange Online at Scale

Managing multiple Exchange Online environments from one PowerShell session

Another feature of the new Exchange V2 module is the ability to connect to multiple tenants in one PowerShell session. This can be extremely helpful during tenant-to-tenant migrations. But, you’ll need to take care of some important pre-requisites and limitations before using the feature:

  • You’ll need to ensure that you prefix each connection – without doing this, you will retrieve only objects from the last established session.
  • The new cmdlets Get-EXO* are already prefixed and will be available ONLY to the last established connection

In the following example, I connected to a source and target tenant. As the new cmdlets are only available to the last established connection, I connect first to the target as I want to leverage the new cmdlets for gathering data:

Manage Exchange Online at Scale

Note: To distinct the objects from the tenants, I selected PrimarySmtpAddress and UserPrincipalName.

I used the following commands and order:

# connect to target tenant
Connect-ExchangeOnline -UserPrincipalName -Prefix Target
# connect to source tenant
Connect-ExchangeOnline -UserPrincipalName -Prefix Source


I hope this article provided you with the information and motivation to begin looking into other ways of managing your Exchange Online environment when you have many objects to manage, and/or on a large scale.

Remember, you can use more than the Exchange Online V2 module for PowerShell management. You should try and leverage multiple tools, such as Microsoft Graph to improve the performance of your scripts and administrative tasks. Using these techniques you can build a solid foundation to reduce the time it takes to retrieve information and statistics from your environment, and build scripts to automate routine tasks.

Manage Exchange Online at Scale

About the Author

Ingo Gegenwarth

Ingo Gegenwarth is a Technical Consultant at a market-leading organization for enterprise application software. In his role, he is responsible for the Exchange infrastructure as well as Office 365. In 2003, he earned his first MCSE 2000, and since then he's earned Microsoft Certified Master (MCM) and Microsoft Certified Solutions Master (MCSM).

Leave a Reply