AD Group Membership Management

Manipulating AD group membership can definitely be one of the tasks you want to do in bulk and efficiently and PowerShell AD cmdlets are the best way of doing that. Below is my write-up on the main tasks you might need to perform and the PowerShell one-liners to do them.

The main tasks involve:

  • Populating groups based on user properties,
  • Copying group membership,
  • Comparing groups,
  • Restructuring groups.

Below is basically my PowerShell one-liners performing all of the task.

Let’s start with the simplest thing: create a group and populate it by users based on their attributes:

Get-QADUser -Department Accounting | Add-QADGroupMember DL.Accounting

Now, let’s copy the whole group membership to another group (I love this one-liner! Can you get simpler than that?):

Get-QADGroupMember DL.Accounting | Add-QADGroupMember AcctBackup

Let’s compare the two groups now to see whether the group membership is the same:
Compare-Object ( Get-QADGroupMember DL.Accounting) ( Get-QADGroupMember AcctBackup ) -IncludeEqual

InputObject                                                 SideIndicator
-----------                                                 -------------
CN=Jane Nikolsky,CN=Users,DC=domain1,DC=local               ==
CN=Chris Popolutsky,OU=Demo,DC=domain1,DC=local             ==
CN=Janus Demus,OU=Demo,DC=domain1,DC=local                  ==
CN=Kate Schmick,OU=Demo,DC=domain1,DC=local                 ==
CN=Natalia Karolli,OU=Demo,DC=domain1,DC=local              ==

Now, let’s split the accounting group into a few regional subgroups:

# Copy filtered group membership
Get-QADGroupMember DL.Accounting | where {$_.City -eq "Munich"} | Add-QADGroupMember DL.Munich.Accounting
Get-QADGroupMember DL.Accounting | where {$_.City -eq "Berlin"} | Add-QADGroupMember DL.Berlin.Accounting

# Nest the groups
Add-QADGroupMember -Identity DL.Accounting -Member domain1.local/demo/DL.Berlin.Accounting
Add-QADGroupMember -Identity DL.Accounting -Member domain1.local/demo/DL.Munich.Accounting

# Compare groups again
Compare-Object ( Get-QADGroupMember DL.Accounting) ( Get-QADGroupMember DL.Berlin.Accounting ) -IncludeEqual

InputObject                                                 SideIndicator
-----------                                                 -------------
CN=Janus Demus,OU=Demo,DC=domain1,DC=local                  ==
CN=Natalia Karolli,OU=Demo,DC=domain1,DC=local              ==
CN=Jane Nikolsky,CN=Users,DC=domain1,DC=local               <=
CN=Chris Popolutsky,OU=Demo,DC=domain1,DC=local             <=
CN=Kate Schmick,OU=Demo,DC=domain1,DC=local                 <=
CN=DL.Munich.Accounting,OU=Demo,DC=domain1,DC=local         <=
CN=DL.Berlin.Accounting,OU=Demo,DC=domain1,DC=local         <=

# Remove group member duplicates

Get-QADGroupMember DL.Berlin.Accounting | Remove-QADGroupMember DL.Accounting
Get-QADGroupMember DL.Munich.Accounting | Remove-QADGroupMember DL.Accounting

# Check if it worked
Compare-Object ( Get-QADGroupMember DL.Accounting) ( Get-QADGroupMember DL.Munich.Accounting ) -IncludeEqual

InputObject                                                 SideIndicator
-----------                                                 -------------
CN=Chris Popolutsky,OU=Demo,DC=domain1,DC=local             =>
CN=Kate Schmick,OU=Demo,DC=domain1,DC=local                 =>
CN=Jane Nikolsky,CN=Users,DC=domain1,DC=local               <=
CN=DL.Munich.Accounting,OU=Demo,DC=domain1,DC=local         <=
CN=DL.Berlin.Accounting,OU=Demo,DC=domain1,DC=local         <=

# No "Berlin" or "Munich" members left
Get-QADGroupMember DL.Accounting | ft Name, Type, City

Name                                    Type                                    City
----                                    ----                                    ----
Jane Nikolsky                           user                                    Orlando
DL.Munich.Accounting                    group
DL.Berlin.Accounting                    group

P.S. There are some known issues in AD cmdlets 1.0.5 which I worked around in the commands above. These will be fixed in later drops but I will mention them here just in case:

  • If you are adding members to a group not via a pipeline but by providing the -Member parameter, use canonical name for the new member.
  • If you have a group which has the same name as the beginning of another group name (e.g. AB and AB.CD) you might need to supply canonical name instead of name to disambiguate.

Tags: , , , , , , ,


11 Responses to “AD Group Membership Management”

  1. 1 Philipp November 6, 2007 at 3:36 pm

    I think that the powershell method is not the best. Have you heard about active administrator ? I suppose it can do the same things without any coding.

  2. 2 dmitrysotnikov November 6, 2007 at 3:56 pm

    Philipp, I have seen ScriptLogic’s Active Admin and it is a great tool.

    By no means I am saying the PowerShell is the only way to manage groups. It is not and should not be. It is just a command-line which allows you to do tasks you can probably do with other means as well. It is just that sometimes UI is a better way to do some change, and sometimes it is the command-line.

    As Jeffrey Snover was saying in Channel 9 it is not OR, it is AND:

    When you have both UI and scripting/command-line you can pick the tool which is the most appropriate for your particular task. Choice is good.


  3. 3 02dag February 12, 2010 at 1:58 pm

    Hi Dmitry,

    when I try to filter out a user by using a customattribute this never works. It seems to me that activeroles can only see a certain set of attributes. I have alos added the snapin for exchangecommands but it doesnt seem to help. Thats too bad because I think activeroles makes powershell so much more powerful.

  4. 5 Mario February 2, 2011 at 9:12 pm


    Is there away to look at a share, obtain all users and groups assigned then if it is a group get all the members of that group?

    • 6 Dmitry Sotnikov February 5, 2011 at 12:47 am

      Something along these lines?

      (Get-Acl “\\server\share”).Access | ForEach-Object {


      if ((Get-QADGroup ($_.IdentityReference.ToString()) -DontUseDefaultIncludedProperties -ErrorAction SilentlyContinue) -ne $null) {

      Get-QADGroupMember ($_.IdentityReference.ToString()) -Indirect | Select Name


      • 7 Anonymous February 7, 2011 at 12:41 pm

        Perfect like always! How about if the group is a local group, how can i add this in too? This way I can grab Domain and local groups?

  5. 8 Mario February 7, 2011 at 12:41 pm

    Perfect like always! How about if the group is a local group, how can i add this in too? This way I can grab Domain and local groups?

  6. 9 Dmitry Sotnikov February 7, 2011 at 6:32 pm

    Mario: this thread seems to cover getting group membership from a Windows Server fairly well:

    • 10 Mario February 7, 2011 at 7:05 pm

      OK…I have come up with this. Let me know what you think. I will add this to a loop to read a text file with servers and share names.

      Write “ACLS for the resource:”

      $acl = Get-Acl -Path c:\test
      $acl.Access | ForEach-Object { $_.identityReference.value }
      write ————————————————————————————————
      Write “Built-in Group Members:”

      $local = $acl.Access | ForEach-Object { $_.identityReference.value } | Select-String “BUILTIN” | Get-Unique
      $localgrp = Split-Path $local -leaf
      $localgrp | foreach {
      Write $_
      $group =[ADSI]”WinNT://./$_”
      $members = @($group.psbase.Invoke(“Members”))
      $members | foreach {$_.GetType().InvokeMember(“Name”, ‘GetProperty’, $null, $_, $null)}
      Write ————————————————————————————-

      write ————————————————————————————————
      Write “Domain Group Members:”

      $acls=(get-acl c:\test).Access
      $acls | foreach {
      get-qadobject $_.IdentityReference.value |
      foreach {
      if ($_.Type -eq “group”) {
      write = $_.Name
      $grp = Get-QADGroupMember $_.NTAccountName

      Write $grp
      write —————————————————————————
      $grp |
      foreach {
      if ($_.Type -eq “group”) {
      write = $_.Name
      $grp1 = Get-QADGroupMember $_.NTAccountName
      Write $grp1
      write —————————————————————————–


  1. 1 Compare-Object gotcha « Dmitry’s PowerBlog: PowerShell and beyond Trackback on June 6, 2008 at 7:01 am

Leave a Reply

Fill in your details below or click an icon to log in: Logo

You are commenting using your account. Log Out /  Change )

Google+ photo

You are commenting using your Google+ account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )


Connecting to %s

My Recent Tweets


The posts on this blog are provided “as is” with no warranties and confer no rights. The opinions expressed on this site are mine and mine alone, and do not necessarily represent those of my employer - WSO2 or anyone else for that matter. All trademarks acknowledged.

© 2007-2014 Dmitry Sotnikov

October 2007
« Sep   Nov »

%d bloggers like this: