From dd361a12979ea8f3fa84076fd906bce96378fe60 Mon Sep 17 00:00:00 2001 From: seanwlk Date: Wed, 5 Jun 2019 18:34:03 +0200 Subject: [PATCH 1/5] Added adsearch.by_sam() --- pyad/adsearch.py | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/pyad/adsearch.py b/pyad/adsearch.py index b46c6cf..46ad35e 100644 --- a/pyad/adsearch.py +++ b/pyad/adsearch.py @@ -17,6 +17,19 @@ def by_cn(cn, search_base=None, options={}): type="GC") return _ad_query_obj.get_single_result()['distinguishedName'] +def by_sam(sAMAccountName, search_base=None, options={}): + if not search_base: + if not ADBase.default_domain: + raise Exception("Unable to detect default domain. Must specify search base.") + search_base = ADBase.default_domain + _ad_query_obj.reset() + + _ad_query_obj.execute_query(where_clause=("sAMAccountName = '%s'" % sAMAccountName), + base_dn=search_base, + options=options, + type="GC") + return _ad_query_obj.get_single_result()['distinguishedName'] + def by_upn(upn, search_base=None, options={}): if not search_base: if not ADBase.default_forest: From 19b3dcad79e3f2e288c6055c185dce65375186b0 Mon Sep 17 00:00:00 2001 From: seanwlk Date: Wed, 5 Jun 2019 18:37:18 +0200 Subject: [PATCH 2/5] Changed ADBase to default_domain for all_results_by_upn() I'm unsure of what happened here, but if I try this in our domain it always returns a void list because it cannot get the forest. As soon as i changed it to default domain it worked. --- pyad/adsearch.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/pyad/adsearch.py b/pyad/adsearch.py index 46ad35e..1852eb5 100644 --- a/pyad/adsearch.py +++ b/pyad/adsearch.py @@ -69,9 +69,9 @@ def all_results_by_cn(cn, search_base=None, options={}): def all_results_by_upn(upn, search_base=None, options={}): if not search_base: - if not ADBase.default_forest: - raise Exception("Unable to detect default forest. Must specify search base.") - search_base = ADBase.default_forest + if not ADBase.default_domain: + raise Exception("Unable to detect default domain. Must specify search base.") + search_base = ADBase.default_domain _ad_query_obj.reset() _ad_query_obj.execute_query(where_clause=("userPrincipalName = '%s'" % upn), base_dn=search_base, From e13c4d016f47b64ea1a752c6df0a59ecb1eee262 Mon Sep 17 00:00:00 2001 From: seanwlk Date: Wed, 5 Jun 2019 18:45:42 +0200 Subject: [PATCH 3/5] "Normalized" user creation method In a normal AD, the object gets created with the CN (Common Name) and sAMAccountName different from each other. With the current process, the function creates the user with the given sAMAccountName and puts it as CN too, which makes it not editable later in the script since AD blocks you from editing the CN of a "opened" object. Example: CN = "Walker Sean" sAMAccountName = "seanwlk" --- pyad/adcontainer.py | 8 ++++---- pyad/aduser.py | 5 +++-- 2 files changed, 7 insertions(+), 6 deletions(-) diff --git a/pyad/adcontainer.py b/pyad/adcontainer.py index 2461b8b..280b167 100644 --- a/pyad/adcontainer.py +++ b/pyad/adcontainer.py @@ -26,14 +26,14 @@ def __create_object(self, type_, name): prefixed_name = '='.join((prefix,name)) return self._ldap_adsi_obj.Create(type_, prefixed_name) - def create_user(self, name, password=None, upn_suffix=None, enable=True,optional_attributes={}): + def create_user(self, sAMAccountName, cn, password=None, upn_suffix=None, enable=True,optional_attributes={}): """Create a new user object in the container""" try: if not upn_suffix: upn_suffix = self.get_domain().get_default_upn() - upn = '@'.join((name, upn_suffix)) - obj = self.__create_object('user', name) - obj.Put('sAMAccountName', optional_attributes.get('sAMAccountName', name)) + upn = '@'.join((sAMAccountName, upn_suffix)) + obj = self.__create_object('user', cn) + obj.Put('sAMAccountName', optional_attributes.get('sAMAccountName', sAMAccountName)) obj.Put('userPrincipalName', upn) obj.SetInfo() pyadobj = ADUser.from_com_object(obj) diff --git a/pyad/aduser.py b/pyad/aduser.py index d0d0644..8cde4f5 100644 --- a/pyad/aduser.py +++ b/pyad/aduser.py @@ -6,11 +6,12 @@ class ADUser(ADObject): @classmethod - def create(cls, name, container_object, password=None, upn_suffix=None, + def create(cls, sAMAccountName, cn, container_object, password=None, upn_suffix=None, enable=True, optional_attributes={}): """Creates and returns a new active directory user""" return container_object.create_user( - name=name, + sAMAccountName=sAMAccountName, + cn=cn, password=password, upn_suffix=upn_suffix, enable=enable, From a0387f69ec684b2c5e507a1f7d807bc53e8146e5 Mon Sep 17 00:00:00 2001 From: seanwlk Date: Wed, 5 Jun 2019 19:26:39 +0200 Subject: [PATCH 4/5] CN made optional in accont creation, default CN = sAMAccountName --- pyad/adcontainer.py | 7 +++++-- pyad/aduser.py | 2 +- 2 files changed, 6 insertions(+), 3 deletions(-) diff --git a/pyad/adcontainer.py b/pyad/adcontainer.py index 280b167..ce81460 100644 --- a/pyad/adcontainer.py +++ b/pyad/adcontainer.py @@ -26,13 +26,16 @@ def __create_object(self, type_, name): prefixed_name = '='.join((prefix,name)) return self._ldap_adsi_obj.Create(type_, prefixed_name) - def create_user(self, sAMAccountName, cn, password=None, upn_suffix=None, enable=True,optional_attributes={}): + def create_user(self, sAMAccountName, cn=None, password=None, upn_suffix=None, enable=True,optional_attributes={}): """Create a new user object in the container""" try: if not upn_suffix: upn_suffix = self.get_domain().get_default_upn() upn = '@'.join((sAMAccountName, upn_suffix)) - obj = self.__create_object('user', cn) + if not cn: + obj = self.__create_object('user', sAMAccountName) + else: + obj = self.__create_object('user', cn) obj.Put('sAMAccountName', optional_attributes.get('sAMAccountName', sAMAccountName)) obj.Put('userPrincipalName', upn) obj.SetInfo() diff --git a/pyad/aduser.py b/pyad/aduser.py index 8cde4f5..de643fc 100644 --- a/pyad/aduser.py +++ b/pyad/aduser.py @@ -6,7 +6,7 @@ class ADUser(ADObject): @classmethod - def create(cls, sAMAccountName, cn, container_object, password=None, upn_suffix=None, + def create(cls, sAMAccountName, container_object, cn=None, password=None, upn_suffix=None, enable=True, optional_attributes={}): """Creates and returns a new active directory user""" return container_object.create_user( From f7763ca81bcf87504357d0ae83974a7501ead67c Mon Sep 17 00:00:00 2001 From: seanwlk Date: Tue, 25 Jun 2019 08:14:22 +0200 Subject: [PATCH 5/5] Added adsearch.by_mail() --- pyad/adsearch.py | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/pyad/adsearch.py b/pyad/adsearch.py index 1852eb5..2be34df 100644 --- a/pyad/adsearch.py +++ b/pyad/adsearch.py @@ -30,6 +30,19 @@ def by_sam(sAMAccountName, search_base=None, options={}): type="GC") return _ad_query_obj.get_single_result()['distinguishedName'] +def by_mail(mail, search_base=None, options={}): + if not search_base: + if not ADBase.default_domain: + raise Exception("Unable to detect default domain. Must specify search base.") + search_base = ADBase.default_domain + _ad_query_obj.reset() + + _ad_query_obj.execute_query(where_clause=("mail = '%s'" % mail), + base_dn=search_base, + options=options, + type="GC") + return _ad_query_obj.get_single_result()['distinguishedName'] + def by_upn(upn, search_base=None, options={}): if not search_base: if not ADBase.default_forest: