How to Create a Report About Exchange Online Mailbox Permissions

Make Sure The Right People Access Your Exchange Online Mailboxes

One of the recommendations made in the Office 365 for IT Pros eBook is that tenant administrators should conduct periodic reviews of permissions assigned to mailboxes to ensure that the right people (other than the mailbox owners) have access, perhaps by creating an Exchange Online mailbox permissions report. A recent request in the Microsoft Technical Community prompted me to look at the situation again to make sure that our advice was still accurate (it is).

Scripting a Report

I responded to the original question with some quick and dirty PowerShell but decided that a better job could be done. If you use the Get-MailboxPermission cmdlet to examine permissions on an Exchange Online mailbox, several types exist:

  • The mailbox owner (if you’re unsure, run Get-MailboxPermission with the -Owner parameter to see this entry).
  • Permissions needed by Exchange Online to access the mailbox for different purposes, such as removing items during retention policy processing. These entries appear like EXOForest\Organization Management, where “EXOForest” is the name of the Exchange Online forest hosting the mailbox.
  • An entry for “JitUsers” (Just in time access) assigned to Microsoft support personnel when they need access to the mailbox.
  • System entries like NT AUTHORITY\System and NT AUTHORITY\NETWORK SERVICE.

For the purpose of this exercise we don’t care about these permissions because they exist on all mailboxes. What we’re looking for are delegated permissions used to grant non-owner accounts access to the mailbox. Vasil Michev, our esteemed technical editor, has a script in the TechNet Gallery to report non-standard permissions, but there’s always room for another PowerShell answer to a problem.

My script (the full version of the Exchange Online mailbox permissions report is available on GitHub) selects user and shared mailboxes (those most likely to have extra permissions). For each mailbox, we extract the permissions and look for those assigned to other Office 365 accounts. We store details of these permissions into a list that is written out to a CSV file after all mailboxes are processed. Here’s the basic idea:

# Quick and simple script to generate a report of non-standard permissions applied to Exchange Online user and shared mailboxes
# Needs to be connected to Exchange Online PowerShell with an administrative account to run
CLS
Write-Host "Fetching mailboxes"
[array]$Mbx = Get-Mailbox -RecipientTypeDetails UserMailbox, SharedMailbox -ResultSize Unlimited | Select DisplayName, UserPrincipalName, RecipientTypeDetails
If ($Mbx.Count -eq 0) { Write-Error "No mailboxes found. Script exiting..." -ErrorAction Stop } 
# We have some mailboxes, so we can process them...
CLS
$Report = [System.Collections.Generic.List[Object]]::new() # Create output file 
$ProgressDelta = 100/($Mbx.count); $PercentComplete = 0; $MbxNumber = 0
ForEach ($M in $Mbx) {
    $MbxNumber++
    $MbxStatus = $M.DisplayName + " ["+ $MbxNumber +"/" + $Mbx.Count + "]"
    Write-Progress -Activity "Processing mailbox" -Status $MbxStatus -PercentComplete $PercentComplete
    $PercentComplete += $ProgressDelta
    $Permissions = Get-MailboxPermission -Identity $M.UserPrincipalName | ? {$_.User -Like "*@*" }    
    If ($Null -ne $Permissions) {
       # Grab each permission and output it into the report
       ForEach ($Permission in $Permissions) {
         $ReportLine  = [PSCustomObject] @{
           Mailbox    = $M.DisplayName
           UPN        = $M.UserPrincipalName
           Permission = $Permission | Select -ExpandProperty AccessRights
           AssignedTo = $Permission.User
           MailboxType = $M.RecipientTypeDetails } 
         $Report.Add($ReportLine) }
     } 
}     
$Report | Sort -Property @{Expression = {$_.MailboxType}; Ascending= $False}, Mailbox | Export-CSV c:\temp\MailboxPermissions.csv -NoTypeInformation
Write-Host "All done." $Mbx.Count "mailboxes scanned. Report of non-standard permissions available in c:\temp\MailboxPermissions.csv"

The CSV file is stored by user mailbox and then shared mailbox (you must use a calculated expression to sort by multiple properties when the first property is sorted in descending order).

Note: The full Exchange Online mailbox permissions report script uses the REST-based cmdlets in the Exchange Online Management module.

Reviewing the Results

As you can see from Figure 1, the Exchange Online mailbox permissions report details FullAccess and SendAs permissions assigned to mailboxes. The fact that these permissions exist isn’t an issue by itself as the permissions are usually well-justified. For instance, FullAccess permission is needed by delegates to have full control over a shared or user mailbox (as in the case of Outlook Mobile delegation). However, it’s important to review each assignment to understand if it is still valid and necessary. If not, the permission should be removed.

Exchange Online mailbox permissions report
Figure 1: Reporting mailbox permissions

The Exchange Online mailbox permissions report doesn’t include folder-level permissions assigned by Outlook. These permissions can be reviewed with the Get-MailboxFolderPermission cmdlet. To find all such permissions for a mailbox, you would need to run Get-MailboxFolderStatistics to generate a list of mailbox folders and then check each folder to see if any permissions exist. I’ll cover how to do this in a future post.


For many more examples of using PowerShell to manage Exchange Online and other Office 365 components, subscribe to the Office 365 for IT Pros eBook and find some hidden jewels.

10 Replies to “How to Create a Report About Exchange Online Mailbox Permissions”

  1. Once you have the data, what’s a good process for getting it distributed to users then collecting their responses?

    1. That depends on your organization. One simple approach is to send email to the owner of each mailbox with permissions set to as them if the permissions are still required,.

  2. + CategoryInfo : InvalidOperation: (:) [], RuntimeException
    + FullyQualifiedErrorId : InvokeMethodOnNull

    You cannot call a method on a null-valued expression.
    At C:\md\permission.ps1:27 char:10
    + $Report.Add($ReportLine) }
    + ~~~~~~~~~~~~~~~~~~~~~~~~
    + CategoryInfo : InvalidOperation: (:) [], RuntimeException
    + FullyQualifiedErrorId : InvokeMethodOnNull

    You cannot call a method on a null-valued expression.
    At C:\md\permission.ps1:27 char:10
    + $Report.Add($ReportLine) }
    + ~~~~~~~~~~~~~~~~~~~~~~~~
    + CategoryInfo : InvalidOperation: (:) [], RuntimeException
    + FullyQualifiedErrorId : InvokeMethodOnNull

    You cannot call a method on a null-valued expression.
    At C:\md\permission.ps1:27 char:10
    + $Report.Add($ReportLine) }
    + ~~~~~~~~~~~~~~~~~~~~~~~~
    + CategoryInfo : InvalidOperation: (:) [], RuntimeException
    + FullyQualifiedErrorId : InvokeMethodOnNull

    We are getting this error when we use this script.

  3. Is there a way to report if a mail-enabled security group is assigned permissions? The script appears to report if a user is assigned, but not if a group is.

    1. The script has a line to filter out anything but users:

      $Permissions = Get-MailboxPermission -Identity $M.UserPrincipalName | ? {$_.User -Like “*@*” }

      Use a different filter to include whatever you want to report, like:

      $Permissions = Get-MailboxPermission -Identity Cservices | ? {$_.User -ne “NT AUTHORITY\SELF”}

      But if you include mail-enabled security groups, you’ll need to change the code to report the permissions because the current code assumes a mailbox.

Leave a Reply

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