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 ";"
The scripts runs but produces an empty output in the csv. What am I missing.
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