Exchange

Microsoft Exchange – Set Address Book Policy to multiple users based on group membership

One of the common tasks of Exchange Administrator is to add Exchange Address Book Policy to a user. Depending on needs of organization there may be a need to add address book policies based on their group membership which often are inside other groups. Below solution helps to solve this task. In our case this little script runs every 24 hours making sure the group membership is updated in Global Address Book properly. There's also an updated version of this article, with newer, updated code that can be found here.

Solution

Administrator needs 2 methods to be able to set address book properly:

function Get-GroupMembershipRecursive ($group) {
    $SubGroup = @{}
    $AllMembers = @()
    if(!$group)
    {
        $group = Read-Host "Please enter the groups display name"
    }
    if ($group.Contains("'"))
    {
        $group = $group.Replace("'",'"')
    }
    if ($group -eq "/?")
    {
        Write-Host "Usage:"
        Write-Host ""
        Write-Host "Get-GroupMembershipRecursive -group <group name>"
        Write-Host ""
        Write-Host "or Get-GroupMembershipRecursive <group name>"
        Write-Host "Returns an object containing multiple values."
        break
    }

    $validate = Get-Group $group
    if ($validate.RecipientTypeDetails.ToString() -match "mail")
    {
        $searchGroup = Get-DistributionGroupMember $group
        #write-host 1.1 $searchGroup
        if ($searchGroup)
        {    
            foreach ($member in $searchGroup)
            {
                $membertype = $member.RecipientTypeDetails
                #if($membertype -match "Group")
                if ($membertype -match "MailUniversalSecurityGroup" -or $membertype -match "MailUniversalDistributionGroup")
                {
                    $samname = $member.SamAccountName.ToString()
                    if ($SubGroup.ContainsKey($samname) -eq $true)
                    {
                        Write-Output "^ already seen group member (stopping to avoid loop)"
                    }
                     else
                    {
                        #write-host 1.6 $samname " or " $member.DisplayName
                        $SubGroup.Add($samname,$member.DisplayName.ToString())
                    }
                }    
                else
                {
                    if($member.PrimarySmtpAddress -and $member.RecipientTypeDetails -notcontains "group")
                    {
                        $obj = new-object psObject
                        $obj | Add-Member -membertype noteproperty -Name GroupMember -Value $member.name
                        $obj | Add-Member -MemberType noteproperty -Name Group -Value $group 
                        $obj | Add-Member -MemberType noteproperty -Name SubGroup -Value $group
                        $obj | Add-Member -MemberType NoteProperty -Name RecipientType -Value $member.RecipientType
                        $obj | Add-Member -MemberType NoteProperty -Name PrimarySmtpAddress -Value $member.PrimarySmtpAddress
                        $AllMembers += $obj
                    }                    
                }
            }
        }
        else
        {
            $UnknownGroup.add($group,1)
        }
        if($SubGroup.Values.Count -gt 0)
        {
            #write-host 1.5 $SubGroup.Values.Count
            foreach ($subGroup in $SubGroup.values)
            {
                #DisplayMembers $subGroup
                #write-host 1.4 $subgroup "or " $SubGroup.Values 
                $searchGroup = Get-DistributionGroupMember $subGroup
                #write-host 1.2
                foreach ($member in $searchGroup) {                
                        $obj = new-object psObject
                        $obj | Add-Member -membertype noteproperty -Name GroupMember -Value $member.name
                        $obj | Add-Member -MemberType noteproperty -Name Group -Value $group 
                        $obj | Add-Member -MemberType noteproperty -Name SubGroup -Value $subGroup
                        $obj | Add-Member -MemberType NoteProperty -Name RecipientType -Value $member.RecipientType
                        $obj | Add-Member -MemberType NoteProperty -Name PrimarySmtpAddress -Value $member.PrimarySmtpAddress
                        $AllMembers += $obj
                }

            }
        }
        if ($UnknownGroup.Keys.Count -gt 0)
        {
            foreach ($LostGroup in $UnknownGroup.keys)
            {
                $obj = new-object psObject
                $obj | Add-Member -membertype noteproperty -name GroupMember -Value "Cannot enumerate group"
                $obj | Add-Member -MemberType noteproperty -Name Group -Value $group 
                $obj | Add-Member -MemberType noteproperty -Name SubGroup -Value $LostGroup
                $obj | Add-Member -MemberType NoteProperty -Name RecipientType -Value ""
                $obj | Add-Member -MemberType NoteProperty -Name PrimarySmtpAddress -Value ""
                $AllMembers += $obj
            }
            $UnknownGroup.Clear()
        }    
    }    
    else
    {
        Write-Output "$group does not appear to be mail enabled."
    }
    Write-Output $AllMembers
}
function SetAddressBookPolicy ([string] $AddressBookPolicy, [string] $SetOnGroup) {

    $members = Get-GroupMembershipRecursive $SetOnGroup
    #$members | ft GroupMember, Group, SubGroup, RecipientType, PrimarySmtpAddress -AutoSize
    foreach ($member in $members) {

           if ($member.RecipientType -eq "UserMailbox") {
                Set-Mailbox $member.PrimarySmtpAddress -AddressBookPolicy $AddressBookPolicy
           }
    }
}

Usage of those methods:

SetAddressBookPolicy -AddressBookPolicy "<addres_book_policy>" -SetOnGroup "<distribution_group"

Get-GroupMembershipRecursive method is supportive method to make sure that each member of group within group will also get the Address Book Policy applied. Remember to use following commands to make sure the Global Address List, Address Lists and Offline Address Book are all up to date.

Get-GlobalAddressList | Update-GlobalAddressList
Get-AddressList | Update-AddressList
Get-OfflineAddressBook | Update-OfflineAddressBook

Notes

Please be aware that the script doesn't actually display anything during setting of address book policy. Only warning are displayed if the address book is already assigned to the mailbox.

This post was last modified on March 20, 2016 12:24

Przemyslaw Klys

System Architect with over 14 years of experience in the IT field. Skilled, among others, in Active Directory, Microsoft Exchange and Office 365. Profoundly interested in PowerShell. Software geek.

Share
Published by
Przemyslaw Klys

Recent Posts

Upgrade Azure Active Directory Connect fails with unexpected error

Today, I made the decision to upgrade my test environment and update the version of…

2 months ago

Mastering Active Directory Hygiene: Automating Stale Computer Cleanup with CleanupMonster

Have you ever looked at your Active Directory and wondered, "Why do I still have…

3 months ago

Active Directory Replication Summary to your Email or Microsoft Teams

Active Directory replication is a critical process that ensures the consistent and up-to-date state of…

7 months ago

Syncing Global Address List (GAL) to personal contacts and between Office 365 tenants with PowerShell

Hey there! Today, I wanted to introduce you to one of the small but excellent…

12 months ago

Active Directory Health Check using Microsoft Entra Connect Health Service

Active Directory (AD) is crucial in managing identities and resources within an organization. Ensuring its…

1 year ago

Seamless HTML Report Creation: Harness the Power of Markdown with PSWriteHTML PowerShell Module

In today's digital age, the ability to create compelling and informative HTML reports and documents…

1 year ago