Exporting shared mailbox permissions to a CSV

A demonstration of one way to get shared mailbox permissions exported to a CSV file. We needed both users, groups and users in groups (so, a recursive search). Only Shared mailboxes had to be included, we could identity these by a simple rule:

the first portion of the primary email address does not contain a dot

See line 126 and 127 for this rule if you need a different method.

Edit: make sure you replace CED\ with your own domain! Sorry bout that…

This export excludes Deny permissions and looks for users in groups up to 2 levels deep. Credits to Piotrek for his Get-ADNestedGroupMember function.

Script source:


#Module name: reportSharedMailboxPermissions
#Author: Jos Lieben (OGD)
#Date: 08-06-2016
#Script help: www.liebensraum.nl
#Purpose: writes a csv report of user and group permissions (recursive) on mailboxes with a . in their primary email prefix
#Requirements: run from Exchange Shell, requires AD module

ipmo ActiveDirectory

$users = Get-Mailbox -Resultsize Unlimited
$script:csvEntries = @()
$csvExportPath = "C:\Scripts\mailboxRights.csv"

function searchForUserOrGroup{
 param(
 [String]$name
 )
 $found = $False
 try{
 $adresult = Get-ADUser -filter{samAccountName -eq $name}
 if($adresult) {$found = $True}
 }catch{$Null}
 if($found -eq $False){
 try{
 $adresult = Get-ADGroup -filter{samAccountName -eq $name}
 if($adresult) {$found = $True}
 }catch{$Null}
 }
 if($found){
 return $adresult
 }else{
 return $False
 }
}

function Get-ADNestedGroupMembers {
 param ( 
 [Parameter(ValuefromPipeline=$true,mandatory=$true)][String] $GroupName, 
 [int] $nesting = -1, 
 [int]$circular = $null 
 ) 
 $table = $null 
 $nestedmembers = $null 
 $adgroupname = $null 
 $nesting++ 
 $ADGroupname = get-adgroup $groupname -properties memberof,members 
 $memberof = $adgroupname | select -expand memberof 
 if ($adgroupname){ 
 if ($circular){ 
 $nestedMembers = Get-ADGroupMember -Identity $GroupName -recursive 
 $circular = $null 
 } 
 else{ 
 $nestedMembers = Get-ADGroupMember -Identity $GroupName | sort objectclass -Descending
 if (!($nestedmembers)){
 $unknown = $ADGroupname | select -expand members
 if ($unknown){
 $nestedmembers=@()
 foreach ($member in $unknown){
 $nestedmembers += get-adobject $member
 }
 }

 }
 } 
 foreach ($nestedmember in $nestedmembers){ 
 $Props = @{Type=$nestedmember.objectclass;Name=$nestedmember.name;DisplayName="";ParentGroup=$ADgroupname.name;Enabled="";Nesting=$nesting;DN=$nestedmember.distinguishedname;Comment=""} 
 if ($nestedmember.objectclass -eq "user"){ 
 $nestedADMember = get-aduser $nestedmember -properties enabled,displayname 
 $table = new-object psobject -property $props 
 $table.enabled = $nestedadmember.enabled
 $table.name = $nestedadmember.samaccountname
 $table.displayname = $nestedadmember.displayname
 $table | select type,name,displayname,parentgroup,nesting,enabled,dn,comment 
 } 
 elseif ($nestedmember.objectclass -eq "group"){ 
 $table = new-object psobject -Property $props 
 
 if ($memberof -contains $nestedmember.distinguishedname){ 
 $table.comment ="Circular membership" 
 $circular = 1 
 } 
 $table | select type,name,displayname,parentgroup,nesting,enabled,dn,comment 
 if($nesting -lt 3){
 Get-ADNestedGroupMembers -GroupName $nestedmember.distinguishedName -nesting $nesting -circular $circular 
 } 
 } 
 else{ 
 if ($nestedmember){
 $table = new-object psobject -property $props
 $table | select type,name,displayname,parentgroup,nesting,enabled,dn,comment 
 
 }
 } 
 } 
 } 
 
}

function addToCSV{
 Param(
 [String]$mailboxEmail,
 [String]$mailboxAlias,
 [String]$mailboxDisplayName,
 [String]$mailboxType,
 [String]$permissionName,
 [String]$permissionClass,
 [String]$permissionType
 )
 $csvEntry = New-Object PSObject
 $csvEntry | Add-Member NoteProperty mailboxEmail($mailboxEmail)
 $csvEntry | Add-Member NoteProperty mailboxAlias($mailboxAlias)
 $csvEntry | Add-Member NoteProperty mailboxDisplayName($mailboxDisplayName)
 $csvEntry | Add-Member NoteProperty mailboxType($mailboxType)
 $csvEntry | Add-Member NoteProperty permissionName($permissionName)
 $csvEntry | Add-Member NoteProperty permissionClass($permissionClass)
 $csvEntry | Add-Member NoteProperty permissionType($permissionType)
 $script:csvEntries += $csvEntry
}

Write-Progress -Activity "Running report" -PercentComplete 0 -Status "Indexing..."

$done = 0
foreach($user in $users){
 
 $mail = $user.PrimarySMTPAddress.ToString()
 if($mail.Split("@")[0] -like "*.*"){
 write-verbose "$mail not shared" 
 }else{
 try{
 $perms = $user | Get-MailboxPermission -erroraction stop | where{$_.Deny -eq $False}
 }catch{
 write-error "failed to retrieve mailbox permissions for $mail"
 continue
 }
 foreach ($perm in $perms){
 $permUserName = $perm.User.ToString()
 if($permUserName -like "*CED\*"){
 $permAdInfo = searchForUserOrGroup -name $permUserName.Split("\")[1]
 if($permAdInfo -eq $False){
 $rights = $perm.AccessRights -Join ","
 addToCSV -mailboxEmail $mail -mailboxAlias $user.alias -mailboxDisplayName $user.displayName -mailboxType $user.recipientTypeDetails -permissionName $permUserName -permissionClass "failed to retrieve" -permissionType $rights 
 write-output "failed to find AD object for $permUserName"
 }else{
 if($permAdInfo.ObjectClass -eq "group"){
 try{
 $members = Get-ADNestedGroupMembers -GroupName $permAdInfo.Name
 foreach($member in $members){
 Write-Output "$mail : $($member.Name)"
 $rights = $perm.AccessRights -Join ","
 addToCSV -mailboxEmail $mail -mailboxAlias $user.alias -mailboxDisplayName $user.displayName -mailboxType $user.recipientTypeDetails -permissionName $member.DisplayName -permissionClass $member.ObjectClass -permissionType $rights
 }
 }catch{
 Write-Output "$mail : $($permAdInfo.Name)"
 $rights = $perm.AccessRights -Join ","
 addToCSV -mailboxEmail $mail -mailboxAlias $user.alias -mailboxDisplayName $user.displayName -mailboxType $user.recipientTypeDetails -permissionName $permAdInfo.Name -permissionClass $permAdInfo.ObjectClass -permissionType $rights
 }
 }else{
 Write-Output "$mail : $($permAdInfo.Name)"
 $rights = $perm.AccessRights -Join ","
 addToCSV -mailboxEmail $mail -mailboxAlias $user.alias -mailboxDisplayName $user.displayName -mailboxType $user.recipientTypeDetails -permissionName $permAdInfo.Name -permissionClass $permAdInfo.ObjectClass -permissionType $rights 
 }
 }
 }
 }
 }
 $done++
 try{$percent_done = ($done/($users.Count))*100}catch{$percent_done = 0}
 Write-Progress -Activity "Running report" -PercentComplete $percent_done -Status "$percent_done % done"
}

$csvEntries | Export-CSV -Path $csvExportPath -Delimiter ";"

Subscribe
Notify of
guest

This site uses Akismet to reduce spam. Learn how your comment data is processed.

5 Comments
Most Voted
Newest Oldest
Inline Feedbacks
View all comments
Lawrence
Lawrence
3 years ago

The scripts runs but produces an empty output in the csv. What am I missing.

Victor
Victor
3 years ago

Hello lieben,

Thanks so much for this script. It has proved invaluable for the current Office 365 migration work I’m currently doing.

My challenge is I have a single forest with 6 sub domains. The report seems to fail to get the user or group in other domains. How can I edit the script to query entire forest for ad object rather than just the default domain?

Regards