Python-ldap Query MS Active Directory
I use Python to pull Active Directory information sometimes. In my case mainly to report or view information but also to create files in a LDIF or PowerShell format. These can be manually run on the Domain Controller later. For instance find all users in a Distribution List or Group and create a rule or ldif entry that can manually be executed line by line. Off course there is also ways with PowerShell and vbscript to do this, but I prefer Python for text manipulation and it is not too cumbersome for me to batch run these files manually later.
I noticed on Ubuntu 12.10 that my query failed with the following error:
ldap.LDAP_CONTROL_PAGE_OID,True,(page_size,'')
AttributeError: 'module' object has no attribute 'LDAP_CONTROL_PAGE_OID'
I found a comment from the developers saying that with python-ldap 2.4
"there have been changes in the API for LDAPv3 extended controls. Please see Demo/page_control.py (and Demo/paged_search_ext_s.py) how to use the simple paged control with 2.4."
I found the source here: http://python-ldap.cvs.sourceforge.net/viewvc/python-ldap/python-ldap/Demo/page_control.py?view=log
I made a new script and tested as shown below:
** Note the following first:
- This is a "paged" query meaning you should not have issues if LDAP return a limted number of results. More detail here: http://support.microsoft.com/kb/315071
- You need to install python-ldap of course. apt-get install python-ldap should work on apt systems.
- Check comment about using 512 as userAccountControl.
DistributionList = "CN=IT Infrastructure,CN=Distribution Lists,CN=Users,DC=domain,DC=com" url = "ldap://usdc101" base = "dc=domain,dc=com" # search_flt = r'(objectClass=*)' ## I used userAccountControl=512 but that would most certainly exclude some ## user accounts in your domain. For instance "66048 Enabled, Password Doesn't Expire" ## values listed here: http://www.netvision.com/ad_useraccountcontrol.php search_flt = r'(&(objectCategory=user) (userAccountControl=512) )' page_size = 10 import ldap,pprint from ldap.controls import SimplePagedResultsControl searchreq_attrlist=["displayName","cn","distinguishedName","mail","memberOf"] ldap.set_option(ldap.OPT_REFERRALS, 0) l = ldap.initialize(url,trace_level=0) l.protocol_version = 3 l.simple_bind_s("ADaccount@domain.com", "passsword") req_ctrl = SimplePagedResultsControl(True,size=page_size,cookie='') known_ldap_resp_ctrls = { SimplePagedResultsControl.controlType:SimplePagedResultsControl, } # Send search request msgid = l.search_ext( base, ldap.SCOPE_SUBTREE, search_flt, attrlist=searchreq_attrlist, serverctrls=[req_ctrl] ) pages = 0 i = 0 print "listing users in the list:" + DistributionList while True: pages += 1 rtype, rdata, rmsgid, serverctrls = l.result3(msgid,resp_ctrl_classes=known_ldap_resp_ctrls) for dn, entry in rdata: ## Lets check if the user is a member of the AD List / Group try: membership = entry['memberOf'] except: membership = 'none' if DistributionList in membership: i += 1 print " \"%d\" | \"%s\" " % (i , dn) pctrls = [ c for c in serverctrls if c.controlType == SimplePagedResultsControl.controlType ] if pctrls: if pctrls[0].cookie: # Copy cookie from response control to request control req_ctrl.cookie = pctrls[0].cookie msgid = l.search_ext( base, ldap.SCOPE_SUBTREE, search_flt, attrlist=searchreq_attrlist, serverctrls=[req_ctrl] ) else: break else: print "Warning: Server ignores RFC 2696 control." break l.unbind_s()