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 ";"

5
Leave a Reply

avatar
2 Comment threads
3 Thread replies
2 Followers
 
Most reacted comment
Hottest comment thread
4 Comment authors
JosDeHeMLawrenceVictor Recent comment authors

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

  Subscribe  
newest oldest most voted
Notify of
Lawrence
Guest
Lawrence

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

Victor
Guest
Victor

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