Reducing the Memory Footprint of Exchange Online PowerShell

Three Steps to Shrinking Memory Demands for Exchange Online PowerShell

Exchange Online PowerShell Performance
Exchange Online PowerShell memory

I read the Exchange team’s blog post about Exchange Online PowerShell performance. The team behind the Exchange Online management module made three recommendations:

  • Don’t load the module help when running scripts in non-interactive sessions. In other words, humans might need some help to understand what cmdlets do but computers don’t. Computers never ask for more detail about the commands they’re asked to execute. They just get on with the job.
  • Restrict the number of cmdlets loaded into a PowerShell session. The Exchange Online management module spans some 800 cmdlets. Any session is likely to use less than ten cmdlets. In fact, many scripts might only use the REST-based cmdlets introduced in 2019. These cmdlets (like Get-ExoMailbox and Get-ExoMailboxStatistics) are always loaded by the module into memory along with some of the more recently introduced cmdlets, like Get-UserBriefingConfig. Along with the REST cmdlets, a script might use one or two modernized cmdlets (like Get-User). Modernized means that the cmdlets no longer support basic authentication and have discarded dependencies like WinRM.
  • Create a new PowerShell process for each Exchange Online session. The idea here is that the new session starts off with an empty cache and that reduces the memory footprint. Sounds good, but I bet not many will follow this guidance. I say this for two reasons. First, people are generally lazy and don’t want to go through the hassle of starting and shutting down perfectly good PowerShell sessions. Second, most people working with Microsoft 365 load several modules such as the Microsoft Graph PowerShell SDK and Teams.

In any case, the advice is appreciated and should be considered in the light of whatever work you do with the Exchange Online management module.

New Parameter for Connect-ExchangeOnline

To support avoiding cmdlet help, the latest version of the Exchange Online management module (3.4) boasts the SkipLoadingCmdletHelp parameter. The implementation works very nicely and speeds up module loading. I recommend that you use this parameter in every script that runs without human intervention. For instance, I have some work to do to upgrade scripts (runbooks) written to run using Azure Automation. The next time I touch the code for any of the runbooks, I’ll be sure to add the parameter to Connect-ExchangeOnline.

Avoiding memory overhead like this should be very helpful in any script that combines the Exchange Online management module with the Microsoft Graph PowerShell SDK. When Microsoft created V2 of the Microsoft Graph PowerShell SDK, they split the cmdlets into V1.0 and beta sets to reduce the overhead of loading the SDK for Azure Automation runbooks.

Remember to update your Azure Automation accounts with the latest module so that runbooks can take advantage of the new feature. That might be even more important than keeping the module updated on your workstation (here’s a handy script that I use for that purpose).

Figuring Out Exchange Online PowerShell Cmdlets

Building a list of Exchange Online cmdlets used in a script is a matter of checking the cmdlets called and understanding if they come from the Exchange Online management module and then constructing a list to use with Connect-ExchangeOnline. The Get-Command module returns a small subset of the available cmdlets.

Get-Command -Module ExchangeOnlineManagement

Do not include any of these cmdlets in the set passed to Connect-ExchangeOnline as you’ll get an error like “OperationStopped: No cmdlet assigned to the user have this feature enabled.”

When you’ve determined the set of cmdlets needed by a session, put them in an array and pass the array in the CommandName parameter. This example combines the parameter to skip loading cmdlet help with a defined set of cmdlets to load into a session.

$Cmdlets = "Set-User", "Get-User", "Get-OWAMailboxPolicy", "Set-OWAMailboxPolicy"
connect-ExchangeOnline -SkipLoadingCmdletHelp -CommandName  $Cmdlets

Detail is Important When Running Exchange Online PowerShell

Of course, you could ignore these recommendations and continue running your scripts as before. It’s a good tactic if the scripts work and you’re happy. On the other hand, if you’re looking for some extra performance and reduced memory consumption, these tips are worth considering. I suspect that the folks who will benefit most are those who run PowerShell against tens of thousands of objects (mailboxes, user accounts, etc.).


Learn how to exploit the data available to Microsoft 365 tenant administrators through the Office 365 for IT Pros eBook. We love figuring out how things work.

Leave a Reply

This site uses Akismet to reduce spam. Learn how your comment data is processed.