Managing shared and resource mailbox permissions can be more or less a pain depending on how you do it. Adding users directly as delegates to the shared mailboxes gives you a bit more administrative overhead, but makes it possible to utilize the AutoMapping feature that automatically adds the additional mailboxes to the end users Outlook client. If you instead add mail-enabled security groups to the delegate list, you get less administrative overhead, but not the AutoMapping feature.
Even though this is a really “old” problem, I get questions around it almost every week. Therefore I wanted to share a solution with you that gives you an example on how to solve it still using groups. A script that will use Mail-Enabled Security Groups/Distribution Groups to dynamically populate the delegate list of a shared mailbox.
GETTING STARTED
In order to get started, you need to create one “Shadow Group” per mailbox who’s delegation properties you want to manage automatically. To make it as easy as possible, I’m using a prefix to identify the groups with the mailboxes, like Prefix-MailboxName. In my example below, the prefix is SM-. See the screenshot below for the correlation between them.
It could of course be possible to use another attribute on the groups to store the mailbox name, but I thought this was an easier approach.
RUNNING THE SCRIPT
After editing the credentials in the Connect-ExchangeOnline function, you simply run the script as below:
.\SharedMailboxViaGroups.ps1 -Prefix 'SM-'
As seen in the screenshot above it will process adds and removals of permissions for all mailboxes/groups in scope. Please note that both FullAccess and SendAs-permissions are added for each delegate.
SharedMailboxViaGroups.ps1
<# .SYNOPSIS The script will automatically assign mailbox and recipient permissions on shared mailboxes based on groups. .EXAMPLE .\SharedMailboxViaGroups.ps1 -Prefix 'SM-' .PARAMETER Prefix Prefix of the groups that will manage permissions on the shared mailboxes. .NOTES File Name: SharedMailboxViaGroups.ps1 Author : Johan Dahlbom, johan[at]dahlbom.eu Blog : 365lab.net The script are provided “AS IS” with no guarantees, no warranties, and they confer no rights. Requires PowerShell Version 3.0! #> param ( [string]$Prefix = 'SM-' ) function Connect-ExchangeOnline { param( [string]$Username = 'admin@tenant.onmicrosoft.com', [string]$Password = 'password' ) #Clean up existing PowerShell Sessions Get-PSSession | Remove-PSSession $CloudCred = New-Object –TypeName System.Management.Automation.PSCredential –ArgumentList $Username, (ConvertTo-SecureString $Password -AsPlainText -Force) #Connect to Exchange Online $Session = New-PSSession –ConfigurationName Microsoft.Exchange -ConnectionUri https://outlook.office365.com/powershell-liveid/ -Credential $CloudCred -Authentication Basic -AllowRedirection $Commands = @("Add-MailboxPermission","Add-RecipientPermission","Remove-RecipientPermission","Remove-MailboxPermission","Get-MailboxPermission","Get-User","Get-DistributionGroupMember","Get-DistributionGroup","Get-Mailbox") Import-PSSession -Session $Session -Prefix "Cloud" -DisableNameChecking:$true -AllowClobber:$true -CommandName $Commands | Out-Null } function Add-JDMailboxPermission { param( [string]$Identity, [string]$SharedMailboxName ) try { Add-CloudMailboxPermission -Identity $SharedMailboxName -User $Identity -AccessRights FullAccess -ErrorAction stop | Out-Null Add-CloudRecipientPermission -Identity $SharedMailboxName -Trustee $Identity -AccessRights SendAs -Confirm:$False -ErrorAction stop | Out-Null Write-Output "INFO: Successfully added $Identity to $SharedMailboxName" } catch { Write-Warning "Cannot add $Identity to $SharedMailboxName`r`n$_" } } function Remove-JDMailboxPermission { param( [string]$Identity, [string]$SharedMailboxName ) try { Remove-CloudMailboxPermission -Identity $SharedMailboxName -User $Identity -AccessRights FullAccess -Confirm:$False -ErrorAction stop -WarningAction ignore | Out-Null Remove-CloudRecipientPermission -Identity $SharedMailboxName -Trustee $Identity -AccessRights SendAs -Confirm:$False -ErrorAction stop -WarningAction ignore | Out-Null Write-Output "INFO: Successfully removed $Identity from $SharedMailboxName" } catch { Write-Warning "Cannot remove $Identity from $SharedMailboxName`r`n$_" } } function Sync-EXOResourceGroup { [CmdletBinding(SupportsShouldProcess=$true)] param( [string]$Prefix = 'SM-' ) #Get All groups to process mailboxes for $MasterGroups = Get-CloudDistributionGroup -ResultSize Unlimited -Identity "$Prefix*" foreach ($Group in $MasterGroups) { #Remove prefix to get the mailbox name $MbxName = $Group.Name.Replace("$Prefix",'') $SharedMailboxName = (Get-CloudMailbox -Identity $MbxName -ErrorAction ignore -WarningAction ignore).WindowsLiveID if ($SharedMailboxName) { Write-Verbose -Message "Processing group $($Group.Name) and mailbox $SharedMailboxName" #Get all users with explicit permissions on the mailbox $SharedMailboxDelegates = Get-CloudMailboxPermission -Identity $SharedMailboxName -ErrorAction Stop -ResultSize Unlimited | Where-Object {$_.IsInherited -eq $false -and $_.User -ne "NT AUTHORITY\SELF" -and $_.User -notmatch 'S-\d-\d-\d+-\d+-\d+-\d+-\w+' -and $_.User -notlike "$Prefix*"} | Select-Object @{Name="User";Expression={(Get-CloudUser -identity $_.User).WindowsLiveID }} #Get all group members $SharedMailboxMembers = Get-CloudDistributionGroupMember -Identity $Group.Identity -ResultSize Unlimited #Remove users if group is empty if (-not($SharedMailboxMembers) -and $SharedMailboxDelegates) { Write-Warning "The group $Group is empty, will remove explicit permissions from $SharedMailboxName" foreach ($user in $SharedMailboxDelegates.User) { Remove-JDMailboxPermission -Identity $user -SharedMailboxName $SharedMailboxName } #Add users if no permissions are present } elseif (-not($SharedMailboxDelegates)) { foreach ($user in $SharedMailboxMembers.WindowsLiveID) { Add-JDMailboxPermission -Identity $user -SharedMailboxName $SharedMailboxName } #Process removals and adds } else { #Compare the group with the users that have actual access $Users = Compare-Object -ReferenceObject $SharedMailboxDelegates.User -DifferenceObject $SharedMailboxMembers.WindowsLiveID #Add users that are members of the group but do not have access to the shared mailbox foreach ($user in ($users | Where-Object {$_.SideIndicator -eq "=>"})) { Add-JDMailboxPermission -Identity $user.InputObject -SharedMailboxName $SharedMailboxName } #Remove users that have access to the shared mailbox but are not members of the group foreach ($user in ($users | Where-Object {$_.SideIndicator -eq "<="})) { Remove-JDMailboxPermission -Identity $user.InputObject -SharedMailboxName $SharedMailboxName } } } else { Write-Warning "Could not find the mailbox $MbxName" } } } #Connect to Exchange Online Connect-ExchangeOnline #Start Processing groups and mailboxes Sync-EXOResourceGroup -Prefix $Prefix -Verbose
SUMMARY
A pretty simple solution on a very common problem in most environments where you have shared mailboxes. Let me know if you have feature requests or if something is not working as intended!
Enjoy!
/Johan
Pingback: Get rid of your Office 365 Scheduled tasks with Azure Automation! | Tailspintoys – 365lab.net
Hey, seems, that the sendas permissions not working in your script. Can you confirm that? regards steffen