All scripts
Governance 576

Export-SharedMailboxPermissionsReport

A PowerShell script that reports on shared mailbox sizes and permissions in Exchange Online, so you can spot large mailboxes or unexpected access before they cause problems.

Export-SharedMailboxPermissionsReport.ps1
<#
.SYNOPSIS
    Reports on shared mailboxes in Exchange Online, including size and who has Full Access or Send As permissions.

.DESCRIPTION
    Connects to Exchange Online and loops through every shared mailbox in the tenant. For each one it
    pulls the mailbox size, item count, and a list of users with Full Access or Send As rights. This is
    useful for spotting shared mailboxes that have grown too large, or that have more people with access
    than expected. Results are exported to a CSV file so they are easy to review or hand off.

.PARAMETER OutputPath
    Path to the CSV file that the report is written to. Defaults to a timestamped file in the current folder.

.EXAMPLE
    .\Export-SharedMailboxPermissionsReport.ps1

    Connects to Exchange Online, prompts for sign in if needed, and writes a report to
    SharedMailboxPermissionsReport-<date>.csv in the current folder.

.EXAMPLE
    .\Export-SharedMailboxPermissionsReport.ps1 -OutputPath C:\Reports\shared-mailboxes.csv

    Writes the report to a specific path instead of the default location.

.AUTHOR
    Shehryar Hassan
#>

[CmdletBinding()]
param(
    [string]$OutputPath = "SharedMailboxPermissionsReport-$(Get-Date -Format 'yyyy-MM-dd').csv"
)

if (-not (Get-Module -ListAvailable -Name ExchangeOnlineManagement)) {
    Write-Error "The ExchangeOnlineManagement module is not installed. Run: Install-Module ExchangeOnlineManagement"
    return
}

Import-Module ExchangeOnlineManagement

$existingSession = Get-ConnectionInformation -ErrorAction SilentlyContinue
if (-not $existingSession) {
    Connect-ExchangeOnline -ShowBanner:$false
}

Write-Host "Getting shared mailboxes..."
$sharedMailboxes = Get-EXOMailbox -RecipientTypeDetails SharedMailbox -ResultSize Unlimited

$report = foreach ($mailbox in $sharedMailboxes) {
    Write-Host "Checking $($mailbox.PrimarySmtpAddress)"

    $stats = Get-EXOMailboxStatistics -Identity $mailbox.PrimarySmtpAddress

    $sizeMB = 0
    if ($stats.TotalItemSize) {
        $sizeText = $stats.TotalItemSize.ToString()
        if ($sizeText -match '\(([\d,]+)\s+bytes\)') {
            $sizeMB = [math]::Round(($matches[1] -replace ',', '') / 1MB, 0)
        }
    }

    $fullAccessUsers = Get-EXOMailboxPermission -Identity $mailbox.PrimarySmtpAddress |
        Where-Object { $_.AccessRights -contains "FullAccess" -and -not $_.IsInherited -and $_.User -notlike "NT AUTHORITY\SELF" } |
        Select-Object -ExpandProperty User

    $sendAsUsers = Get-EXORecipientPermission -Identity $mailbox.PrimarySmtpAddress |
        Where-Object { $_.AccessRights -contains "SendAs" -and $_.Trustee -notlike "NT AUTHORITY\SELF" } |
        Select-Object -ExpandProperty Trustee

    [PSCustomObject]@{
        DisplayName     = $mailbox.DisplayName
        PrimarySmtp     = $mailbox.PrimarySmtpAddress
        ItemCount       = $stats.ItemCount
        SizeMB          = $sizeMB
        FullAccessUsers = ($fullAccessUsers -join "; ")
        SendAsUsers     = ($sendAsUsers -join "; ")
        FullAccessCount = @($fullAccessUsers).Count
    }
}

$report | Sort-Object -Property SizeMB -Descending | Export-Csv -Path $OutputPath -NoTypeInformation -Encoding UTF8

Write-Host "Report saved to $OutputPath"
Write-Host "$($report.Count) shared mailboxes checked."

$largeMailboxes = $report | Where-Object { $_.SizeMB -gt 40000 }
if ($largeMailboxes) {
    Write-Warning "$($largeMailboxes.Count) shared mailbox(es) are over 40 GB and close to the 50 GB free size limit."
}

Read it before you run it, and test in a safe tenant first.