How to Create Exchange Dynamic Distribution Lists with Custom Recipient Filters

Build Filters Against Multiple Azure AD Properties

A post in the Microsoft Technical Community looked for help building a dynamic distribution list based on multiple Azure AD properties. Our esteemed technical editor, Vasil Michev, stepped in to help and involved me. I pointed out that this topic is covered in Chapter 6 of the Office 365 for IT Pros eBook (easy to miss in 1,250 pages) but admitted that the question was interesting.

Dynamic distribution lists are an undervalued part of Exchange Online. The concept has existed since Exchange 2003 introduced the query-based distribution group, or QDG. The current implementation arrived in Exchange 2007. In both cases, a query is resolved against the directory to identify the set of recipients for a message. The list is dynamic because the set of recipients will change based on the contents of the directory.

Precanned and Custom Recipient Filters

The Exchange admin center (EAC) GUI is designed to make it easy for administrators to create the queries for dynamic distribution lists. It does this by limiting the set of properties available for queries, like department and city. The queries generated by the EAC are called precanned queries. after generation, Exchange stores the recipient filter as a property of the dynamic distribution list.

Custom queries can use a much wider set of properties. The downside is that you must build the queries by hand and update dynamic distribution lists with PowerShell. That might seem hard, but it’s really not.

Excluding Some Mailboxes

In this instance, the need is to have a dynamic distribution list to address mailboxes owned by people with a specific job title but exclude any whose Azure AD accounts are blocked for sign-in. Figure 1 shows the account of architect Ben James. The account is blocked.

Details of a blocked Azure AD account
Dynamic distribution list
Figure 1: Details of a blocked Azure AD account

When an Azure AD account is blocked, Exchange synchronizes the status and updates the ExchangeUserAccountControl mailbox property. To find the set of recipients who have architect in their job title and can still sign in, we can build a recipient filter which checks the Title and ExchangeUserAccountControl properties. Because people might have prefixes to indicate the seniority of their architect status, we need to include some variants of the job title. Exchange only supports wildcards for filters at the end of a string (“architect*”) instead of the start (“*architect”), which would be more useful in this case.

Building and Testing a Recipient Filter with PowerShell

Here’s what a custom filter to check for a job title and account blocked status looks like:

$Filter = "((Title -eq 'Architect') -or (Title -eq 'Senior Architect') -or (Title -eq 'Principal Architect') -and (ExchangeUserAccountControl -ne 'AccountDisabled'))"

To know if the filter works, we can use the Get-Recipient cmdlet. Get-Recipient accepts the filter defined in the $Filter variable and returns what it finds in the directory. This is exactly what will be returned as the set of recipients when the Exchange transport service resolves the query stored in the dynamic distribution list.

Get-Recipient -RecipientPreviewFilter $Filter | ft displayname, title

DisplayName                   Title
-----------                   -----
Ben James                     Architect
Eoin Redmond (Ireland)        Architect
James Joyce                   Principal Architect
Tony Redmond                  Principal Architect
Vasil Michev (Technical Guru) Senior Architect

It’s important to test any filter before using it with a dynamic distribution list. If the query generated by the filter fails to resolve and return any recipients, any message sent to the list goes into a black hole. Exchange won’t generate a non-delivery notification because the address used for the message is valid (the list); the problem lies with what happens when the query is run against the directory.

Creating a Dynamic Distribution List with PowerShell

After you’re sure that the filter returns the correct set of recipients, you can create a dynamic distribution list using the filter. For example:

New-DynamicDistributionGroup -Name "Architects" -DisplayName "System and Engineering Architects" -Alias AllArchitects -PrimarySmtpAddress Architects@Office365itpros.com -RecipientFilter $Filter
Set-DynamicDistributionGroup -Identity AllArchitects -ManagedBy Tony.Redmond -MailTip "Distribution List for anyone with Architect in the job title"

The second command is to add an owner for the dynamic distribution list and to assign a mail tip for clients like Outlook to display when people address email to the list.

EAC Blocks Edits of Custom Recipient Filters

Any further adjustments to the recipient filter can only be made with PowerShell. If you look at a custom recipient filter with the Exchange admin center, it’s blocked for edit (Figure 2).

EAC stops any attempt to update a custom recipient filter for a dynamic distribution list
Figure 2: EAC stops any attempt to update a custom recipient filter for a dynamic distribution list

As for Ben James, when his Azure AD account is reenabled for sign-in, he’ll start to receive messages sent to the dynamic distribution list again, which is exactly what we want.


Insight like this doesn’t come easily. You’ve got to know the technology and understand how to look behind the scenes. Benefit from the knowledge and experience of the Office 365 for IT Pros team by subscribing to the best eBook covering Office 365 and the wider Microsoft 365 ecosystem.

36 Replies to “How to Create Exchange Dynamic Distribution Lists with Custom Recipient Filters”

  1. Be aware a bug exists in the New EAC where any Custom recipient filter set on a DDG is wiped and replaced by a Precanned recipient filter when the DDG properties are opened and saved. The default Precanned filter that is applied will include all reciepient types. Resulting in emails sent to the DDG going to all mailboxes in the organisation as well as external recipients. When the DDG properties are opened in the New EAC, the save button is available even if the user does not change anything.

    Due to this bug. It is recommended not to use the New EAC to manage DDGs with custom reciepient filters. Only use PowerShell.

    Microsoft has been made aware of this bug. While they have recognised the bug they have not provided a timeline for resolution.

    1. Personally speaking, I would never go near the EAC when dealing with DDGs with custom filters. The record of dealing with these filters is not good.

  2. I am trying to build DDL based on StreetAddress but getting some weird syntax error. Can you please help? Basically, need to have DDL of mailbox users whose streetAddress is “Sterling”

    $filter = “((((((RecipientType -eq ‘UserMailbox’))) -and (-not(UserAccountControl -eq ‘AccountDisabled, NormalAccount’)))) -and (-not(Name -like ‘SystemMailbox{*’)) -and (-not(Name -like ‘CAS_{*’)) -and (-not(RecipientTypeDetailsValue -eq ‘MailboxPlan’)) -and (-not(RecipientTypeDetailsValue -eq ‘DiscoveryMailbox’)) -and (-not(RecipientTypeDetailsValue -eq ‘PublicFolderMailbox’)) -and (-not(RecipientTypeDetailsValue -eq ‘ArbitrationMailbox’)) -and (-not(RecipientTypeDetails -eq ‘SharedMailbox’) -and (-not(RecipientTypeDetailsValue -eq ‘AuditLogMailbox’)) -and (-not(RecipientTypeDetailsValue -eq ‘AuxAuditLogMailbox’)) -and (-not(RecipientTypeDetailsValue -eq ‘SupervisoryReviewPolicyMailbox’)) -and (StreetAddress -eq ‘sterling’)”

  3. Hello. I’m try create ddg filter based emails with script below:
    New-DynamicDistributionGroup -Alias “Everyone” -Name Husola Everyone” -RecipientFilter {(RecipientType -eq ‘UserMailbox’) -and (EmailAddresses -like ‘*husola.de*’)} -PrimarySmtpAddress “Everyone@husola.de”

    And the output is:
    ((((RecipientType -eq ‘UserMailbox’) -and (EmailAddresses -like ‘*husola.de*’))) -and (-not(Name -like ‘SystemMailbox{*’)) -and (-not(Name -like ‘CAS_{*’)) -and (-not(RecipientTypeDetailsValue -eq ‘MailboxPlan’)) -and (-not(RecipientTypeDetailsValue -eq ‘DiscoveryMailbox’)) -and (-not(RecipientTypeDetailsValue -eq ‘PublicFolderMailbox’)) -and (-not(RecipientTypeDetailsValue -eq ‘ArbitrationMailbox’)) -and (-not(RecipientTypeDetailsValue -eq ‘AuditLogMailbox’)))

    But when i sending mail in Everyone@husola.de nobody getting mail with smtp @husola.de. Where and what am I doing wrong?
    I want to note that we have had filters like this one for many years and work perfectly, but this is what does not work.

    1. What do you get when you try the recipient filter from the DDG with Get-Recipient?

      This works for me:

      $Filter = “((EmailAddresses -like ‘*Office365itpros*’) -and (RecipientTypeDetails -eq ‘UserMailbox’))”
      get-recipient -RecipientPreviewFilter $Filter

      But the filter doesn’t work with the DDG because Exchange Online doesn’t support a wildcard character as the start of a term – only at the end (I know that https://docs.microsoft.com/en-us/powershell/exchange/recipientfilter-properties?view=exchange-ps specifies that wildcards can be used withg EmailAddresses, but only at the end):

      Text string properties that accept wildcard characters require the -like operator (for example, “Property -like ‘abc*'”). In Exchange Online PowerShell, you can’t use the wildcard as a prefix (for example, “Property -like ‘*abc'”) is not allowed).

      1. Firstly, I want to say that I am doing this on On-premise (local) Exchange 2013.

        What do you get when you try the recipient filter from the DDG with Get-Recipient?
        I get a list of users who have this smtp address.

        My this command for on-premise exchange 2013 wrong?:
        New-DynamicDistributionGroup -Alias “Everyone” -Name Husola Everyone” -RecipientFilter {(RecipientType -eq ‘UserMailbox’) -and (EmailAddresses -like ‘*husola.de*’)} -PrimarySmtpAddress “Everyone@husola.de”

      2. Hi Tony,

        Please let me know how to pass wildcard as a prefix, I have few property where I want to pass it like *abc*.
        Please let me know if there is any way.

  4. Hello,

    i’m try to create a DDL based on a active directory group:

    set-DynamicDistributionGroup “AllUserInGroup” -recipientFilter “(sAMAccountName -eq ‘TEST_DYNAMIC_GROUP_0365’)”

    but don’t working

  5. These few filters are very fun to work with, However found something strange, hence wanted to clarify with the experts:)

    Here is an easiest filter I have applied,

    $Filter = ((UsageLocation -eq ‘US’) -and (CustomAttribute15 -eq ’employee’))

    Now, when preview the filter, I’m returned with 360 entries:

    (Get-Recipient -RecipientPreviewFilter $filter).count

    360

    However, When this filter is set in the DDG, it doesn’t give me 360 members instead it give me a higher number.

    Here are the recipient filters after updating:

    RecipientFilter: ((((((RecipientType -eq ‘UserMailbox’) -and (UsageLocation -eq ‘United States’))) -and (CustomAttribute15 -eq ’employee’))) -and (-not(Name -like ‘SystemMailbox{*’)) -and (-not(Name -like ‘CAS_{*’)) -and (-not(RecipientTypeDetailsValue -eq ‘MailboxPlan’)) -and (-not(RecipientTypeDetailsValue -eq ‘DiscoveryMailbox’)) -and (-not(RecipientTypeDetailsValue -eq ‘PublicFolderMailbox’)) -and (-not(RecipientTypeDetailsValue -eq ‘ArbitrationMailbox’)) -and (-not(RecipientTypeDetailsValue -eq ‘AuditLogMailbox’)) -and (-not(RecipientTypeDetailsValue -eq ‘AuxAuditLogMailbox’)) -and (-not(RecipientTypeDetailsValue -eq ‘SupervisoryReviewPolicyMailbox’)))

    Here is the count I get, when I do Get-DynamicDistributionGroupMembers (I don’t think this command existed before)

    (Get-DynamicDistributionGroupMember It.test).count
    553

    Strangely, When I try to review the member using the legacy way, that is, storing the recipient filter after a variable and the calling that using get-recipient, I see the correct number:

    $ITDdg = Get-DynamicDistributionGroup it.test
    (Get-Recipient -RecipientPreviewFilter $ITDdg.RecipientFilter).count
    360

    Now, either the new cmdlet Get-DynamicDistributionGroupMember is not showing the correct number or my filter has a syntax error.

    Please suggest.

    1. I’d give your information to Microsoft in the form of a support incident to ask them to check out what’s going on. They can check the data against your tenant. I can’t!

      1. Thanks for your response, Tony!

        Agreed, this needs to be shared with MS, however my intent to post here to understand if this is reproduced by others too.

        Thanks for looking into it anyway!

      2. The problem is that we don’t have the same data to test against… so it’s hard to know if something in the data is causing the problem. But Microsoft can gain access (with your permission) to the data to check things out. Hence the recommendation.

  6. Hi
    I am trying to create a Dynamic DL based on these filter Like EmailAddresses Like ‘@abc.com” Sample is -RecipientFilter {(RecipientType -eq ‘UserMailbox’ -and -not (UserAccountControl -eq “AccountDisabled, NormalAccount”) -and (EmailAddresses -Like ‘@abc.com’) -and (Title -like ‘General Manager*’))}.
    The DL group did get created but no memebers. Can you please advise me what am I missing here.
    Thank you in advanced.

      1. HI Amardeep
        I am using Get-Recipient -RecipientPreviewFilter $FTE.RecipientFilter -OrganizationalUnit $FTE.RecipientContainer to get the memership results

    1. I don’t think this is possible. You can only position the wildcard character at the end of strings in a recipient filter and I think you’d want to have it at the start. A quick search revealed that many people have had similar issues, so I will raise this with Microsoft.

  7. Hi Tony,

    Thank you for a good guide, it makes it a bit easier to understand. I did have a few questions and hopefully you can help with some answers. Do you know why after it is done, Exchange puts like so many parenthesis in front for example, here is the result I have:

    ((((((((((((((((((((((RecipientType -eq ‘UserMailbox’) -and (((-not(Name -like ‘REDACTED’)) -and (((-not(MemberOfGroup -eq ‘DC=ExcludeFromAllStaff’)) -and (((-not(Name -like ‘REDACTED’)) -and (-not(RecipientTypeDetailsValue -eq ‘RoomMailbox’)))))))))) -and (-not(Name -like ‘SystemMailbox{*’)))) -and (-not(Name -like ‘CAS_{*’)))) -and (-not(RecipientTypeDetailsValue -eq ‘MailboxPlan’)))) -and (-not(RecipientTypeDetailsValue -eq ‘DiscoveryMailbox’)))) -and (-not(RecipientTypeDetailsValue -eq ‘PublicFolderMailbox’)))) -and (-not(RecipientTypeDetailsValue -eq ‘ArbitrationMailbox’)))) -and (-not(RecipientTypeDetailsValue -eq ‘AuditLogMailbox’)))) -and (-not(RecipientTypeDetailsValue -eq ‘AuxAuditLogMailbox’)))) -and (-not(RecipientTypeDetailsValue -eq ‘SupervisoryReviewPolicyMailbox’)))) -and (-not(Name -like ‘SystemMailbox{*’)) -and (-not(Name -like ‘CAS_{*’)) -and (-not(RecipientTypeDetailsValue -eq ‘MailboxPlan’)) -and (-not(RecipientTypeDetailsValue -eq ‘DiscoveryMailbox’)) -and (-not(RecipientTypeDetailsValue -eq ‘PublicFolderMailbox’)) -and (-not(RecipientTypeDetailsValue -eq ‘ArbitrationMailbox’)) -and (-not(RecipientTypeDetailsValue -eq ‘AuditLogMailbox’)) -and (-not(RecipientTypeDetailsValue -eq ‘AuxAuditLogMailbox’)) -and (-not(RecipientTypeDetailsValue -eq ‘SupervisoryReviewPolicyMailbox’)))

    To note, I have not created this, but I am simply looking to modifiy the (((-not(MemberOfGroup -eq ‘DC=ExcludeFromAllStaff’)) line since we have some issues with that group it looks like. I feel like all the parenthesis aren’t intentionally created by the end user and from your example, it doesn’t look like it.

    Also, reading the specific recipient filter properties here: https://docs.microsoft.com/en-us/powershell/exchange/recipientfilter-properties?view=exchange-ps
    Do you know if it supports Cloud only Security Groups or would I need to convert it to a Mail-enabled security group to get the MemberofGroup functionality working again?

    I appreciate your time and response.

    Thank you,
    Brice H

    1. This looks like it’s a custom filter created using PowerShell. Do you know how it was created?
      The parenthesis are inserted by Exchange to make sure that all of its exclusions (no system mailboxes, no audit mailboxes, no disposition review mailboxes, no discovery mailboxes, and so on) do not show up in the returned set. You can’t do anything about the exclusions or how Exchange formats the command. All you can control is the recipient filter built with PowerShell. If that filter works with Get-Recipient, then it should work with the dynamic distribution list.
      WRT the question about groups, I think any group supported by Exchange will work. The acid test is if it passes the recipient filter.

      1. Unfortunately I don’t know how it was created. The client was onboarded to us with this already in place and we typically would not set up a dynamic distribution list (not a common practice for us).

        I think maybe the option that you are hinting at, and correct me if I am wrong, but if I have a group named ExcludeFromGroupName, a test would be:

        $Filter = “((MemberOfGroup -eq ‘ExcludeFromGroupName’))”

        Get-Recipient -RecipientPreviewFilter $Filter | ft displayname, title

        Do you know if the MemberOfGroup attributing is pulling the DisplayName option?

        Thanks,
        Brice H

      2. This works:
        $DN = (Get-UnifiedGroup ExchangeGoms).DistinguishedName
        $Filter = “((memberOfgroup -eq ‘$DN’) -and (RecipientType -eq ‘UserMailbox’))”
        Get-Recipient -RecipientPreviewFilter $Filter | Ft DisplayName, Title

        DisplayName Title
        ———– —–
        Tony Redmond Principal Architect
        Jeff Guillet Chief ExPTA
        Global Tenant Administrator Office 365 Global Administrator
        Vasil Michev (Technical Guru) Senior Architect

        The important points here are that:

        1. Use the distinguished name property to identify the group for use with MemberOfGroup.
        2. The group can be a Microsoft 365 group (used in my example), a distribution list, or a dynamic distribution list. In other words, its membership has to be under the control of Exchange.

  8. Hi Tony,
    I have a question of how can we ADD a External Contact or another DL to the DDG that is trying to filter out other Contacts and DL’s
    I’ve worked this script except to the point I need to add 4 Contacts either by DL or individuals. Please Take a look: Primary @SET-DDG where I try to add a DL that has the contacts.
    I have replaced identifying information with simple 3 digit or letter combo’s

    ## Used with MFA to connect to ExchangeOnline
    Connect-ExchangeOnline

    ## Enter the name of the Dynamic Distrobution Group here ##
    $DistroIdentity = “123 ALL Emails”

    $List=Get-DynamicDistributionGroup $DistroIdentity

    ## The Separation below is when you customize it per client to remove additional UserMailboxes that you do not want a part of the DDG ##
    ## If Alias doesn’t work, try DisplayName

    Set-DynamicDistributionGroup -identity $DistroIdentity -RecipientFilter {(EmailAddresses -eq “team4@123.com”)
    -and (-not(RecipientTypeDetailsValue -eq ‘SharedMailbox’))
    -and (-not(RecipientTypeDetailsValue -eq ‘RoomMailbox’))
    -and (-not(RecipientType -eq ‘MailContact’))
    -and (-not(RecipientType -eq ‘MailUniversalDistributionGroup’))
    -and (-not(RecipientType -eq ‘MailUniversalSecurityGroup’))
    -and (-not(RecipientTypeDetailsValue -eq ‘EquipmentMailbox’))
    -and (-not(RecipientType -eq ‘MailUser’))
    -and (-not(RecipientType -eq ‘DynamicDistributionGroup’))

    -and (-not(DisplayName -eq “Scanner”))
    -and (-not(Alias -eq “123”))
    -and (-not(Alias -eq “234”))
    -and (-not(Alias -eq “spadmin”))
    -and (-not(Alias -eq “ConferenceRoom”))
    -and (-not(Alias -eq “crestronmanagementaccount”))
    -and (-not(Alias -eq “zoomroomadmin”))
    -and (-not(Alias -eq “345”))
    -and (-not(Displayname -eq “456”))
    -and (-not(Alias -eq “567”))
    -and (-not(Displayname -eq “678”))
    -and (-not(Displayname -eq “789”))
    -and (-not(Displayname -eq “890”))
    -and (-not(Displayname -eq “abc”))
    -and (-not(Alias -eq “bcd”))
    -and (-not(Alias -eq “cde”))
    -and (-not(Displayname -eq “def”))
    -and (-not(Displayname -eq “efg”))
    -and (-not(Displayname -eq “fgh”))
    -and (-not(Displayname -eq “ghi”))
    -and (-not(Alias -eq “hij”))
    -and (-not(Displayname -eq “ijk”))

    }

    Get-Recipient -RecipientPreviewFilter $List.RecipientFilter

    1. I think you are over-complicating things. In situations like this, I use one of the Exchange custom attributes to identify the recipients to be in the DDG. Then you can simply filter on the CustomAttribute which works for all mail-enabled recipient types.

  9. I am attempting to remove disabled accounts from a DDL, however it is not working. We are syncing with on-prem AD to Azure for 365.

    Here is the validation I am doing, but disabled users are still included:

    $Filter = “((Department -like ‘IT*’) -or (Department -eq ‘Data Analytics and Reporting’) -or (Title -eq ‘Chief Information Officer’) -and (RecipientType -eq ‘UserMailbox’) -and (ExchangeUserAccountControl -ne ‘AccountDisabled’))”

    get-recipient -RecipientPreviewFilter $Filter

    1. The documentation says that the values for ExchangeUserAccountControl:

      For valid values, see ADS_USER_FLAG_ENUM enumeration. The integer values will work as described. Most of the text values won’t work as described (even if you remove ADS_UF and all underscores).

      I don’t see a value there for AccountDisabled. Where did you get it?

      I did see a suggested answer on https://social.technet.microsoft.com/Forums/windowsserver/en-US/00aeef18-6528-42a0-9760-118479bf9a7c/dynamic-distribution-list-exclude-disabled-accounts that you could check out.

  10. Hi Tony,

    I created a few DDLs withe intention of populating them with users who have the country or region attribute set according our office countries.

    As an example I have used New-DynamicDistributionGroup -Name “Gibraltar Employees New” -RecipientFilter “(RecipientTypeDetails -eq ‘UserMailbox’) -and (CountryOrRegion -eq ‘Gibraltar’)”

    I mass update all required users CountryOrRegion Attribute via PoSH and a CSV so I know they have this set. But for some reason the list is not fully populating when I check with PoSH using Get-Recipient -RecipientPreviewFilter (Get-DynamicDistributionGroup “Malta Employees New”).RecipientFilter.

    Perhaps I have something wrong but I can’t see what.

Leave a Reply

This site uses Akismet to reduce spam. Learn how your comment data is processed.