Active Directory |
 
Active Directory combines all sorts of domain-wide information into one spot. Using Microsoft's COM LDAP provider, python has good access to Active Directory.
To access active directory, it is easiest to put some boilerplate code
into a functions for future use. This will be done w/python's COM
access to Active Directory. If you use python's ldap library, you can
do similar stuff. Unfortunately, Microsoft switched directions
w/exchange. You used to be able to access a lot of exchange
functionality with ldap which no longer exists. Now, COM is needed.
Here is a list of the functions
A tool that can be of a great help is ADSIedit which is in the Windows 2000 support tools on the Windows 2000 server cdrom. It gives you the raw ldap view of active directory.
def discover():
Here is a function that helps you determine the active directory ldap strings that you can actually use.
#get base LDAP string
ldap_loc=win32com.client.GetObject('LDAP://rootDSE').Get("defaultNamingContext")
#container where users are put it, may be like:
ldap_main_loc='OU=people,'+ldap_loc
Finding out about exchange, it is a bit more complicated.
#typical exchange string
ex_loc='CN=Microsoft Exchange,CN=Services,CN=Configuration'
#look for your exchange sites
ex_sites=[]
for i in win32com.client.GetObject('LDAP://'+ex_loc+','+ldap_loc):
if i.cn!='Active Directory Connections': ex_sites.append(i.cn)
#get an exchange server
ex_admin_grps='CN=Administrative Groups,cn='+ex_site+','+ex_loc+','+ldap_loc
admin_grp=win32com.client.GetObject('LDAP://'+ex_admin_grps)[0].cn
ex_servers='LDAP://CN=Servers,'+'cn='+admin_grp+','+ex_admin_grps
servers=win32com.client.GetObject(ex_servers)
ex_servers=[]
for i in servers:
ex_servers.append(i.cn)
print '\texchange servers',string.join(ex_servers)
ex_first_store='CN=First Storage Group,CN=InformationStore,CN=%s,CN=Servers,CN=%s,%s'%(ex_servers[-1],admin_grp,ex_admin_grps)
ex_stores=[]
for i in win32com.client.GetObject('LDAP://'+ex_first_store):
ex_stores.append('cn='+i.cn+','+ex_first_store)
print '\tExchange stores:',string.join(ex_stores,"',")
This then allows things like:
print('The last name: ',opends('fred').sn) #sn =surname
or to get the groups fred is a member of
print("groups=',opends('fred').memberOf)
def opends(loc,server=''):
'''automatically buoild ldap string and authenticate
ldap=win32com.client.Dispatch('ADsNameSpaces').getobject("","LDAP:")
ldap_main_loc='OU=people,DC=ad,DC=company,DC=state,DC=oh,DC=us'
ldap_auth='CN=admin_account,'+ldap_main_loc
#if there is no "," then they are not providing a full url
#so append the standard url for it
#if there is no '=', assume they want a cn
if loc.find(',')==-1:
if loc.find('=')==-1: loc='cn='+loc+','+Ad.ldap_main_loc
else: loc=loc+','+Ad.ldap_main_loc
if loc.find('LDAP://')==-1: loc='LDAP://'+loc
return ldap.OpenDSObject(loc,Ad.ldap_auth,Ad.pw,1)
You would use ad_dict like a normal python dictionary.
for i in ad_dict('fred').items():
print(i)
A lot of things convert to automatic python data types. For others, you'll get stuff like
COMObject. You need to do specific processing, like the one done for
pwdLastSet below, to extract data from them.
def ad_dict(ldapobj,attr_dict={},recurse=0,auth=1,filter=()):
if ldapobj.find(',')==-1: ldapobj='cn='+ldapobj+','+Ad.ldap_main_loc
if auth: #setup authenticated connections
if debug: print 'auth'
adobj=opends(ldapobj)
#if debug: print 'authenticated to',ldapobj
else:
adobj=win32com.client.GetObject('LDAP://'+ldapobj)
if debug: print 'connected to',ldapobj
if not(filter):
#check for children
for i in adobj:
if debug: print '****at',i.cn,str(adobj.cn)
if recurse:
pass
#get children's attributes too
#attr_dict[i.distinguishedName]={}
#get_all(i.distinguishedName,attr_dict[i.distinguishedName],recurse,auth)
if debug: print 'getting schema'
schema_obj=win32com.client.GetObject(adobj.schema)
for i in schema_obj.MandatoryProperties:
if i =='nTSecurityDescriptor':continue #takes a long time, skip it
value=getattr(adobj,i)
if value: attr_dict[i]=value
for i in schema_obj.OptionalProperties:
value=getattr(adobj,i)
if i == 'pwdLastSet':
#convert com object to sec since 1970
attr_dict[i]=conv_time(adobj.pwdLastSet.lowpart,adobj.pwdLastSet.highpart)
elif value: attr_dict[i]=value
else:
attr_dict={}
#only get data that is available
for item in filter:
try:
if item == 'pwdLastSet':
#convert com object to sec since 1970
attr_dict[item]=conv_time(adobj.pwdLastSet.lowpart,adobj.pwdLastSet.highpart)
else: attr_dict[item]=getattr(adobj,item)
except:
pass
return attr_dict
def conv_time(l,h):
#converts 64-bit integer specifying the number of 100-nanosecond
#intervals which have passed since January 1, 1601.
#This 64-bit value is split into the
#two 32 bits stored in the structure.
d=116444736000000000L #diference between 1601 and 1970
#we divide by 10million to convert to seconds
return (((long(h)<< 32) + long(l))-d)/10000000
ADSI, Exchange, and Python |