sublimnl Posted March 11, 2012 Share Posted March 11, 2012 Its a 2003 DC. I'll try with a 2008 DC and let you know what happens. Will also get one of the full on domain admins to give it a shot for me on Monday. Thanks for the help. Link to comment Share on other sites More sharing options...
water Posted March 11, 2012 Author Share Posted March 11, 2012 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 2024-07-28 - Version 1.6.3.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 (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 More sharing options...
sublimnl Posted March 12, 2012 Share Posted March 12, 2012 This code works! Thank you! Link to comment Share on other sites More sharing options...
water Posted March 12, 2012 Author Share Posted March 12, 2012 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 2024-07-28 - Version 1.6.3.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 (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 More sharing options...
kor Posted March 15, 2012 Share Posted March 15, 2012 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 More sharing options...
water Posted March 15, 2012 Author Share Posted March 15, 2012 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 2024-07-28 - Version 1.6.3.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 (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 More sharing options...
water Posted March 18, 2012 Author Share Posted March 18, 2012 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 2024-07-28 - Version 1.6.3.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 (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 More sharing options...
caton777 Posted March 20, 2012 Share Posted March 20, 2012 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 ) Any ideas would be appreciated. Link to comment Share on other sites More sharing options...
sublimnl Posted March 20, 2012 Share Posted March 20, 2012 (edited) 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 ) 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 March 20, 2012 by sublimnl Link to comment Share on other sites More sharing options...
caton777 Posted March 20, 2012 Share Posted March 20, 2012 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 More sharing options...
sublimnl Posted March 20, 2012 Share Posted March 20, 2012 It should work. I just tested it out in my environment and it worked for me. Link to comment Share on other sites More sharing options...
caton777 Posted March 20, 2012 Share Posted March 20, 2012 It should work. I just tested it out in my environment and it worked for me. 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 If you have any other ideas let me know. Link to comment Share on other sites More sharing options...
sublimnl Posted March 21, 2012 Share Posted March 21, 2012 Sorry, I forgot that _AD_GetObjectProperties returns an array. So you want $UserSID[1][1]. Give that a shot. Link to comment Share on other sites More sharing options...
caton777 Posted March 22, 2012 Share Posted March 22, 2012 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 More sharing options...
sublimnl Posted March 22, 2012 Share Posted March 22, 2012 (edited) 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>" memberThis 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 March 22, 2012 by sublimnl Link to comment Share on other sites More sharing options...
caton777 Posted March 22, 2012 Share Posted March 22, 2012 Ok thanks! i will try that and post the results in a bit. Link to comment Share on other sites More sharing options...
caton777 Posted March 22, 2012 Share Posted March 22, 2012 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 More sharing options...
sublimnl Posted March 22, 2012 Share Posted March 22, 2012 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 More sharing options...
water Posted March 22, 2012 Author Share Posted March 22, 2012 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 2024-07-28 - Version 1.6.3.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 (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 More sharing options...
caton777 Posted March 22, 2012 Share Posted March 22, 2012 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 More sharing options...
Recommended Posts