Active Directory - Unnest AD groups from nested AD group RRS feed

  • Question

  • i have written code to unnest AD group members from AD groups

    # to give the count of child groups 

    ChildGroupCount = Get-ADGroupMember -Identity $group| measure | select -ExpandProperty count

    # to give members details in AD group

    Get-ADGroupMember Grandparent -Recursive

    I need help to find the cmdlet we use to unnest AD groups from AD group. 

    suresh arasu

    Wednesday, December 4, 2019 4:29 PM

All replies

  • child AD groups are in parent group as MEMBEROF can you please help me to find out any other cmdlet apart from REMOVE-ADGroup.

    Because remove-adgroup cmdlet removes AD group from forest which i dont want. I just want the nesting hierarchy to be flattened. 

    suresh arasu

    Friday, December 6, 2019 12:16 PM
  • Group nesting can make groups easier to manage, and permissions easier to administer. For example, all members of nested groups get the permissions granted to the parent group. There is no need to also grant the same permissions to the nested groups.

    If a nested group is removed from a parent group, then all members of the nested group (including any members due to any further nesting) should be added as direct members of the parent group. Otherwise, the nested group members will lose all permissions granted to the parent group. But care must be taken to avoid adding the same member more than once. Users can be members of more than one group nested under the parent group.

    A made up example might be as follows, with one parent group and four nested groups.
    Each group has its own members, and probably its own permissions:

    With nested groups
    Parent Group   Direct Members   Nested Members   Nested Members
    ------------   --------------   --------------   --------------
    Sales (group)  East (group)     Jim (user)
                                    Sally (user)
                                    Keith (user)
                                    Pluto (computer)
                                    Boston (group)   Mary (user)
                                                     John (user)
                                                     Harvard (computer)
                   Frank (user)
                   Nova (computer)
                   West (group)     Keith (user)
                                    Will (user)
                                    Denver (group)    Jerry (user)
                                                      Linda (user)
                                                      Frank (user)
                                                      Venus (computer)

    After all group nesting is removed, the group membership should be as follows.
    This ensures that no one loses permissions:

    Parent Group   Direct Members
    ------------   --------------
    Sales (group)  Jim (user)
                   Sally (user)
                   Keith (user)
                   Pluto (computer)
                   Mary (user)
                   John (user)
                   Harvard (computer)
                   Frank (user)
                   Nova (computer)
                   Keith (user)
                   Will (user)
                   Jerry (user)
                   Linda (user)
                   Venus (computer)
    East (group)   Jim (user)
                   Sally (user)
                   Pluto (computer)
                   Mary (user)
                   John (user)
                   Harvard (computer)
    Boston (group) Mary (user)
                   John (user)
                   Harvard (computer)
    West (group)   Keith (user)
                   Will (user)
                   Jerry (user)
                   Linda (user)
                   Venus (computer)
    Denver (group) Jerry (user)
                   Linda (user)
                   Frank (user)
                   Venus (computer)

    This looks more complicated. And note that the users Keith and Frank were members of multiple nested groups, but they can only be added once to any parent group. Any attempt to add a user twice to a group will raise an error.

    It would be a challenge to design a script to do this.

    Richard Mueller - MVP Enterprise Mobility (Identity and Access)

    Saturday, December 7, 2019 1:33 AM
  • Thanks richard.. I want to accomplish the task in this way

    Parent -        1st level nesting -              2nd level nesting                           3rd level

    GroupA -      rajesh (user)                         Accounting_security (Group)       Management_admin(Group)       

                      mahesh (user)                         HR_listing (Group)                    Access_remote (Group)

                      pradeep (user)                                                                         Master_line (Group)


                      Admin_finance (GROUP)

         I want to retain the first level of nesting. 2nd level nesting which is MEMBEROF in ADGroup i have to flatten. 

    I have already taken export of all nested groups and members access. once denesting is accomplished I will add the access of last AD group user access to 1 level higher AD group and follow the access in the same hierarchy (This step will make sure that user access does not impact inspite of AD groups flattened)

    Only step i am stuck is denesting. which cmdlet can remove AD group nesting.



    suresh arasu

    Saturday, December 7, 2019 7:31 PM
  • I'm not sure I understand what you plan to do, but I will discuss how to remove nested groups.

    No PowerShell cmdlet can remove group nesting. Instead you must enumerate all direct group members, determine which are groups, then remove these from the Member property of the parent group. The -Remove parameter of the Set-ADGroup cmdlet can remove an array of DistinguishedNames from the Member property.

    The following has not been tested.

    # Specify the DistinguishedName (DN) of the parent group.
    # We will remove all members of this group that have class "group".
    $GroupDN = "cn=Sales,ou=West,dc=domain,dc=com"
    # The Member property is an array of the DistinguishedNames (DN) of all direct members of the group.
    # The DN is required by Get-ADObject, which we use to determine the class of each member.
    $Members = (Get-ADGroup -Identity $GroupDN -Properties Member).Member
    # Create an array of distinguished names of nested groups to remove.
    $GroupsToRemove = @()
    # Enumerate all direct members of the parent group and determine which are nested groups.
    ForEach ($Member In $Members)
        # Members can be users, computers, contacts, or nested groups. We only consider groups.
        $Class = (Get-ADOject -Identity $Member).ObjectClass
        If ($Class -eq "group")
            # Add the DN of this nested group to the array of groups to remove.
            $GroupsToRemove = $GroupsToRemove + $Member
    # Remove any nested groups from the parent group.
    If ($GroupsToRemove.Count -gt 0)
        Set-ADGroup -Identity $GroupDN -Remove @{Member=$GroupsToRemove}

    Richard Mueller - MVP Enterprise Mobility (Identity and Access)

    • Edited by Richard MuellerMVP Friday, January 10, 2020 4:11 PM fixed typo, For Each should be ForEach in the code
    Saturday, December 7, 2019 11:51 PM
  • thanks Richard. 

    I tested $GroupDN = Import-CSV -path c:\scripts\groupdn.csv and was able to remove the groups which is in member column of AD group.

    but if you could help me to retain the AD group in member column but remove the AD groups which are nested 1 level inside the parent group.

    i tried using MemberOf column instead of Member but didnt work. any inputs will be helpfull.

    Below link to show member and memberof difference

    suresh arasu

    Friday, December 20, 2019 12:53 PM
  • The -Remove parameter of Set-ADGroup cannot be used with the MemberOf property because it is a back link attribute. Member is the forward link, memberOf the corresponding back link. My theory is that -Remove cannot be used with MemberOf because the value is not actually saved in Active Directory database. Instead the back link attribute references a link table to determine the DN of the group.

    Edit: This Wiki describes how -Clear, -Add, -Remove, and -Replace cannot be used with back link attributes.

    Richard Mueller - MVP Enterprise Mobility (Identity and Access)

    Saturday, December 21, 2019 10:04 PM
  • This is really informative about the attribute which cannot be altered using PsH Cmdlet. 

    So another Last question with regards to same query... in the above script we are able to remove AD groups in member column of AD group. can we use parameter or add loop to retain the 1st AD group in member column but remove other embedded groups inside.

    Sorry if it was confusing.

    AD group : member 

                    Raj (user)

                   chris (user)

                  Finance_group_0 (AD group) ; Finance_level_1 ; Finance_level_2 ; Finance_level_3

                 HR_group (AD Group) HR_group_0 ; HR_group_1; Finance_level_2


    So here i want to retain members raj, chris, Finance_group_0, HR_group, management in members column of AD group.

    I want to denest (flatten, unnest) Finance_level_1 ; Finance_level_2 ; Finance_level_3; HR_group_0 ; HR_group_1; Finance_level_2

    Can we use loop in your member removal script to achieve above thought. 


    suresh arasu

    Monday, December 23, 2019 4:36 AM
  • Thanks Richard. can we denest retaining the access of user to the groups.

    Because i am sure from the given script the groups are denested but the user who is bottom (Child group) will be removed from the top parent groups.

    suresh arasu

    Friday, January 10, 2020 6:17 AM
  • You are correct that users will lose permissions granted to parent groups.

    For example, if user jsmith is a member of GroupA, and GroupA is a member of GroupB, then if GroupA is removed from GroupB, user jsmith will lose any permissions granted to GroupB (the parent group). That is why I suggested earlier that user jsmith should be made a member of GroupB, in this example.

    Any script to do this could get rather complicated, especially if there is a lot of nesting. But an idea occurs to me that could make this easier. I need some time to think about it. And it assumes two things. First, the "primary" group of each user is not involved (which should always be the group "Domain Users", so everyone is probably already a member of this group). Second, that all groups involved are security groups, no distribution groups. But distribution groups cannot have permissions granted to them. I'll let you know if I find my idea feasible.

    Richard Mueller - MVP Enterprise Mobility (Identity and Access)

    Friday, January 10, 2020 4:00 PM
  • I think the following script should work (I cannot test at this time). It should be run before the previous script to remove all group nesting, so that users have not already lost permissions and the tokenGroups attribute still reveals membership in all groups due to nesting. This script makes sure users are direct members of all groups they are in due to group nesting. Then when nesting is removed, they are still members of all the groups and have all permission granted to the groups.

    # PowerShell script to make users the direct members of every group they are members of due to group nesting.
    # This script should be run before removing all group nesting.
    # Enumerate all users.
    $UserDNs = Get-ADUser -Filter * | Select DistinguishedName
    # To limit this to users in an OU, use similar to:
    # $UserDNs = Get-ADUser -Filter * -SearchBase "ou=Sales,ou=West,dc=domain,dc=com" | Select DistinguishedName
    # To limit this to the direct user members of a group, use similar to:
    # $UserDNs = Get-ADUser -LDAPFilter "(memberOf=cn=Accting,ou=Sales,ou=West,dc=domain,dc=com)" | Select DistinguishedName
    # Enumerate the users.
    ForEach ($User In $UserDNs)
        # Bind to the user object in Active Directory with the [ADSI] accelerator.
        # This is necessary to retrieve the tokenGroups attribute, which is operational (constructed).
        $UserDN = $User.DistinguishedName
        $ADObject = [ADSI]"LDAP://$UserDN"
        # Retrieve the tokenGroups attributes of the user.
        # The tokenGroups attribute is operational and requires special techniques.
        # The attribute is an array of group SID values, one for each security group the user is a member of,
        # including due to any group nesting. It does not include the "primary" group of the user
        # or any distribution groups.
        $SIDs = $ADObject.psbase.Properties.Item("tokenGroups")
        # Retrieve the memberOf attribute of the user.
        # The memberOf attribute is array of group DNs, one for each group the user is a direct member of.
        $DirectGroups = $ADObject.memberOf
        # String of group DNs. The DNs must be quoted and comma delimited.
        $GroupsAddTo = ""
        # Enumerate the SID values.
        ForEach ($Value In $SIDs)
            # Convert the SID byte array into the string SID value.
            $SID = New-Object System.Security.Principal.SecurityIdentifier $Value, 0
            # Bind to the group object with the string SID.
            $Group = [ADSI]"LDAP://<SID=$SID>"
            # Retrieve the distinguishedName of the group.
            $GroupDN = $Group.distinguishedName
            # Check if the user is a direct member of this group.
            If ($GroupDN -NotIn $DirectGroups)
                # Append the group DN to the string of groups this user will be added to.
                If ($GroupsAddTo -eq "") {$GroupsAddTo = "$GroupDN"}
                Else {$GroupsAddTo = "$GroupsAddTo, ""$GroupDN"""}
        # Add the user as a direct member of all the groups in the string.
        If ($GroupsAddTo -ne "") {Add-ADPrincipalGroupMembership -Identity $UserDN -MembersOf $GroupsAddTo}

    Richard Mueller - MVP Enterprise Mobility (Identity and Access)

    Friday, January 10, 2020 7:47 PM
  • thanks Richard.. 

    i just tried to execute for the script with sample example "direct members of group" but i get error as ADprincipalgroupmembership cannot be found. line 52

    suresh arasu

    Monday, January 13, 2020 6:37 AM
  • The PowerShell cmdlet is Add-ADPrincipalGroupMembership, documented here:

    If your test script included the Get-ADUser cmdlet, then the PowerShell AD module must be available. But otherwise, unless you misspelled the name, perhaps you need to include the following at the beginning of the script:

    Import-Module ActiveDirectory

    Richard Mueller - MVP Enterprise Mobility (Identity and Access)

    Monday, January 13, 2020 10:29 AM