All scripts
Microsoft 365 617
Calendar Permissions Report
Audits Calendar folder permissions across Exchange Online mailboxes, so you can see who has access to whose calendar and at what level before an access review or an offboarding.
Get-CalendarPermissionsReport.ps1
<#
.SYNOPSIS
Reports calendar folder permissions across user mailboxes in Exchange Online.
.DESCRIPTION
Connects to Exchange Online and checks the Calendar folder permissions for every
user mailbox, or a specific list you provide. Useful before an access review, an
offboarding, or when you just want to know who can see or edit someone else's
calendar. Skips the Default and Anonymous entries unless you ask for them, since
those show up on almost every calendar and just add noise to the report.
.PARAMETER Mailboxes
Optional list of specific mailbox addresses to check. If you leave this out, the
script checks every user mailbox in the tenant.
.PARAMETER IncludeDefaultAndAnonymous
Switch to include the Default and Anonymous permission entries in the results.
Off by default.
.PARAMETER OutputPath
Path for the CSV report. Defaults to CalendarPermissionsReport.csv in the current
folder.
.EXAMPLE
.\Get-CalendarPermissionsReport.ps1
Checks every user mailbox in the tenant and writes CalendarPermissionsReport.csv.
.EXAMPLE
.\Get-CalendarPermissionsReport.ps1 -Mailboxes "jane@contoso.com","sales@contoso.com" -OutputPath "C:\Reports\calendars.csv"
Checks only the two named mailboxes and writes the report to the given path.
.AUTHOR
Shehryar Hassan
#>
[CmdletBinding()]
param(
[string[]]$Mailboxes,
[switch]$IncludeDefaultAndAnonymous,
[string]$OutputPath = ".\CalendarPermissionsReport.csv"
)
if (-not (Get-Module -ListAvailable -Name ExchangeOnlineManagement)) {
Write-Error "The ExchangeOnlineManagement module is not installed. Run: Install-Module ExchangeOnlineManagement"
return
}
Import-Module ExchangeOnlineManagement
try {
Connect-ExchangeOnline -ShowBanner:$false -ErrorAction Stop
}
catch {
Write-Error "Could not connect to Exchange Online. $_"
return
}
if (-not $Mailboxes) {
Write-Host "No mailbox list given, pulling every user mailbox in the tenant..."
$Mailboxes = (Get-EXOMailbox -RecipientTypeDetails UserMailbox -ResultSize Unlimited).PrimarySmtpAddress
}
$results = New-Object System.Collections.Generic.List[Object]
$total = $Mailboxes.Count
$counter = 0
foreach ($mailbox in $Mailboxes) {
$counter++
Write-Progress -Activity "Checking calendar permissions" -Status "$mailbox ($counter of $total)" -PercentComplete (($counter / $total) * 100)
$calendarFolder = "$mailbox`:\Calendar"
try {
$permissions = Get-MailboxFolderPermission -Identity $calendarFolder -ErrorAction Stop
}
catch {
Write-Warning "Skipped $mailbox, could not read the Calendar folder. $_"
continue
}
foreach ($permission in $permissions) {
if (-not $IncludeDefaultAndAnonymous -and $permission.User.DisplayName -in @("Default", "Anonymous")) {
continue
}
$results.Add([PSCustomObject]@{
Mailbox = $mailbox
GrantedTo = $permission.User.DisplayName
AccessRights = ($permission.AccessRights -join ", ")
SharingPermFlags = $permission.SharingPermissionFlags
})
}
}
Write-Progress -Activity "Checking calendar permissions" -Completed
if ($results.Count -eq 0) {
Write-Host "No calendar permissions found to report."
}
else {
$results | Sort-Object Mailbox, GrantedTo | Export-Csv -Path $OutputPath -NoTypeInformation
Write-Host "Done. $($results.Count) permission entries written to $OutputPath"
}
Disconnect-ExchangeOnline -Confirm:$false
Read it before you run it, and test in a safe tenant first.