I’m trying to improve performance in a script that gets all shared mailboxes that a user has delegate access to in Exchange Online. The script finds mailboxes where the user has “Read and Manage” and “Send As” access, but we can just focus on the “Read and Manage” part for this discussion. The “Send As” part is very similar, but uses the Get-EXORecipientPermission cmdlet. I’d like a solution for PowerShell 5.1 (Windows), but don’t mind examples in PowerShell 7 (core). I’d also prefer a solution that outputs to the host as it goes, but this wouldn’t matter if I could make it blazing fast.
Here’s a simplified version of what I have using a single thread. We must enumerate each shared mailbox and call into Exchange Online to check the delegates, which takes a long time.
function Show-ReadManageMailboxes($mailboxesToSearch, $userEmail)
{
Write-Host "Getting mailboxes where user has `"Read and Manage`" access. Please wait..." -ForegroundColor "DarkCyan"
$mailboxesToSearch |
ForEach-Object {
$permission = Get-EXOMailboxPermission -Identity $_ -User $userEmail -ErrorAction "SilentlyContinue"
if (-not($permission)) { return } # This return statement continues to next object in pipeline. It doesn't return from the function.
$totalMailboxesWithReadAndManage++
[PSCustomObject]@{
"Display Name" = $_.DisplayName
"UPN" = $_.UserPrincipalName
"Access Rights" = $permission.AccessRights
}
} | Format-Table
Write-Host "Done!" -ForegroundColor "Green"
}
$userEmail = "[email protected]"
$allMailboxes = Get-EXOMailbox -ResultSize Unlimited -RecipientTypeDetails SharedMailbox, GroupMailbox, TeamMailbox
Show-ReadManageMailboxes -mailboxesToSearch $allMailboxes -userEmail $userEmail
If I understand right, thread jobs would be the best thing to try here. Here’s what I’ve tried:
function Show-ReadManageMailboxes($mailboxesToSearch, $userEmail)
{
Write-Host "Getting mailboxes where user has `"Read and Manage`" access. Please wait..." -ForegroundColor "DarkCyan"
$mailboxesToSearch |
ForEach-Object {
Start-ThreadJob -ThrottleLimit $mailboxesToSearch.Count {
Get-EXOMailboxPermission -Identity $using:_ -User $using:userEmail -ErrorAction "SilentlyContinue"
}
} | Receive-Job -Wait | Format-Table
Write-Host "Done!" -ForegroundColor "Green"
}
This outputs the mailboxes quicker, but still takes forever to complete. Almost like it gets hung up trying to stop/remove all the jobs.
I’ve also tried this in PowerShell 7, which behaves similarly:
function Show-ReadManageMailboxes($mailboxesToSearch, $userEmail)
{
Write-Host "Getting mailboxes where user has `"Read and Manage`" access. Please wait..." -ForegroundColor "DarkCyan"
$mailboxesToSearch |
ForEach-Object -ThrottleLimit $mailboxesToSearch.Count -AsJob -Parallel {
Get-EXOMailboxPermission -Identity $_ -User $using:userEmail -ErrorAction "SilentlyContinue"
} | Receive-Job -Wait | Format-Table
Write-Host "Done!" -ForegroundColor "Green"
}
Can this be done better?