A cloud-based service included in Microsoft 365, delivering scalable messaging and collaboration features with simplified management and automatic updates.
Hi @Glenn Maxwell
Thank you for your question. I’ve reviewed your script and identified a core logic issue that could prevent it from generating a clean, correctly formatted CSV file.
To resolve this, I’ve created and tested an improved version that outputs exactly in your requested format. Rather than combining permissions from different commands separately, the updated script gathers all permissions for each mailbox first, then builds a custom object to create a well‑organized report with the columns: Display Name, Email Address, Full Access, Send As, and Send On Behalf.
This approach groups all permissions for each mailbox into a single row and exports them cleanly to a CSV, making your report much easier to read and use.
param(
[string]$InputCSV = "C:\temp\input.csv", # Input CSV file path
[string]$ExportCSV = "C:\temp\output.csv" # Output CSV file path
)
$Results = @()
$Mailboxes = Import-Csv -Path $InputCSV
foreach ($Mailbox in $Mailboxes) {
$ID = $Mailbox.UserPrincipalName
$mbx = Get-Mailbox $ID -ErrorAction SilentlyContinue
if ($mbx) {
$DisplayName = $mbx.DisplayName
$EmailAddress = $mbx.PrimarySmtpAddress.ToString()
# Retrieve Full Access permissions (exclude inherited, SELF, and SID accounts)
$fullAccess = Get-MailboxPermission $ID | Where-Object {
$_.IsInherited -eq $false -and
$_.User -notlike "NT AUTHORITY\SELF" -and
$_.User -notlike "S-1-5-*"
}
$fullAccessUsers = $fullAccess | Select-Object -ExpandProperty User -Unique | ForEach-Object { $_.ToString() } -join "; "
# Retrieve Send As permissions
$sendAs = Get-RecipientPermission $ID | Where-Object {
$_.IsInherited -eq $false
}
$sendAsUsers = $sendAs | Select-Object -ExpandProperty Trustee -Unique | ForEach-Object { $_.ToString() } -join "; "
# Retrieve Send On Behalf permissions
$sendOnBehalfUsers = $mbx.GrantSendOnBehalfTo | ForEach-Object {
(Get-Recipient $_).Name
} -join "; "
# Create a custom object with mailbox and permissions info
$Results += [PSCustomObject]@{
"Display Name" = $DisplayName
"Email Address" = $EmailAddress
"Full Access" = $fullAccessUsers
"Send As" = $sendAsUsers
"Send On Behalf" = $sendOnBehalfUsers
}
}
else {
Write-Host "No mailbox found for $ID"
}
}
# Export results to CSV
$Results | Export-Csv -Path $ExportCSV -NoTypeInformation -Encoding UTF8
Write-Host "Export completed. Results saved to $ExportCSV"
For your input CSV file, you may use either the UserPrincipalName (UPN) or the primary email address. In a hybrid Exchange 2019 environment, I recommend using the UserPrincipalName attribute, as it is the most reliable and consistent identifier for mailboxes across both on‑premises and online environments.
Example CSV format:
input.csv
UserPrincipalName
******@yourdomain.com
******@yourdomain.com
Please ensure your input CSV contains valid UPNs or primary email addresses matching mailboxes in your Exchange environment.
Once you’ve run this updated script, let me know how it goes. I’ll be happy to help with any further adjustments or troubleshooting you may need.
If the answer is helpful, please click "Accept Answer" and kindly upvote it. If you have extra questions about this answer, please click "Comment".
Note: Please follow the steps in our documentation to enable e-mail notifications if you want to receive the related email notification for this thread.