Including Members from Other Groups in Membership of Dynamic Groups
Until recently, Dynamic Azure AD Groups have not supported the ability to include members from other groups in their membership (aka, nested groups). You can construct membership rules to include the same accounts in a dynamic group, but it’s easier to say, “include the members from groups 1, 2, and 3” if those groups already exist and include the necessary accounts.
In a June 6 announcement, Microsoft introduced a preview feature to allow the membership rules for dynamic Azure AD groups to use the memberOf attribute. In essence, memberOf instructs Azure AD to extract the membership of one to up to 50 groups and include the individual members of those groups in the dynamic membership.
Creating a New Azure AD Dynamic Group
Apparently, the preview feature is available worldwide. I had no success using it in the Azure AD admin center. Any attempt to create a new group (of any type) generated the error: “per label policy, the selected visibility is not allowed” (Figure 1). No doubt this is due to some configuration I have tweaked, but the error message is obscure, to say the least. (Update: I discovered the root cause of the problem, which Microsoft say they will fix).
Figure 1: Azure AD fails to create a group
But where the will exists, you get the job done, and PowerShell came to the rescue. I created the new dynamic group with the following command. You can see that the membership rule is that the membership comes from any user members in the specified groups.
Microsoft’s documentation doesn’t include any reference to using distribution lists, but as Azure AD treats distribution lists like other groups, it seemed like they should work. After all, you can run the Get-MgGroupMember cmdlet (or Get-AzureADGroupMember if you still haven’t converted from the soon-to-be-deprecated module) against a distribution list and Azure AD is happy to list the members. And as it turns out, you can include the membership of distribution lists in dynamic Azure AD groups. After an hour or so, Azure AD resolved the rule and built the membership of the new dynamic group, including the removal of any duplicates (Figure 2).
Figure 2: Membership of the new dynamic Azure AD group
Preview Limits
During the preview, a dynamic group can have up to 50 groups in its membership, and each tenant can have up to 500 dynamic groups that use the memberOf attribute in their membership rule. If you add security groups to the membership of a dynamic group, Azure AD includes only the direct members of the security group in the dynamic group’s membership.
In addition, Microsoft says that you can’t use a dynamic group that uses the memberOf attribute to define the membership of another group that also uses memberOf. The old and well-proven adage to keep it simple (stupid) rings loud and clear. Don’t nest groups inside groups and don’t over-complicate things. Perhaps more complicated arrangements might be possible in the future, but for the preview, don’t give Azure AD complex membership rules to resolve. For more information on including groups within the membership of dynamic groups, read Microsoft’s documentation.
Another issue is that the memberOf attribute can’t be used with other rules. For instance, let’s assume that you assemble a set of users drawn from the membership of several other group. You can’t add another filter to select people whose accounts match another attribute, such as the department or country.
For now, the rules editor doesn’t work for this type of dynamic group, nor does the other Validate Rules preview feature which allows administrators to check the effectiveness of a membership rule against an account that they know should be in a group’s membership (Figure 3).
Figure 3: Azure AD can’t validate membership of a dynamic group
Dynamic Teams Work Too
I updated the group’s properties to enable it for Teams. Support for dynamic teams has been around since 2018, but it’s always wise to check. The good news is that the dynamic membership for the team appears as expected (Figure 4).
Figure 4: Teams membership roster for the dynamic Azure AD group
Solid Update
There’s no doubt that this is a good change. Anything that adds to the flexibility and capability of dynamic Azure AD groups is a good thing. The bad thing is that Microsoft requires Azure AD Premium P1 for dynamic groups (Exchange Online dynamic distribution lists don’t need additional licenses). The guidance is:
This feature requires an Azure AD Premium P1 license or Intune for Education for each unique user that is a member of one or more dynamic groups. You don’t have to assign licenses to users for them to be members of dynamic groups.
It would be nice if dynamic groups were included in Office 365 E3, but life is cruel sometimes…
So much change, all the time. It’s a challenge to stay abreast of all the updates Microsoft makes across Office 365. Subscribe to the Office 365 for IT Pros eBook to receive monthly insights into what happens, why it happens, and what new features and capabilities mean for your tenant.
6 Replies to “Microsoft Previews Nested Dynamic Azure AD Groups”
Well, I followed your guide pretty closely, but got a kick back of Unsupported property ‘objectId’ any clue what this could reference?
$Group = New-MgGroup -DisplayName “Steve’s test member of DDG” -Description “Dynamic group testing new member of feature in preview” -MailEnabled:$true -SecurityEnabled:$false -Mail “StevesTestDDG@burnsmcd.com” -MailNickname “StevesTestDDG” -GroupTypes “DynamicMembership”, “Unified” -MembershipRule “user.memberOf -any (group.ojbectId -in [‘fb963324-b6b3-46a3-b98f-7590093cce75’])” -MembershipRuleProcessingState “On”
New-MgGroup_CreateExpanded: Unsupported property ‘ojbectId’
Great write-up. I’m trying to
“user.memberof -any (group.objectId -in [”]) -and (user.country -eq ‘US’)” it picks up the users from the Group but seems to ignore the other portion.
MemberOf can’t be used with other rules. For example, a rule that states dynamic group A should contain members of group B and also should contain only users located in Redmond will fail.
From the documentation: MemberOf can’t be used with other operators. For example, you can’t create a rule that states “Members Of group A can’t be in Dynamic group B.”
{"id":null,"mode":"button","open_style":"in_modal","currency_code":"EUR","currency_symbol":"\u20ac","currency_type":"decimal","blank_flag_url":"https:\/\/office365itpros.com\/wp-content\/plugins\/tip-jar-wp\/\/assets\/images\/flags\/blank.gif","flag_sprite_url":"https:\/\/office365itpros.com\/wp-content\/plugins\/tip-jar-wp\/\/assets\/images\/flags\/flags.png","default_amount":100,"top_media_type":"featured_image","featured_image_url":"https:\/\/office365itpros.com\/wp-content\/uploads\/2022\/11\/cover-141x200.jpg","featured_embed":"","header_media":null,"file_download_attachment_data":null,"recurring_options_enabled":true,"recurring_options":{"never":{"selected":true,"after_output":"One time only"},"weekly":{"selected":false,"after_output":"Every week"},"monthly":{"selected":false,"after_output":"Every month"},"yearly":{"selected":false,"after_output":"Every year"}},"strings":{"current_user_email":"","current_user_name":"","link_text":"Virtual Tip Jar","complete_payment_button_error_text":"Check info and try again","payment_verb":"Pay","payment_request_label":"Office 365 for IT Pros","form_has_an_error":"Please check and fix the errors above","general_server_error":"Something isn't working right at the moment. Please try again.","form_title":"Office 365 for IT Pros","form_subtitle":null,"currency_search_text":"Country or Currency here","other_payment_option":"Other payment option","manage_payments_button_text":"Manage your payments","thank_you_message":"Thank you for supporting the work of Office 365 for IT Pros!","payment_confirmation_title":"Office 365 for IT Pros","receipt_title":"Your Receipt","print_receipt":"Print Receipt","email_receipt":"Email Receipt","email_receipt_sending":"Sending receipt...","email_receipt_success":"Email receipt successfully sent","email_receipt_failed":"Email receipt failed to send. Please try again.","receipt_payee":"Paid to","receipt_statement_descriptor":"This will show up on your statement as","receipt_date":"Date","receipt_transaction_id":"Transaction ID","receipt_transaction_amount":"Amount","refund_payer":"Refund from","login":"Log in to manage your payments","manage_payments":"Manage Payments","transactions_title":"Your Transactions","transaction_title":"Transaction Receipt","transaction_period":"Plan Period","arrangements_title":"Your Plans","arrangement_title":"Manage Plan","arrangement_details":"Plan Details","arrangement_id_title":"Plan ID","arrangement_payment_method_title":"Payment Method","arrangement_amount_title":"Plan Amount","arrangement_renewal_title":"Next renewal date","arrangement_action_cancel":"Cancel Plan","arrangement_action_cant_cancel":"Cancelling is currently not available.","arrangement_action_cancel_double":"Are you sure you'd like to cancel?","arrangement_cancelling":"Cancelling Plan...","arrangement_cancelled":"Plan Cancelled","arrangement_failed_to_cancel":"Failed to cancel plan","back_to_plans":"\u2190 Back to Plans","update_payment_method_verb":"Update","sca_auth_description":"Your have a pending renewal payment which requires authorization.","sca_auth_verb":"Authorize renewal payment","sca_authing_verb":"Authorizing payment","sca_authed_verb":"Payment successfully authorized!","sca_auth_failed":"Unable to authorize! Please try again.","login_button_text":"Log in","login_form_has_an_error":"Please check and fix the errors above","uppercase_search":"Search","lowercase_search":"search","uppercase_page":"Page","lowercase_page":"page","uppercase_items":"Items","lowercase_items":"items","uppercase_per":"Per","lowercase_per":"per","uppercase_of":"Of","lowercase_of":"of","back":"Back to plans","zip_code_placeholder":"Zip\/Postal Code","download_file_button_text":"Download File","input_field_instructions":{"tip_amount":{"placeholder_text":"How much would you like to tip?","initial":{"instruction_type":"normal","instruction_message":"How much would you like to tip? Choose any currency."},"empty":{"instruction_type":"error","instruction_message":"How much would you like to tip? Choose any currency."},"invalid_curency":{"instruction_type":"error","instruction_message":"Please choose a valid currency."}},"recurring":{"placeholder_text":"Recurring","initial":{"instruction_type":"normal","instruction_message":"How often would you like to give this?"},"success":{"instruction_type":"success","instruction_message":"How often would you like to give this?"},"empty":{"instruction_type":"error","instruction_message":"How often would you like to give this?"}},"name":{"placeholder_text":"Name on Credit Card","initial":{"instruction_type":"normal","instruction_message":"Enter the name on your card."},"success":{"instruction_type":"success","instruction_message":"Enter the name on your card."},"empty":{"instruction_type":"error","instruction_message":"Please enter the name on your card."}},"privacy_policy":{"terms_title":"Terms and conditions","terms_body":null,"terms_show_text":"View Terms","terms_hide_text":"Hide Terms","initial":{"instruction_type":"normal","instruction_message":"I agree to the terms."},"unchecked":{"instruction_type":"error","instruction_message":"Please agree to the terms."},"checked":{"instruction_type":"success","instruction_message":"I agree to the terms."}},"email":{"placeholder_text":"Your email address","initial":{"instruction_type":"normal","instruction_message":"Enter your email address"},"success":{"instruction_type":"success","instruction_message":"Enter your email address"},"blank":{"instruction_type":"error","instruction_message":"Enter your email address"},"not_an_email_address":{"instruction_type":"error","instruction_message":"Make sure you have entered a valid email address"}},"note_with_tip":{"placeholder_text":"Your note here...","initial":{"instruction_type":"normal","instruction_message":"Attach a note to your tip (optional)"},"empty":{"instruction_type":"normal","instruction_message":"Attach a note to your tip (optional)"},"not_empty_initial":{"instruction_type":"normal","instruction_message":"Attach a note to your tip (optional)"},"saving":{"instruction_type":"normal","instruction_message":"Saving note..."},"success":{"instruction_type":"success","instruction_message":"Note successfully saved!"},"error":{"instruction_type":"error","instruction_message":"Unable to save note note at this time. Please try again."}},"email_for_login_code":{"placeholder_text":"Your email address","initial":{"instruction_type":"normal","instruction_message":"Enter your email to log in."},"success":{"instruction_type":"success","instruction_message":"Enter your email to log in."},"blank":{"instruction_type":"error","instruction_message":"Enter your email to log in."},"empty":{"instruction_type":"error","instruction_message":"Enter your email to log in."}},"login_code":{"initial":{"instruction_type":"normal","instruction_message":"Check your email and enter the login code."},"success":{"instruction_type":"success","instruction_message":"Check your email and enter the login code."},"blank":{"instruction_type":"error","instruction_message":"Check your email and enter the login code."},"empty":{"instruction_type":"error","instruction_message":"Check your email and enter the login code."}},"stripe_all_in_one":{"initial":{"instruction_type":"normal","instruction_message":"Enter your credit card details here."},"empty":{"instruction_type":"error","instruction_message":"Enter your credit card details here."},"success":{"instruction_type":"normal","instruction_message":"Enter your credit card details here."},"invalid_number":{"instruction_type":"error","instruction_message":"The card number is not a valid credit card number."},"invalid_expiry_month":{"instruction_type":"error","instruction_message":"The card's expiration month is invalid."},"invalid_expiry_year":{"instruction_type":"error","instruction_message":"The card's expiration year is invalid."},"invalid_cvc":{"instruction_type":"error","instruction_message":"The card's security code is invalid."},"incorrect_number":{"instruction_type":"error","instruction_message":"The card number is incorrect."},"incomplete_number":{"instruction_type":"error","instruction_message":"The card number is incomplete."},"incomplete_cvc":{"instruction_type":"error","instruction_message":"The card's security code is incomplete."},"incomplete_expiry":{"instruction_type":"error","instruction_message":"The card's expiration date is incomplete."},"incomplete_zip":{"instruction_type":"error","instruction_message":"The card's zip code is incomplete."},"expired_card":{"instruction_type":"error","instruction_message":"The card has expired."},"incorrect_cvc":{"instruction_type":"error","instruction_message":"The card's security code is incorrect."},"incorrect_zip":{"instruction_type":"error","instruction_message":"The card's zip code failed validation."},"invalid_expiry_year_past":{"instruction_type":"error","instruction_message":"The card's expiration year is in the past"},"card_declined":{"instruction_type":"error","instruction_message":"The card was declined."},"missing":{"instruction_type":"error","instruction_message":"There is no card on a customer that is being charged."},"processing_error":{"instruction_type":"error","instruction_message":"An error occurred while processing the card."},"invalid_request_error":{"instruction_type":"error","instruction_message":"Unable to process this payment, please try again or use alternative method."},"invalid_sofort_country":{"instruction_type":"error","instruction_message":"The billing country is not accepted by SOFORT. Please try another country."}}}},"fetched_oembed_html":false}
Well, I followed your guide pretty closely, but got a kick back of Unsupported property ‘objectId’ any clue what this could reference?
$Group = New-MgGroup -DisplayName “Steve’s test member of DDG” -Description “Dynamic group testing new member of feature in preview” -MailEnabled:$true -SecurityEnabled:$false -Mail “StevesTestDDG@burnsmcd.com” -MailNickname “StevesTestDDG” -GroupTypes “DynamicMembership”, “Unified” -MembershipRule “user.memberOf -any (group.ojbectId -in [‘fb963324-b6b3-46a3-b98f-7590093cce75’])” -MembershipRuleProcessingState “On”
New-MgGroup_CreateExpanded: Unsupported property ‘ojbectId’
(group.ojbectId is misspelt. It should be group.objectid
Great write-up. I’m trying to
“user.memberof -any (group.objectId -in [”]) -and (user.country -eq ‘US’)” it picks up the users from the Group but seems to ignore the other portion.
You’re hitting a preview limitation: https://docs.microsoft.com/en-us/azure/active-directory/enterprise-users/groups-dynamic-rule-member-of#preview-limitations
MemberOf can’t be used with other rules. For example, a rule that states dynamic group A should contain members of group B and also should contain only users located in Redmond will fail.
I’ve now called this out explicitly in the text.
How to use this rule AND (NOT IsMemberOf(“XXXXXXXX”))
From the documentation: MemberOf can’t be used with other operators. For example, you can’t create a rule that states “Members Of group A can’t be in Dynamic group B.”
I don’t think this is currently possible.