Skip to content

Commit ba0d783

Browse files
authored
Merge pull request #932 from ojopiyo/patch-19
Patch 19
2 parents c8c618c + 94da114 commit ba0d783

File tree

4 files changed

+251
-0
lines changed

4 files changed

+251
-0
lines changed
328 KB
Loading
58.7 KB
Loading
Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,57 @@
1+
[
2+
{
3+
"name": "mailbox-delegation-audit",
4+
"source": "pnp",
5+
"title": "Mailbox Delegation Audit",
6+
"shortDescription": "This script connects to Exchange Online, enumerates mailboxes, and reports FullAccess, SendAs, and SendOnBehalf delegates.",
7+
"url": "https://pnp.github.io/script-samples/mailbox-delegation-audit/README.html",
8+
"longDescription": [
9+
"Produces a consolidated mailbox delegation report across user and shared mailboxes for governance, compliance, and access reviews."
10+
],
11+
"creationDateTime": "2026-03-07",
12+
"updateDateTime": "2026-03-07",
13+
"products": [
14+
"Office"
15+
],
16+
"metadata": [
17+
{
18+
"key": "POWERSHELL",
19+
"value": "7.2.0"
20+
}
21+
],
22+
"categories": [
23+
"Report",
24+
"Security"
25+
],
26+
"tags": [
27+
"Connect-ExchangeOnline",
28+
"Get-ExoMailbox",
29+
"Get-ExoMailboxPermission",
30+
"Get-ExoRecipientPermission",
31+
"Export-Csv"
32+
],
33+
"thumbnails": [
34+
{
35+
"type": "image",
36+
"order": 100,
37+
"url": "https://raw.githubusercontent.com/pnp/script-samples/main/scripts/mailbox-delegation-audit/assets/preview.png",
38+
"alt": "Preview of the sample Mailbox Delegation Audit"
39+
}
40+
],
41+
"authors": [
42+
{
43+
"gitHubAccount": "ojopiyo",
44+
"company": "",
45+
"pictureUrl": "https://github.com/ojopiyo.png",
46+
"name": "Josiah Opiyo"
47+
}
48+
],
49+
"references": [
50+
{
51+
"name": "Exchange Online PowerShell module",
52+
"description": "Learn how to connect to Exchange Online and use Exchange Online PowerShell cmdlets.",
53+
"url": "https://learn.microsoft.com/powershell/exchange/connect-to-exchange-online-powershell"
54+
}
55+
]
56+
}
57+
]
Lines changed: 194 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,194 @@
1+
# Mailbox Delegation Audit
2+
3+
## Professional Summary
4+
5+
This script connects to Exchange Online, enumerates all user and shared mailboxes, and produces a consolidated report of every delegate with:
6+
7+
- **FullAccess**
8+
- **SendAs**
9+
- **SendOnBehalf**
10+
11+
permissions per mailbox. The output is optimized for large tenants and can be exported to CSV or consumed by downstream governance and audit processes.
12+
13+
## Why it matters
14+
15+
In most organisations, mailbox delegation grows organically-shared mailboxes, executive assistants, team mailboxes, and legacy access that no one remembers granting. Over time, this creates risk: excessive access, stale permissions for leavers, and a lack of clear ownership.
16+
17+
This script gives Microsoft 365 engineers a single, authoritative view of who can read from, and send as/on behalf of, any mailbox. It supports:
18+
19+
- Access reviews for security and compliance
20+
- Offboarding checks to ensure leavers lose access
21+
- Audit evidence for internal and external regulators
22+
- Cleanup projects to remove unnecessary delegation
23+
24+
## Benefits
25+
26+
- Centralised visibility: One report covering all key mailbox delegate permissions.
27+
- Risk reduction: Quickly identify over-permissioned or unexpected delegates.
28+
- Operational efficiency: Avoid manual, per-mailbox checks in the EAC.
29+
- Audit-ready output: CSV-friendly structure for Power BI, Excel, or GRC tools.
30+
- Scales to large tenants: Uses efficient querying and avoids unnecessary processing.
31+
32+
## Usage
33+
34+
1. Register an Azure AD App
35+
2. Assign Exchange.ManageAsApp application permissions
36+
3. Upload a certificate and note:
37+
- Client ID
38+
- Tenant ID
39+
- Certificate Thumbprint
40+
4. Run the script from a secure automation host
41+
5. Review or export the $Report object
42+
43+
# [PnP PowerShell](#tab/pnpps)
44+
45+
```powershell
46+
47+
48+
49+
param(
50+
[Parameter(Mandatory)]
51+
[string]$TenantId,
52+
53+
[Parameter(Mandatory)]
54+
[string]$ClientId,
55+
56+
[Parameter(Mandatory)]
57+
[string]$CertificateThumbprint,
58+
59+
[string]$OutputPath = ".\MailboxDelegatesReport.csv",
60+
61+
[switch]$IncludeRoomAndEquipment
62+
)
63+
64+
# Connect using App-Only Certificate Authentication
65+
Connect-ExchangeOnline `
66+
-AppId $ClientId `
67+
-CertificateThumbprint $CertificateThumbprint `
68+
-Organization $TenantId `
69+
-ShowBanner:$false
70+
71+
# Determine mailbox types
72+
$recipientTypes = @("UserMailbox", "SharedMailbox")
73+
if ($IncludeRoomAndEquipment) {
74+
$recipientTypes += "RoomMailbox", "EquipmentMailbox"
75+
}
76+
77+
# Retrieve mailboxes
78+
$mailboxes = Get-ExoMailbox `
79+
-RecipientTypeDetails $recipientTypes `
80+
-ResultSize Unlimited `
81+
-Properties DisplayName, PrimarySmtpAddress, GrantSendOnBehalfTo
82+
83+
# Pre-size collection for performance
84+
$Report = New-Object System.Collections.Generic.List[object]
85+
86+
foreach ($mailbox in $mailboxes) {
87+
88+
$identity = $mailbox.PrimarySmtpAddress.ToString()
89+
90+
# --- FullAccess ---
91+
$fullAccess = Get-ExoMailboxPermission -Identity $identity -ResultSize Unlimited |
92+
Where-Object {
93+
$_.AccessRights -contains "FullAccess" -and
94+
-not $_.IsInherited -and
95+
$_.User -ne "NT AUTHORITY\SELF"
96+
}
97+
98+
foreach ($perm in $fullAccess) {
99+
$Report.Add([pscustomobject]@{
100+
MailboxIdentity = $identity
101+
MailboxDisplayName = $mailbox.DisplayName
102+
RecipientType = $mailbox.RecipientTypeDetails
103+
PermissionType = "FullAccess"
104+
DelegateIdentity = $perm.User
105+
IsInherited = $perm.IsInherited
106+
AccessRights = ($perm.AccessRights -join ",")
107+
})
108+
}
109+
110+
# --- SendAs ---
111+
$sendAs = Get-ExoRecipientPermission -Identity $identity -ResultSize Unlimited |
112+
Where-Object {
113+
$_.AccessRights -contains "SendAs" -and
114+
-not $_.IsInherited -and
115+
$_.Trustee -ne "NT AUTHORITY\SELF"
116+
}
117+
118+
foreach ($perm in $sendAs) {
119+
$Report.Add([pscustomobject]@{
120+
MailboxIdentity = $identity
121+
MailboxDisplayName = $mailbox.DisplayName
122+
RecipientType = $mailbox.RecipientTypeDetails
123+
PermissionType = "SendAs"
124+
DelegateIdentity = $perm.Trustee
125+
IsInherited = $perm.IsInherited
126+
AccessRights = ($perm.AccessRights -join ",")
127+
})
128+
}
129+
130+
# --- SendOnBehalf ---
131+
if ($mailbox.GrantSendOnBehalfTo) {
132+
foreach ($delegate in $mailbox.GrantSendOnBehalfTo) {
133+
134+
$resolved = Get-ExoRecipient -Identity $delegate -ErrorAction SilentlyContinue
135+
$delegateIdentity = if ($resolved) { $resolved.PrimarySmtpAddress } else { $delegate.ToString() }
136+
137+
$Report.Add([pscustomobject]@{
138+
MailboxIdentity = $identity
139+
MailboxDisplayName = $mailbox.DisplayName
140+
RecipientType = $mailbox.RecipientTypeDetails
141+
PermissionType = "SendOnBehalf"
142+
DelegateIdentity = $delegateIdentity
143+
IsInherited = $false
144+
AccessRights = "SendOnBehalf"
145+
})
146+
}
147+
}
148+
}
149+
150+
# Export
151+
$Report |
152+
Sort-Object MailboxIdentity, PermissionType, DelegateIdentity |
153+
Export-Csv -Path $OutputPath -NoTypeInformation -Encoding UTF8
154+
155+
Write-Host "Mailbox delegate report generated: $OutputPath" -ForegroundColor Green
156+
157+
158+
```
159+
160+
## Output
161+
162+
The script produces a structured dataset with:
163+
164+
- MailboxIdentity
165+
- MailboxDisplayName
166+
- RecipientType
167+
- PermissionType
168+
- DelegateIdentity
169+
- IsInherited
170+
- AccessRights
171+
172+
## Notes
173+
174+
- Run periodically and store historical CSVs to track permission drift over time.
175+
- Consider feeding the CSV into Power BI for visual access review dashboards.
176+
- For very large tenants, you can parallelise mailbox processing with ForEach-Object -Parallel in PowerShell 7, if your operational standards allow it.
177+
178+
## Contributors
179+
180+
| Author(s) |
181+
|-----------|
182+
| [Josiah Opiyo](https://github.com/ojopiyo) |
183+
184+
*Built with a focus on automation, governance, least privilege, and clean Microsoft 365 tenants-helping M365 admins gain visibility and reduce operational risk.*
185+
186+
## Version history
187+
188+
Version|Date|Comments
189+
-------|----|--------
190+
1.0|Mar 01, 2026|Initial release
191+
192+
[!INCLUDE [DISCLAIMER](../../docfx/includes/DISCLAIMER.md)]
193+
<img src="https://m365-visitor-stats.azurewebsites.net/script-samples/scripts/mailbox-delegation-audit" aria-hidden="true" />
194+

0 commit comments

Comments
 (0)