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.
| Method | Best fit |
|---|---|
| PowerShell | A CSV of every shared, room and equipment mailbox with its sign-in state and licences. |
| Admin centre | Checking a few shared mailboxes manually, without a script. |
| Altivane | Recommended 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. and LicenseAssignment. (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.
# 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$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. scope.
Check a single mailbox
The export above disconnects when it finishes, so reconnect to both services, then read 1 mailbox.
# 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,AccountEnabledAccountEnabled is True when the account can sign in.
Option 2
Review shared mailbox sign-in in the admin centre
- Sign in to the Microsoft 365 admin centre for the correct tenant.
- Go to Teams & Groups > Shared mailboxes and note the names. Room and equipment mailboxes are in the Exchange admin centre, under Recipients > Resources.
- Go to Users > Active users.
- 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.
- Look for the names from step 2 in the list. Each one listed has an account that can sign in.
- To see an account's licences, select it and open the Licenses and Apps tab. Close the pane without saving anything.
- 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.
Option 3 ยท Recommended for regular checks
Run Altivane's Shared Mailbox Sign-In report
- Open Altivane and choose the tenant.
- Run the Shared Mailbox Sign-In report for Exchange Online.
- Open the Excel workbook the run wrote and read its rows: Mailbox, Mailbox address, Mailbox type, User principal name, Sign-in, Licensed, Licences and Status.
The report reads the accounts from Microsoft Graph, so it needs User.; without Organization. the Licences column shows licence IDs, not names. Status rates each row: Warning for an account that can sign in, Review for a licensed room that can (Teams Rooms devices sign in that way) or an account it could not read, and OK when sign-in is blocked. Warnings sort first. The workbook is a file to keep, and a selected report also runs in scheduled runs.
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. or LicenseAssignment. 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.