Bulk remove mailbox permissions for Microsoft 365 users

For this week’s updated PowerShell script, we will tackle the scenario of removing all mailbox (Full access) permissions for a given user. Such task might be performed as part of a cleanup after (suspected) account compromise, or as part of the leaver process. We did in fact cover this scenario in a previous article, so here we’re just presenting an updated version of the script.


Before that, let’s address a related question, namely how to remove all Send As or Send on behalf of permissions granted for a user. Turns out, both those scenarios are quite easier to address, thanks to some “hacks”. For example, to list all the mailboxes a given user has been granted Send on behalf of permissions to, we can use the following query:

Get-Mailbox -ResultSize Unlimited -Filter {GrantSendOnBehalfTo -ne $null} | ? {$_.GrantSendOnBehalfTo -eq "vasil"}

To break it down, we filter all mailboxes with non-null values for the GrantSendOnBehalfTo property, then use client-side filtering to narrow down the list to just the ones matching our user. Once we have the list, we can simply use the pipeline for the removal part:

Get-Mailbox -ResultSize Unlimited -Filter {GrantSendOnBehalfTo -ne $null} | ? {$_.GrantSendOnBehalfTo -eq "vasil"} | Set-Mailbox -GrantSendOnBehalfTo @{remove="vasil"}

Similarly, for the Send As scenario we can leverage the Get-RecipientPermission cmdlet. It has a built-in filter for the Trustee property, which is all we need:

Get-RecipientPermission -Trustee huku | Remove-RecipientPermission


Simple as that! Well, the case for Full access permissions is a bit more complicated, as there is no way to get the full list of mailboxes to which a given user has been granted such permissions in one go. In turn, this means we have to iterate over each and every mailbox, and while you can certainly achieve this via the pipeline, for any large environments you’d probably want to use a full blown script, with proper error handling and such.

Hence, this article, and its previous iterations. The logic of the script remains the same – get a list of all mailboxes of the desired type, iterate over each mailbox and check whether the specified user(s) have any Full access permissions on them, and remove the permissions. Here are the set of parameters supported by the script:

  • Identity – provide a list of users for which to remove the permissions. Mandatory. Aliased as -UserToRemove.
    Use any valid identifier supported by Exchange, such as UserPrincipalName, Email address or Alias.
    See the examples below on how to provide a a set of users via CSV file or by leveraging the built-in cmdlets.
  • IncludeSharedMailboxes – specify whether to remove permissions from Shared mailboxes. Optional.
  • IncludeResourceMailboxes – specify whether to remove permissions from Room, Equipment and Scheduling mailboxes. Optional.
  • WhatIf – use this parameter to “preview” the changes, without committing them.

The connectivity function of the script has been updated to use the Connect-ExchangeOnline cmdlet, should an existing session to ExO is not detected. Only the cmdlets required by the script will be loaded, in order to minimize its footprint. Needless to say, if you plan to use additional cmdlets, or leverage the script in an automated manner, make sure to update the Check-Connectivity function to best suit your needs!

The script also has a dependency on my Mailbox permissions inventory script, which you can get from GitHub. The reason for this is to ensure proper execution in large environments. Instead of leveraging the pipeline method, if more than 5 entries are provided as input for the Identity parameter, the script will call the Mailbox permissions inventory script to obtain a report of all Full access permissions within the organization, then filter it out based on the user(s) in question. To ensure proper processing in such scenarios, make sure to place your copy of the Mailbox permissions inventory script within the script directory. If the Mailbox permissions inventory script is not found or fails to execute for some reason, the script will fallback to using the pipeline method instead.

Without further ado, here are some examples of how to run the script. First, make sure to get your copy from GitHub. Then, prepare the list of user(s) against you want to run it. The below example uses a comma-separated list of users:

.\Remove_user_MBpermissionsV2.ps1 -Identity AdeleV,IsaiahL,DebraB,PradeepG

For each entry provided, the script will try to find a matching user object. If such is not found, or multiple matches are returned, the entry will be ignored.  For this reason, is best to use uniquely-valued identifiers, such as the UPN. Here’s an example of leveraging the output of the Get-Mailbox cmdlet as input for the script:

.\Remove_User_MBpermissionsv2.ps1 -Identity (Get-User -Filter {Department -eq "sales"}).UserPrincipalName

Of course, when running the script against a set of user, it’s a very good idea to “preview” the results first. To do so, specify the -WhatIf and -Verbose parameter, with the latter spilling out additional details of the script’s execution:

.\Remove_User_MBpermissionsv2.ps1 -Identity (Get-User -Filter {Department -eq "sales"}).UserPrincipalName -Verbose -WhatIf

Lastly, to cover all supported mailbox types, use the and switches. By default, the script runs only against user mailboxes.

.\Remove_User_MBpermissionsv2.ps1 -Identity (Get-User -Filter {Department -eq "sales"}).UserPrincipalName -IncludeSharedMailboxes -IncludeResourceMailboxes -Verbose -WhatIf

Here’s also an example of how to use a CSV file as input, where the specified CSV file has a column UserPrincipalName to designate the user:

.\Remove_User_MBpermissionsv2.ps1 -Identity (Import-Csv C:\Temp\testtttt.csv).UserPrincipalName -WhatIf


One thing to note is that the script will only generate output if run against more than 5 users. The reason for this is that the  Remove-MailboxPermission cmdlet does not generate any input, and we manually handle that part. But, when using the pipeline method (i.e. for less than 5 users), there is no way to know which mailboxes the permissions were removed from. If there is output generated, it will be dumped to the console and exported to a CSV file in the script’s directory.

Another important bit – the script no longer works against on-premises Exchange installs. As it leverages the “V3” Exchange Online module, a different connectivity method is used, so you have to replace that if you want to run the script against on-premises server. You will also have to replace the Get-ExOMailbox cmdlet, which at least in theory adds some improvements in terms of speed. This is the only REST cmdlet currently used by the script, as the Get-ExOMailboxPermission cmdlet does not return the UserSid property in its output, so we’re using the good old Get-MailboxPermission instead.

And that’s all there is to the script. It’s also worth mentioning some other scripts that might be relevant. If you want to address the “remove folder permissions” scenario as well, refer to the script detailed in this article. Similarly, this article addresses the scenario where you want to ‘clear’ user’s membership, as in remove him from all groups within Office 365.

Leave a Reply

Your email address will not be published. Required fields are marked *

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