Jump to content

Active Directory UDF - Help & Support


water
 Share

Recommended Posts

I've expanded the code to set the option as suggested in one of my previous posts. Maybe this helps:

Func _AD_SetGroupManagerCanModify($sAD_Group)

    Local Const $ADS_OPTION_SECURITY_MASK = 3 ; See: http://msdn.microsoft.com/en-us/library/windows/desktop/aa772273(v=vs.85).aspx
    Local Const $ADS_SECURITY_INFO_DACL = 0x4 ; See: http://msdn.microsoft.com/en-us/library/windows/desktop/aa772293(v=vs.85).aspx
    If _AD_ObjectExists($sAD_Group) = 0 Then Return SetError(1, 0, 0)
    If StringMid($sAD_Group, 3, 1) <> "=" Then $sAD_Group = _AD_SamAccountNameToFQDN($sAD_Group) ; sAMAccountName provided
    If _AD_GroupManagerCanModify($sAD_Group) = 1 Then Return SetError(2, 0, 0)
    Local $oAD_Group = _AD_ObjGet("LDAP://" & $sAD_HostServer & "/" & $sAD_Group)
    Local $sAD_ManagedBy = $oAD_Group.Get("managedBy")
    If $sAD_ManagedBy = "" Then Return SetError(3, 0, 0)
    Local $oAD_User = _AD_ObjGet("LDAP://" & $sAD_HostServer & "/" & $sAD_ManagedBy)
    Local $aAD_UserFQDN = StringSplit($sAD_ManagedBy, "DC=", 1)
    Local $sAD_Domain = StringTrimRight($aAD_UserFQDN[2], 1)
    Local $sAD_SamAccountName = $oAD_User.Get("sAMAccountName")
    Local $oAD_SD = $oAD_Group.Get("ntSecurityDescriptor")
    $oAD_SD.Owner = $sAD_Domain & "" & @UserName
    Local $oAD_DACL = $oAD_SD.DiscretionaryAcl
    Local $oAD_ACE = ObjCreate("AccessControlEntry")
    $oAD_ACE.Trustee = $sAD_Domain & "" & $sAD_SamAccountName
    $oAD_ACE.AccessMask = $ADS_RIGHT_DS_WRITE_PROP
    $oAD_ACE.AceFlags = 0
    $oAD_ACE.AceType = $ADS_ACETYPE_ACCESS_ALLOWED_OBJECT
    $oAD_ACE.Flags = $ADS_FLAG_OBJECT_TYPE_PRESENT
    $oAD_ACE.ObjectType = $SELF_MEMBERSHIP
    $oAD_DACL.AddAce($oAD_ACE)
    $oAD_SD.DiscretionaryAcl = _AD_ReorderACE($oAD_DACL)
    ; Set options to only update the DACL. See: http://www.activedir.org/ListArchives/tabid/55/view/topic/postid/28231/Default.aspx
    $oAD_Group.Setoption($ADS_OPTION_SECURITY_MASK, $ADS_SECURITY_INFO_DACL)
    $oAD_Group.Put("ntSecurityDescriptor", $oAD_SD)
    $oAD_Group.SetInfo
    If @error <> 0 Then Return SetError(@error, 0, 0)
    Return 1

EndFunc   ;==>_AD_SetGroupManagerCanModify

My UDFs and Tutorials:

Spoiler

UDFs:
Active Directory (NEW 2022-02-19 - Version 1.6.1.0) - Download - General Help & Support - Example Scripts - Wiki
ExcelChart (2017-07-21 - Version 0.4.0.1) - Download - General Help & Support - Example Scripts
OutlookEX (2021-11-16 - Version 1.7.0.0) - Download - General Help & Support - Example Scripts - Wiki
OutlookEX_GUI (2021-04-13 - Version 1.4.0.0) - Download
Outlook Tools (2019-07-22 - Version 0.6.0.0) - Download - General Help & Support - Wiki
PowerPoint (2021-08-31 - Version 1.5.0.0) - Download - General Help & Support - Example Scripts - Wiki
Task Scheduler (NEW 2022-07-28 - Version 1.6.0.1) - Download - General Help & Support - Wiki

Standard UDFs:
Excel - Example Scripts - Wiki
Word - Wiki

Tutorials:
ADO - Wiki
WebDriver - Wiki

 

Link to comment
Share on other sites

Glad we could solve the problem! So it was a permission problem as described in one of my posts.

My UDFs and Tutorials:

Spoiler

UDFs:
Active Directory (NEW 2022-02-19 - Version 1.6.1.0) - Download - General Help & Support - Example Scripts - Wiki
ExcelChart (2017-07-21 - Version 0.4.0.1) - Download - General Help & Support - Example Scripts
OutlookEX (2021-11-16 - Version 1.7.0.0) - Download - General Help & Support - Example Scripts - Wiki
OutlookEX_GUI (2021-04-13 - Version 1.4.0.0) - Download
Outlook Tools (2019-07-22 - Version 0.6.0.0) - Download - General Help & Support - Wiki
PowerPoint (2021-08-31 - Version 1.5.0.0) - Download - General Help & Support - Example Scripts - Wiki
Task Scheduler (NEW 2022-07-28 - Version 1.6.0.1) - Download - General Help & Support - Wiki

Standard UDFs:
Excel - Example Scripts - Wiki
Word - Wiki

Tutorials:
ADO - Wiki
WebDriver - Wiki

 

Link to comment
Share on other sites

I have a question about _AD_ObjectExists

Why must we run _AD_GetObjectAttributes prior to running _AD_ObjectExists?

If you don't run get object attributes will the object exists not run correctly?

In my example from another script

$vGetAttribute = _AD_GetObjectAttribute($sUsername, "sAMAccountName")
        If _AD_ObjectExists($sUsername, "sAMAccountName") Then
            $bUserExists = True
            Sleep(5000)

the code works, but it has been so long since I create the script this code came out of, I forget WHY I am calling get object attribute. It isn't referenced by a handle or anything in the object exists call, so I'm just curious why it is there.

Link to comment
Share on other sites

The call to _AD_GetObjectAttribute is not needed.

But I've noticed that the docu for _AD_ObjectExists isn't clear so I'm going to improve it.

My UDFs and Tutorials:

Spoiler

UDFs:
Active Directory (NEW 2022-02-19 - Version 1.6.1.0) - Download - General Help & Support - Example Scripts - Wiki
ExcelChart (2017-07-21 - Version 0.4.0.1) - Download - General Help & Support - Example Scripts
OutlookEX (2021-11-16 - Version 1.7.0.0) - Download - General Help & Support - Example Scripts - Wiki
OutlookEX_GUI (2021-04-13 - Version 1.4.0.0) - Download
Outlook Tools (2019-07-22 - Version 0.6.0.0) - Download - General Help & Support - Wiki
PowerPoint (2021-08-31 - Version 1.5.0.0) - Download - General Help & Support - Example Scripts - Wiki
Task Scheduler (NEW 2022-07-28 - Version 1.6.0.1) - Download - General Help & Support - Wiki

Standard UDFs:
Excel - Example Scripts - Wiki
Word - Wiki

Tutorials:
ADO - Wiki
WebDriver - Wiki

 

Link to comment
Share on other sites

Experimental Version 1.2.1.0 has been released.

For testing purpose only!

Needs 3.3.9.2 beta for the new way the UDF handles COM errors!

For download please see my signature.

My UDFs and Tutorials:

Spoiler

UDFs:
Active Directory (NEW 2022-02-19 - Version 1.6.1.0) - Download - General Help & Support - Example Scripts - Wiki
ExcelChart (2017-07-21 - Version 0.4.0.1) - Download - General Help & Support - Example Scripts
OutlookEX (2021-11-16 - Version 1.7.0.0) - Download - General Help & Support - Example Scripts - Wiki
OutlookEX_GUI (2021-04-13 - Version 1.4.0.0) - Download
Outlook Tools (2019-07-22 - Version 0.6.0.0) - Download - General Help & Support - Wiki
PowerPoint (2021-08-31 - Version 1.5.0.0) - Download - General Help & Support - Example Scripts - Wiki
Task Scheduler (NEW 2022-07-28 - Version 1.6.0.1) - Download - General Help & Support - Wiki

Standard UDFs:
Excel - Example Scripts - Wiki
Word - Wiki

Tutorials:
ADO - Wiki
WebDriver - Wiki

 

Link to comment
Share on other sites

Water, this is a very useful UDF! Thank you for posting it. I've made good use of it so far however i've hit a snag:

I have a multi-domain environment with users that are members of groups in all domains. So for instance a user in "domain1" is a member of a security group that is based in "domain2". The problem is that the "_AD_RemoveUserFromGroup" function claims those users don't exist when you try to remove them even though i can see them in the array when you run "_AD_GetGroupMembers". It will only remove users that are in the same domain as the group. Is there a workaround for this? I've tried multiple things without success...I'm trying to clean up these security groups (a mess i inherited :oops:) Any ideas would be appreciated.

Link to comment
Share on other sites

Water, this is a very useful UDF! Thank you for posting it. I've made good use of it so far however i've hit a snag:

I have a multi-domain environment with users that are members of groups in all domains. So for instance a user in "domain1" is a member of a security group that is based in "domain2". The problem is that the "_AD_RemoveUserFromGroup" function claims those users don't exist when you try to remove them even though i can see them in the array when you run "_AD_GetGroupMembers". It will only remove users that are in the same domain as the group. Is there a workaround for this? I've tried multiple things without success...I'm trying to clean up these security groups (a mess i inherited :oops:) Any ideas would be appreciated.

When running the _AD_RemoveUserFromGroup Did you specify the domain for the user account as well or just the username? You could also try the following...

1. Get the SID associated with the user (make sure you open a connection to DomainB with _AD_Open() first): _AD_GetObjectProperties($UserDN, "objectSID")

2. On my domain, users from DomainB that are members of a group in DomainA have the following DN's specified:

CN=S-1-5-21-1371183983-1057381791-735938884-63415,CN=ForeignSecurityPrincipals,DC=DomainA,DC=com

Where the SID is the SID of the user's account from DomainB, and of course DC=DomainA,DC=com should match the proper name for the domain containing your group.

So...

_AD_Open("user","pass",$DomainB_DNS_Name)
$UserSID = _AD_GetObjectProperties($username, "objectSID")
_AD_Close
_AD_Open("user","pass",$DomainA_DNS_Name)
_AD_RemoveUserFromGroup($groupDN, "CN=" & $UserSID & ",CN=ForeignSecurityPrincipals,DC=DomainA,DC=com")
_AD_Close()
Edited by sublimnl
Link to comment
Share on other sites

When running the _AD_RemoveUserFromGroup Did you specify the domain for the user account as well or just the username? You could also try the following...

1. Get the SID associated with the user (make sure you open a connection to DomainB with _AD_Open() first): _AD_GetObjectProperties($UserDN, "objectSID")

2. On my domain, users from DomainB that are members of a group in DomainA have the following DN's specified:

CN=S-1-5-21-1371183983-1057381791-735938884-63415,CN=ForeignSecurityPrincipals,DC=DomainA,DC=com

Where the SID is the SID of the user's account from DomainB, and of course DC=DomainA,DC=com should match the proper name for the domain containing your group.

So...

_AD_Open("user","pass",$DomainB_DNS_Name)
$UserSID = _AD_GetObjectProperties($username, "objectSID")
_AD_Close
_AD_Open("user","pass",$DomainA_DNS_Name)
_AD_RemoveUserFromGroup($groupDN, "CN=" & $UserSID & ",CN=ForeignSecurityPrincipals,DC=DomainA,DC=com")
_AD_Close()

I was trying with both the samaccount name and the FQDN with no luck. I thought the FQDN would work since it specifies the domain, but it didn't. I didn't try getting the SID, but that is a great idea. I'll try that here in a bit and let you know.

Thanks!

Link to comment
Share on other sites

It should work. I just tested it out in my environment and it worked for me. :oops:

Unfortunately, it didn't work in my environment. Debug still says the user doesn't exist. I verified that it is getting the SID correctly and all. I have a ForeignSecurityPrincipals container, but it doesn't appear to be configured. I'm told by a former admin that he has removed foreign domain users with no problem using the DS tools in a script on our same environment. Hopefully he can dig up that script so i can see what may be different. I'll keep tinkering in the meantime. Thanks for trying though :bye: If you have any other ideas let me know.

Link to comment
Share on other sites

Sorry, I forgot that _AD_GetObjectProperties returns an array. So you want $UserSID[1][1]. Give that a shot.

Actually that doesn't work either and i think i know why. I didn't explain that we are on subdomains and not actual different domains. So We basically have a primary domain with 3 sub domains. So my issue is removing users that are a member of primarydomain.subdomainA.company.com from groups that are based in primarydomain.subdomainB.company.com. That could be the problem, but i'm not sure how to work around it.
Link to comment
Share on other sites

I'm not sure if you are familiar with the ADFIND tool (http://www.joeware.net/freetools/tools/adfind/) but download that and run the following command:

adfind -h <DC_FOR_SUBDOMAINB> -f "samaccountname=<GROUPNAME>" member

This will output the DN for every user that is a member of that group. Find the SubDomainA users in there and make sure that your code is specifying their DN's correctly when you try to remove them. I dont have a subdomain architecture to test with here, so I'm not sure what those DN's would look like. If you can post a sample DN here then I can try to help you out a little more.

Edited by sublimnl
Link to comment
Share on other sites

Ok, i ran it and got this for a sample DN: CN=Bruce Potter,OU=Users,OU=Site1,OU=Sites,DC=SUBDOMAINB,DC=COMPANY,DC=LOCAL

I took that and pasted it in plain text into the function as a test and it still says the user doesn't exist. :

_AD_RemoveUserFromGroup("CN=GROUP1,OU=Applications,OU=Groups,OU=Enterprise,DC=SUBDOMAINA,DC=COMPANY,DC=LOCAL", "CN=Bruce Potter,OU=Users,OU=Site1,OU=Sites,DC=SUBDOMAINB,DC=COMPANY,DC=LOCAL")

Keep in mind i am running the script from within subdomainA and the group is located in subdomainA. The user is in subdomainB but a member of the group in subdomainA. I'm trying to remove that user. Thanks again, for trying to help out with this. If i can get it working it will be a tremendous help.

Link to comment
Share on other sites

Hmmm, not sure why that would be. I actually have a similar script that I wrote this week to allow some secretaries to update group membership for certain projects and one of those groups contains 3rd party users whose accounts we keep in a separate domain entirely. I was able to successfully automate the task of adding and removing these trusted domain users from groups in our domain, which is in essence the same thing you are trying to do. The only difference is that my users were in a separate forest that we have a trust established with while yours are in a separate domain in the same forest. I cant explain it - actually your scenario should be the easier of the two! Maybe water will have an idea?

Have you thought about using DSQUERY/DSMOD commands to do the dirty work and just parsing the output from those to make sure that the commands are successfully run? I know its not as elegant of a solution when compared to a native AutoIt script using UDF's, but if you aren't too picky about it then you can probably get that working and move on rather than spinning your wheels here.

Link to comment
Share on other sites

The problem is caused by function _AD_RemoveUserFromGroup. It checks the user and group for existance. If it can't find the user or group you get the described error.

I'm no domain admin so I don't know too much about domains, forrests etc.

A - possibly - quick & dirty solution would be to write _AD_RemoveUserFromGroupEX function without the checks:

; #FUNCTION# ====================================================================================================================
; Name...........: _AD_RemoveUserFromGroup
; Description ...: Removes the user from the specified group.
; Syntax.........: _AD_RemoveUserFromGroup($sAD_Group, $sAD_User)
; Parameters ....: $sAD_Group - Groupname (FQDN or sAMAccountName)
;                 $sAD_User - Username (FQDN or sAMAccountName)
; Return values .: Success - 1
;                 Failure - 0, sets @error to:
;                 |1 - $sAD_Group does not exist
;                 |2 - $sAD_User does not exist
;                 |3 - $sAD_User is not a member of $sAD_Group
;                 |x - Error returned by SetInfo Function(Missing permission etc.)
; Author ........: Jonathan Clelland
; Modified.......: water
; Remarks .......: Works for computer objects as well. Remember that the sAMAccountname of a computer needs a trailing "$" before converting it to a FQDN.
; Related .......: _AD_CreateOU, _AD_CreateUser, _AD_CreateGroup, _AD_AddUserToGroup
; Link ..........:
; Example .......: Yes
; ===============================================================================================================================
Func _AD_RemoveUserFromGroup($sAD_Group, $sAD_User)
 
    If Not _AD_ObjectExists($sAD_Group) Then Return SetError(1, 0, 0)
;~    If Not _AD_ObjectExists($sAD_User) Then Return SetError(2, 0, 0)
    If Not _AD_IsMemberOf($sAD_Group, $sAD_User) Then Return SetError(3, 0, 0)
    If StringMid($sAD_Group, 3, 1) <> "=" Then $sAD_Group = _AD_SamAccountNameToFQDN($sAD_Group) ; sAMACccountName provided
    If StringMid($sAD_User, 3, 1) <> "=" Then $sAD_User = _AD_SamAccountNameToFQDN($sAD_User) ; sAMACccountName provided
    Local $oAD_User = _AD_ObjGet("LDAP://" & $sAD_HostServer & "/" & $sAD_User) ; Retrieve the COM Object for the user
    Local $oAD_Group = _AD_ObjGet("LDAP://" & $sAD_HostServer & "/" & $sAD_Group) ; Retrieve the COM Object for the group
    $oAD_Group.Remove($oAD_User.AdsPath)
    $oAD_Group.SetInfo
    If @error <> 0 Then Return SetError(@error, 0, 0)
    Return 1
 
EndFunc   ;==>_AD_RemoveUserFromGroup

My UDFs and Tutorials:

Spoiler

UDFs:
Active Directory (NEW 2022-02-19 - Version 1.6.1.0) - Download - General Help & Support - Example Scripts - Wiki
ExcelChart (2017-07-21 - Version 0.4.0.1) - Download - General Help & Support - Example Scripts
OutlookEX (2021-11-16 - Version 1.7.0.0) - Download - General Help & Support - Example Scripts - Wiki
OutlookEX_GUI (2021-04-13 - Version 1.4.0.0) - Download
Outlook Tools (2019-07-22 - Version 0.6.0.0) - Download - General Help & Support - Wiki
PowerPoint (2021-08-31 - Version 1.5.0.0) - Download - General Help & Support - Example Scripts - Wiki
Task Scheduler (NEW 2022-07-28 - Version 1.6.0.1) - Download - General Help & Support - Wiki

Standard UDFs:
Excel - Example Scripts - Wiki
Word - Wiki

Tutorials:
ADO - Wiki
WebDriver - Wiki

 

Link to comment
Share on other sites

Thanks for the ideas. I've found that the problem runs deeper than just the checks. I've commented all of them out and have now traced it down to errors generated after the _AD_ObjGet function. The error code is -2147352567. I haven't researched to find out what that means yet, but for now i'll just use the DSQUERY/DSMOD commands. I'll keep playing with it on the side until I get it to work and then I'll write a function for it and post it. Thanks again for you guys' input, it helped get me on the right track at least.

Link to comment
Share on other sites

Guest
This topic is now closed to further replies.
 Share

  • Recently Browsing   0 members

    • No registered users viewing this page.
×
×
  • Create New...