Exchange Online security

How to check shared mailbox sign-in in Exchange Online

Check if shared mailbox accounts can sign in with Exchange Online and Microsoft Graph PowerShell, review them in the admin centre, or run Altivane's Shared Mailbox Sign-In report for a rated list.

By the Published Updated

To check shared mailbox sign-in in Exchange Online, list the shared mailboxes with Get-EXOMailbox, then read each mailbox's account with Get-MgUser and keep those where AccountEnabled is true. Microsoft says to block sign-in on these accounts and keep it blocked. The script makes 1 Graph call for each mailbox, so a large tenant is slow.

Choose the method that fits the job
MethodBest fit
PowerShellA CSV of every shared, room and equipment mailbox with its sign-in state and licences.
Admin centreChecking a few shared mailboxes manually, without a script.
AltivaneRecommended for regular checks, with each mailbox rated and a workbook to keep.

Before you start

For the mailbox list, use an account in the Organization Management, Recipient Management or View-Only Management role group. The script asks Microsoft Graph for User.Read.All and LicenseAssignment.Read.All (for licence names); your organisation may require administrator consent.

The script also covers room and equipment mailboxes, and leaves out user, soft-deleted and inactive mailboxes. The CSV is a snapshot of the state when the script runs. The examples read and export and change nothing, apart from the admin centre filter, a saved view every admin sees until it is deleted.

Option 1

Check shared mailbox sign-in with PowerShell

Install the modules once, then connect to both services, read each mailbox's account and export the result. Any error stops the script before it writes a partial CSV.

PowerShell
# Install once, if the modules are not already installed.
Install-Module ExchangeOnlineManagement -Scope CurrentUser
Install-Module Microsoft.Graph.Authentication -Scope CurrentUser
Install-Module Microsoft.Graph.Users -Scope CurrentUser
Install-Module Microsoft.Graph.Identity.DirectoryManagement -Scope CurrentUser
PowerShell
$ErrorActionPreference = 'Stop'
Connect-ExchangeOnline
Connect-MgGraph -Scopes 'User.Read.All', 'LicenseAssignment.Read.All' -NoWelcome
try {
    $types = 'SharedMailbox', 'RoomMailbox', 'EquipmentMailbox'
    $mailboxes = @(Get-EXOMailbox -RecipientTypeDetails $types -ResultSize Unlimited)
    if ($mailboxes.Count -eq 0) {
        Write-Output 'No shared, room or equipment mailboxes were found.'
    } else {
        $skuNames = @{}
        foreach ($sku in Get-MgSubscribedSku -All) { $skuNames[$sku.SkuId] = $sku.SkuPartNumber }
        $report = @(foreach ($mailbox in $mailboxes) {
            $id = [string]$mailbox.ExternalDirectoryObjectId
            if (-not $id) { throw "No directory ID for $($mailbox.DisplayName)." }
            $user = Get-MgUser -UserId $id -Property 'id,accountEnabled,assignedLicenses'
            if ($null -eq $user.AccountEnabled) {
                throw "No sign-in state for $($mailbox.DisplayName)."
            }
            $licences = foreach ($license in $user.AssignedLicenses) {
                if ($skuNames.ContainsKey($license.SkuId)) { $skuNames[$license.SkuId] }
                else { $license.SkuId }
            }
            [pscustomobject]@{
                Mailbox = $mailbox.DisplayName
                MailboxAddress = $mailbox.PrimarySmtpAddress.ToString()
                MailboxType = $mailbox.RecipientTypeDetails
                SignIn = if ($user.AccountEnabled) { 'Allowed' } else { 'Blocked' }
                Licences = (@($licences | Sort-Object) -join ', ')
            }
        })
        $report | Sort-Object SignIn, Mailbox |
            Export-Csv -Path './shared-mailbox-sign-in.csv' -NoTypeInformation -Encoding utf8
        $allowed = @($report | Where-Object { $_.SignIn -eq 'Allowed' }).Count
        Write-Output "$allowed of $($report.Count) mailbox accounts can sign in."
    }
} finally {
    Disconnect-MgGraph | Out-Null
    Disconnect-ExchangeOnline -Confirm:$false
}

The CSV has 1 row for each mailbox, with the accounts that can sign in first. To check shared mailboxes only, change the $types list to 'SharedMailbox'. To drop licence names, remove the Get-MgSubscribedSku line, the $licences lines and the LicenseAssignment.Read.All scope.

Check a single mailbox

The export above disconnects when it finishes, so reconnect to both services, then read 1 mailbox.

PowerShell
# Run while connected to Exchange Online and Microsoft Graph. Replace the example mailbox.
$mailbox = Get-EXOMailbox -PrimarySmtpAddress 'support@example.com'
$id = $mailbox.ExternalDirectoryObjectId
Get-MgUser -UserId $id -Property 'userPrincipalName,accountEnabled' |
    Select-Object UserPrincipalName,AccountEnabled

AccountEnabled is True when the account can sign in.

Option 2

Review shared mailbox sign-in in the admin centre

  1. Sign in to the Microsoft 365 admin centre for the correct tenant.
  2. Go to Teams & Groups > Shared mailboxes and note the names. Room and equipment mailboxes are in the Exchange admin centre, under Recipients > Resources.
  3. Go to Users > Active users.
  4. Open the Filter set list and select New filter. In the Custom filter pane, name the filter, choose allowed users under Sign-in status and select Add. The filter is saved as a view every admin sees.
  5. Look for the names from step 2 in the list. Each one listed has an account that can sign in.
  6. To see an account's licences, select it and open the Licenses and Apps tab. Close the pane without saving anything.
  7. To delete the filter afterwards, switch to it, then choose Filter set, Edit filter, the ellipsis (...) and Delete.

This suits a few shared mailboxes. It does not suit a full review: the filter lists every account that can sign in, so you compare names manually, and there is nothing to export.

Common questions

Does a blocked account stop people using the shared mailbox?

No. Microsoft says delegates reach a shared mailbox through their own mailbox, and that the shared mailbox's account is not intended for direct sign-in. Blocking changes the tenant, so it is not part of this guide; Microsoft's steps are in Block Microsoft 365 user accounts with PowerShell. To see who can open each mailbox, see how to export mailbox permissions in Exchange Online.

Why does a shared mailbox show a licence?

A shared mailbox needs no licence up to 50 GB. More than that, or archiving or litigation hold, needs an Exchange Online Plan 2 licence; for the last two, Plan 1 with the Archiving add-on also works. The licence and the sign-in state are separate settings on the account, so read both.

Why does the script stop with an error?

It stops on the first error, so no partial CSV is written. A permission error usually means Graph consent for User.Read.All or LicenseAssignment.Read.All is missing, or the account lacks 1 of the roles above. It also stops on a mailbox with no directory ID, as each account is looked up by that ID.

Microsoft references

Technical references checked on 5 October 2026. The example scripts have been reviewed and syntax checked; they have not been run against a live tenant.

Talk to us about Altivane

Questions, or pricing? Get in touch.

Contact us