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