public/get-ExOPermissions.ps1
Function get-ExOPermissions{ <# Author = "Jos Lieben (jos@lieben.nu)" CompanyName = "Lieben Consultancy" Copyright = "https://www.lieben.nu/liebensraum/commercial-use/" Parameters: -expandGroups: if set, group memberships will be expanded to individual users -includeFolderLevelPermissions: if set, folder level permissions for each mailbox will be retrieved. This can be (very) slow -outputFormat: XLSX CSV Default (output to Out-GridView) Any combination of above is possible -includeCurrentUser: add entries for the user performing the audit (as this user will have all access, it'll clutter the report) #> Param( [Switch]$expandGroups, [Switch]$includeCurrentUser, [Switch]$includeFolderLevelPermissions, [parameter(Mandatory=$true)][String]$recipientIdentity, [ValidateSet('XLSX','CSV','Default')] [String[]]$outputFormat="XLSX" ) $global:octo.includeCurrentUser = $includeCurrentUser.IsPresent $global:ExOPermissions = @{} if(!$global:octo.recipients){ Write-Progress -Id 2 -PercentComplete 1 -Activity "Scanning Recipient" -Status "Retrieving recipients for cache..." $global:octo.recipients = (New-ExOQuery -cmdlet "Get-Recipient" -cmdParams @{"ResultSize" = "Unlimited"}) | Where-Object{$_ -and !$_.Identity.StartsWith("DiscoverySearchMailbox")} } $recipient = $global:octo.recipients | Where-Object {$_.Identity -eq $recipientIdentity} if(!$recipient){ Write-Error "Recipient $recipientIdentity not found, skipping..." -ErrorAction Continue return $Null } New-StatisticsObject -category "ExoRecipients" -subject $recipient.displayName $ignoredFolderTypes = @("RecoverableItemsSubstrateHolds","RecoverableItemsPurges","RecoverableItemsVersions","RecoverableItemsDeletions","RecoverableItemsDiscoveryHolds","Audits","CalendarLogging","RecoverableItemsRoot","SyncIssues","Conflicts","LocalFailures","ServerFailures") Update-StatisticsObject -category "ExoRecipients" -subject $recipient.displayName if(!$recipient.PrimarySmtpAddress){ Write-Warning "skipping $($recipient.identity) as it has no primary smtp address" return $Null } #mailboxes have mailbox permissions if($recipient.RecipientTypeDetails -like "*Mailbox*" -and $recipient.RecipientTypeDetails -ne "GroupMailbox"){ Write-Progress -Id 2 -PercentComplete 5 -Activity "Scanning $($recipient.Identity)" -Status "Checking recipient for SendOnBehalf permissions..." #get mailbox meta for SOB permissions $mailbox = $Null; $mailbox = New-ExOQuery -cmdlet "Get-Mailbox" -cmdParams @{Identity = $recipient.Guid} -retryCount 2 if($mailbox.GrantSendOnBehalfTo){ foreach($sendOnBehalf in $mailbox.GrantSendOnBehalfTo){ $entity = $Null; $entity= @($global:octo.recipients | Where-Object {$_.DisplayName -eq $sendOnBehalf})[0] $splat = @{ path = "/$($recipient.PrimarySmtpAddress)" type = $recipient.RecipientTypeDetails principalUpn = if($entity.PrimarySmtpAddress){$entity.PrimarySmtpAddress}else{$entity.windowsLiveId} principalName = $sendOnBehalf principalEntraId = $entity.ExternalDirectoryObjectId principalType = $entity.RecipientTypeDetails role = "SendOnBehalf" through = "Direct" kind = "Allow" } New-ExOPermissionEntry @splat } } if($mailbox){ Write-Progress -Id 2 -PercentComplete 15 -Activity "Scanning $($recipient.Identity)" -Status "Checking recipient for Mailbox permissions..." $mailboxPermissions = $Null; $mailboxPermissions = (New-ExOQuery -cmdlet "Get-Mailboxpermission" -cmdParams @{Identity = $mailbox.Guid}) | Where-Object {$_.User -like "*@*"} foreach($mailboxPermission in $mailboxPermissions){ foreach($AccessRight in $mailboxPermission.AccessRights){ $entity = $Null; $entity= @($global:octo.recipients | Where-Object {$_.PrimarySmtpAddress -eq $mailboxPermission.User -or $_.windowsLiveId -eq $mailboxPermission.User})[0] $splat = @{ path = "/$($recipient.PrimarySmtpAddress)" type = $recipient.RecipientTypeDetails principalUpn = if($entity.PrimarySmtpAddress){$entity.PrimarySmtpAddress}else{$entity.windowsLiveId} principalName = $entity.Identity principalEntraId = $entity.ExternalDirectoryObjectId principalType = $entity.RecipientTypeDetails role = $AccessRight through = $(if($mailboxPermission.IsInherited){ "Inherited" }else{ "Direct" }) kind = $(if($mailboxPermission.Deny -eq "False"){ "Allow" }else{ "Deny" }) } New-ExOPermissionEntry @splat } } } #retrieve individual folder permissions if -includeFolderLevelPermissions is set if($mailbox.UserPrincipalName -and $includeFolderLevelPermissions){ Write-Progress -Id 2 -PercentComplete 25 -Activity "Scanning $($recipient.Identity)" -Status "Checking recipient for folder permissions..." Write-Progress -Id 3 -PercentComplete 1 -Activity "Scanning folders $($recipient.Identity)" -Status "Retrieving folder list for $($mailbox.UserPrincipalName)" try{ $folders = $Null; $folders = New-ExOQuery -cmdlet "Get-MailboxFolderStatistics" -cmdParams @{"ResultSize"="unlimited";"Identity"= $mailbox.UserPrincipalName} }catch{ Write-Warning "Failed to retrieve folder list for $($mailbox.UserPrincipalName)" } $folderCounter = 0 foreach($folder in $folders){ Update-StatisticsObject -category "ExoRecipients" -subject $recipient.displayName $folderCounter++ Write-Progress -Id 3 -PercentComplete (($folderCounter/$folders.Count)*100) -Activity "Scanning folders $($recipient.Identity)" -Status "Examining $($folder.Name) ($($folderCounter) of $($folders.Count))" if($ignoredFolderTypes -contains $folder.FolderType -or $folder.Name -in @("SearchDiscoveryHoldsFolder")){ Write-Verbose "Ignoring folder $($folder.Name) as it is in the ignored list" continue } try{ $folderPermissions = $Null; $folderPermissions = New-ExoQuery -cmdlet "Get-MailboxFolderPermission" -cmdParams @{Identity = "$($mailbox.UserPrincipalName):$($folder.FolderId)"} foreach($folderPermission in $folderPermissions){ $entity = $Null; $entity= @($global:octo.recipients | Where-Object {$_.Identity -eq $folderPermission.User})[0] if(!$entity){ $entity = $Null; $entity= @($global:octo.recipients | Where-Object {$_.DisplayName -eq $folderPermission.User})[0] } if($entity -and $entity.Identity -eq $recipient.Identity){ Write-Verbose "Skipping permission $($folderPermission.AccessRights) scoped at $($mailbox.UserPrincipalName)$($folder.FolderPath) for $($recipient.Identity) as it is the owner" continue } #handle external permissions for e.g. calendars if($folderPermission.User.StartsWith("ExchangePublishedUser")){ $entity = [PSCustomObject]@{ PrimarySmtpAddress = $folderPermission.User.Replace("ExchangePublishedUser.","") ExternalDirectoryObjectId = "N/A" RecipientTypeDetails = "ExternalUser" } } if($folderPermission.AccessRights -notcontains "None"){ foreach($AccessRight in $folderPermission.AccessRights){ $splat = @{ path = "/$($mailbox.UserPrincipalName)$($folder.FolderPath)" type = "MailboxFolder" principalUpn = if($entity.PrimarySmtpAddress){$entity.PrimarySmtpAddress}else{$entity.windowsLiveId} principalName = $folderPermission.User principalEntraId = $entity.ExternalDirectoryObjectId principalType = $entity.RecipientTypeDetails role = $AccessRight through = "Direct" kind = "Allow" } New-ExOPermissionEntry @splat } } } }catch{ Write-Warning "Failed to retrieve folder permissions for $($mailbox.UserPrincipalName)$($folder.FolderPath)" } } Write-Progress -Id 3 -Completed -Activity "Scanning folders $($recipient.Identity)" } } #all recipients can have recipient permissions Write-Progress -Id 2 -PercentComplete 85 -Activity "Scanning $($recipient.Identity)" -Status "Checking recipient for SendAs permissions..." $recipientPermissions = (New-ExOQuery -cmdlet "Get-RecipientPermission" -cmdParams @{"ResultSize" = "Unlimited"; "Identity" = $recipient.Guid}) | Where-Object {$_.Trustee -ne "NT Authority\SELF" } foreach($recipientPermission in $recipientPermissions){ $entity = $Null; $entity= $global:octo.recipients | Where-Object {$_.PrimarySmtpAddress -eq $recipientPermission.Trustee} foreach($AccessRight in $recipientPermission.AccessRights){ $splat = @{ path = "/$($recipient.PrimarySmtpAddress)" type = $recipient.RecipientTypeDetails principalUpn = $recipientPermission.Trustee principalName = $entity.displayName principalEntraId = $entity.ExternalDirectoryObjectId principalType = $entity.RecipientTypeDetails role = $AccessRight through = $(if($recipientPermission.IsInherited){ "Inherited" }else{ "Direct" }) kind = $recipientPermission.AccessControlType } New-ExOPermissionEntry @splat } } Write-Progress -Id 2 -PercentComplete 95 -Activity "Scanning $($recipient.Identity)" -Status "Writing report..." Stop-StatisticsObject -category "ExoRecipients" -subject $recipient.displayName $permissionRows = foreach($row in $global:ExOPermissions.Keys){ foreach($permission in $global:ExOPermissions.$row){ [PSCustomObject]@{ "Path" = $permission.Path "Type" = $permission.Type "PrincipalEntraId" = $permission.PrincipalEntraId "PrincipalUpn" = $permission.PrincipalUpn "PrincipalName" = $permission.PrincipalName "PrincipalType" = $permission.PrincipalType "Role" = $permission.Role "Through" = $permission.Through "Kind" = $permission.Kind } } } add-toReport -formats $outputFormat -permissions $permissionRows -category "ExoRecipients" -subject $recipient.displayName Write-Progress -Id 2 -Completed -Activity "Scanning $($recipient.Identity)" } |