Welcome, guest | Sign In | My Account | Store | Cart

Script to enumerate the members of groups in the domain.

Python, 136 lines
  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
""" Script to enumerate the members of groups in the domain"""
import sys
from win32com.client import *

## The values should be the groups you wish to examine, use the group's sAMAccountName
groups = ['Administrators', 'Account Operators', 'Backup Operators',
            'Server Operators', 'DnsAdmins', 'Domain Admins', 
            'Exchange Administrators', 'Exchange Services', 
            'DHCP Administrators']

# Select the AD attributes you wish the query to return
attribs = "name,member,objectClass,adspath,primaryGroupToken,primaryGroupID"
objConnection = Dispatch("ADODB.Connection")
objConnection.Open("Provider=ADsDSOObject")

def getDefaultDN(server=None):
    """ Get the base LDAP Naming Context, used specified server if available."""

    if server is None:
        ldap_root = GetObject('LDAP://rootDSE')
    else:
        ldap_root = GetObject('LDAP://%s/rootDSE' % server)

    ldap_loc = ldap_root.Get('defaultNamingContext')

    return ldap_loc

def getGrpInfo(name, searchRoot, category="Group"):
    """ Find the group in AD and set up a dictionary for its attributes.
    
    searchRoot is the part of the LDAP tree that you want to start searching from.
    category filters what objedts to search on.  So you could also search for a User.
    name is the account's sAMAccountName which is a unique identifier in AD.
    attribs is the list of attributes to return from the query.
    """
    strSearch = \
        "<LDAP://%s>;(&(objectCategory=%s)(sAMAccountName=%s));%s;subtree" % \
        (searchRoot, category, name, attribs)
    objRecordSet = objConnection.Execute(strSearch)[0]
    objRecord = dict()

    # Normally, we would only expect one object to be retrieved.
    if objRecordSet.RecordCount == 1:
        # Set up a dictionary with attribute/value pairs and return the dictionary.
        for f in objRecordSet.Fields:
            objRecord[f.Name] = f.Value

        #print objRecord.items()
        return objRecord
    else:
        # Group not found
        return None

def getGrpMembers(strLdap, header=""):
    """ Recursively look up a group's members.
    
    strLdap is the groups adspath attribute.
    header is used for indenting to show sub groups.
    """
    strSearch = "<%s>;;%s" % (strLdap, attribs)
    objRecordSet = objConnection.Execute(strSearch)[0]
    objRecord = dict()
    memberList = []

    # Normally, we would only expect one object to be retrieved.
    if objRecordSet.RecordCount == 1:
        for f in objRecordSet.Fields:
            objRecord[f.Name] = f.Value

        # Check to see if the group has any members
        if objRecord['member'] is not None:
            # Look up each member and get their LDAP object
            for mbr in objRecord['member']:
                objRS = objConnection.Execute("<LDAP://%s>;;name,objectClass,adspath" % mbr)[0]

                # Check to see if the member is a group.
                # If so, look up its members.
                # The Field index number corresponds to the order that you list the
                # attributes in on the LDAP query string.
                if 'group' in objRS.Fields[1].Value:
                    memberList.append("%sGroup - %s, members:" % (header, objRS.Fields[0].Value))
                    memberList.extend(getGrpMembers(objRS.Fields[2].Value, header+"   "))
                else:
                    memberList.append("%s%s" % (header, objRS.Fields[0].Value))
        
    # Return the list of results
    return memberList

def getPrimaryGroup(searchRoot, token, header="   "):
    """ Used to look up Users whose Primary Group is set to one of the groups we're
    looking up.  This is necessary as AD uses that attribute to calculate a group's
    membership.  These type of users do not show up if you query the group's member field
    directly.
    
    searchRoot is the part of the LDAP tree that you want to start searching from.
    token is the groups primaryGroupToken.
    """
    strSearch = \
        "<LDAP://%s>;(primaryGroupID=%d);name;subtree" % \
        (searchRoot, token)
    objRecordSet = objConnection.Execute(strSearch)[0]
    memberList = []

    # Process if accounts are found.
    if objRecordSet.RecordCount > 0:
        memberList.append("Primary Group calculated:")
        objRecordSet.MoveFirst()

        while not objRecordSet.EOF:
            memberList.append("%s%s" % (header, objRecordSet.Fields[0].Value))
            objRecordSet.MoveNext()
            
    # Return the list of results
    return memberList

def main(server=None):
    """ Main program logic. """
    dn = getDefaultDN(server)
    message = []

    for grp in groups:
        objGrp = getGrpInfo(grp, dn)
        # If the group is found, process the group's membership.
        if objGrp is not None:
            message.append("\nMembers of %s:" % objGrp['name'])
            message.extend(getGrpMembers(objGrp['adspath']))
            message.extend(getPrimaryGroup(dn, objGrp['primaryGroupToken']))    
            
    print "\n".join(message)

if __name__ == '__main__':
    if len(sys.argv) == 1:
        main()
    else:
        # If a server is given on the command line, run the script against it.
        main(sys.argv[1])

This is an example of how you can look up all the members of a group in AD. It will also look up the membership of any sub-groups it finds.

It will also use the groups primary group token and find all users that have that group set as their primary group. This is necessary as AD uses the primaryGroupID to calculate a group's membership.

1 comment

Esteban Guillardoy 16 years, 8 months ago  # | flag

How do I query a Domain Controller with a user in another domain? This code works great when you run it with a user that is in the same domain, but fails if you try to get information from a domain controller in another domain.

For example, say we have user1 that is in DOMAIN1 (the domain controller would be SERVER1).
I want to get information from groups in SERVER2 that is the domain controller of DOMAIN2.

If I run this script with user DOMAIN1\user1 I can't get it to work.
If I run this with a user of DOMAIN2 it works ok!

Is there any way to run this script and get information using a user and computer outside the domain?

Any comment will be appreciated!