Active Directory UDF

1,299 posts in this topic




Posted

I've finished to implement the read-only functions (see previous post).

Before I start with the write-functions I need a volunteer to help me test this functions as I don't have write access to an Active Directory.

Share this post


Link to post
Share on other sites

Posted

Just wanted to say that you've done an awesome job thus far!!! I look forward to using this UDF!!!

I'm converting Jonathan Clelland adfunctions.au3 to a full AutoiIt UDF including help file, examples, ScITE integration etc.

In a first step the readonly functions will be converted.

In a second step all other functions will follow.

Share this post


Link to post
Share on other sites

Posted

Anyone willing to run the example scripts and report errors/problems?

Share this post


Link to post
Share on other sites

Posted (edited)

hi,

Sorry for my bad English, I speak Spanish.

I can test functions. I have an AD, in which test some of the functions read-only of your library.

I leave my mail marianilucas@gmail.com

greetings

Edited by FractalReactor

Share this post


Link to post
Share on other sites

Posted (edited)

More then 50 downloads and still no error reports? ;)

Edited by water

Share this post


Link to post
Share on other sites

Posted (edited)

More then 50 downloads and still no error reports? ;)

Working great Water! I'm currently using it in production.

I've adapted the example to my environment, it will check for FQDN group if you want but you can change it to general

Func _AD_UserInGroup($ADusername,$ADGroupName,$FQDN = 0)
	; Open Connection to the Active Directory
	local $founduser
	_AD_Open()

	; Get an array of group names (FQDN) that the current user is immediately a member of
	_AD_GetUserGroups($aUser, $ADusername)

	IF $FQDN = 0 Then 
		$ADGroupName = "CN=" & $ADGroupName & ","
	Endif
	
	For $each in $aUser
		IF StringinStr($each,$ADGroupName) Then
			_AD_Close()
			Return 1
		Endif
	Next

	_AD_Close()
	
	Return 0
	
EndFunc
Edited by kickarse

Share this post


Link to post
Share on other sites

Posted

@Water,

I'll do my best to check things out and test..I have access to an AD environment. If there is anything specific you want tested please let me know otherwise I'll just go through as best I can. Regardless though I want to say thanks for heading up this UDF project.... I used adfunctions.au3 pretty recently to make an easy add/remove groups interface for myself.

Share this post


Link to post
Share on other sites

Posted (edited)

Working great Water! I'm currently using it in production.

I've adapted the example to my environment, it will check for FQDN group if you want but you can change it to general

Hi kickarse,

I think the function you have written (test if a user is a member of a specific group) is already available as "_AD_IsMemberOf($sAD_Group, $sAD_User)"

Edited by water

Share this post


Link to post
Share on other sites

Posted

water,

Thank you very much for working on this. I'm going to have to revise/revisit most of my scripts because of what you're doing, but it'll be well worth it. I'm very thankful for Johnny having made the original as well! This is probably my most-used UDF.

Share this post


Link to post
Share on other sites

Posted

Glad to hear that it's of use for someone ;)

Share this post


Link to post
Share on other sites

Posted

Hi,

First off all, great job and very useful UDF! ;)

For those who are interested on making connection to a domain controller from a pc that is not registered into any domain, i had to change one line

Local $oAD_RootDSE = ObjGet("LDAP://RootDSE")

into

Local $oAD_RootDSE = ObjGet("LDAP://" & $sAD_HostServerParam & "/RootDSE")

and i was able to connect and query the domain controller. (of course you have to provide all necessary parameters to _ad_open())

Without this change you get a COM error.

Bye,

Tim

Share this post


Link to post
Share on other sites

Posted (edited)

I've been using the other adfuctions.au3 and I have to admit that there should have been examples because some of the functions were a little hard to get working.

I had trouble with several that I ended up just finding vbscripts and converting them to autoit. Example I could never get the list domains controllers to work with the one in that UDF, but I found a vbscript that did the same thing and converted it to autoit. I have also since made several other custom AD functions not included in the adfuntions. I would love to see this as an official UDF so that it shows up in Scite and in the help file with usage examples.

Thanks for taking this one as it has been needed for a long time.

Edited by EndFunc

Share this post


Link to post
Share on other sites

Posted

@EndFunc

If there are any functions you want to see in the UDF which are not yet implemented in adfunctions.au3 or AD.au3 please just drop me a note and I will do my very best.

Share this post


Link to post
Share on other sites

Posted (edited)

@EndFunc

If there are any functions you want to see in the UDF which are not yet implemented in adfunctions.au3 or AD.au3 please just drop me a note and I will do my very best.

Well something that would be a awesome function is searchable usernames. Just like the find in ADUC. I can pull up info based on a username but if it isn't exact then you get the error. What would be nice is that if finds names that match or are close and give you a choice. I've been trying to look at that but so far no go.

This guy's site has some very good vbscripts for many things. I've used a few of them in AutoIt. Some were difficult to convert because of not knowning the AutoIt equivalent. Anyway check out this site. Lots of good stuff for functions. That's just for seaching stuff, he has much more code on his site for other things.

http://www.rlmueller.net/freecode6.htm

Edited by EndFunc

Share this post


Link to post
Share on other sites

Posted (edited)

Known bugs:

  • _AD_Open: Still does not work when you connect from a PC that is no domain member. Is solved in the next version
  • _AD_ListRoleOwners: Gives "Object referenced outside a "With" statement." in some environments
  • _AD_ListSites: Gives a COM error in some environments
  • _AD_MoveObject: Wrong syntax. Will be changed in next version
  • _AD_EnablePasswordChange and _AD_DisablePasswordChange: Do not work at all. We investigate the situation - I think we will have to rewrite the code

These original functions in adfunctions.au3 work fine for me, so why not use it as it is, just updating the vars?

_ADEnablePasswordChange and _ADDisablePasswordChange

Edited by EndFunc

Share this post


Link to post
Share on other sites

Posted (edited)

Hi EndFunc,

thanks for your reply!

  • All readonly functions work fine in my environment (have only readonly access to an AD). The "known bugs" section lists some errors another user gets when he uses AD.au3 from a PC which is not a member of a domain.
  • I will have a look at the suggested site. Are there any functions you would like to see in AD.au3?
  • To search for a user name (full or partial) you can use something like: _AD_GetObjectsInOU($asUser, $sOU, "(&(objectCategory=user)(name="*water*))", 2, "department,cn,distinguishedName,sAMAccountName")

    This will return department, full name, FQDN and sAMAccountname for all users in the specified OU that have "water" somewhere in the field "name".

  • _ADEnablePasswordChange and _ADDisablePasswordChange: As I understand the ACEs have to be sorted (according to KB269159) to make sure they work in all situations. The following scripts give an example. Do they work for you?

    http://www.wisesoft.co.uk/scripts/vbscri...disable_user_cannot_change_password.aspx

    http://www.rlmueller.net/Cannot%20Change%20PW.htm

I hope I will soon release a new version. Edited by water

Share this post


Link to post
Share on other sites

Posted (edited)

Hi EndFunc,

I did check out this site (http://www.rlmueller.net/freecode6.htm). Here are my findings:

  • Search for Common Name: Use _AD_GetObjectsInOU
  • Duplicate Display Names: _AD_GetObjectsInOU with sort parameter "displayname" and then check the resulting array
  • Enumerate DC's: I've modified _AD_ListDomainControllers and incorporated the code from this script
  • Enumerate Servers: Use _AD_GetObjectsInOU
  • Document Forest: Use multiple calls to _AD_GetObjectsInOU
  • Create User List: Use _AD_GetObjectsInOU
  • Move Old Computers: _AD_GetPasswordInfo, _AD_DisableObject and _AD_MoveObject
  • Computer Roles: Uses WMI which is outside the scope of the AD UDF
  • Inventory Computers: Use _AD_GetObjectsInOU and the Excel UDF
  • Document Organization: Not yet implemented in the AD UDF. Will be implemented if enough users have a need for it
  • Unique Computer SIDs: Uses WINNT:// which is outside the scope of the AD UDF
  • Local Admin Passwords: Uses WINNT:// which is outside the scope of the AD UDF
  • Generic ADO Searches: Use _AD_GetObjectsInOU
If there are any functions you would like to see in the AD UDF please drop me a note. Edited by water

Share this post


Link to post
Share on other sites

Posted

First off, great work. Your AD functions are fantastic.

I have a bug/issue to report:

I noticed when I installed version 3.3.4.0 of AutoIt the _AD_IsMemberOf() function no longer works (i was using ad.au3 v0.33). It simply returns a -1. I rolled back to 3.3.0.0 and everything works fine. However, other functions such as _AD_GetUserGroups work with the new version. I also tried the original adfunctions.au3 file, and it also returns -1.

Share this post


Link to post
Share on other sites

Posted

Hi,

I think we got hit by bug #1068: Binary to Int. This was fixed in 3.3.2.0

I was always wondering why the function returned a negative value because IsMember only returns 0x0 or 0x1.

I changed the code to return an absolute value so the function returns a valid result for every AutoIt version.

Share this post


Link to post
Share on other sites

Posted

Nice job, at the moment I don't have use for it, but I think I will in near future. If I will have use for it, I will gladly help with test and development.

Share this post


Link to post
Share on other sites

Posted (edited)

The Active Directory UDF is still under heavy development and testing.

When all functions are implemented and everything is well tested then version 1.0 will be released.

Until then every new release (e.g. 0.40) might contain script breaking changes.

What do you think about script breaking changes? Do you already have scripts that heavily rely on the UDF?

Please post your opinions.

Edited by water

Share this post


Link to post
Share on other sites

Posted

Hi,

I try to add a user in an AD group.

When I use the default script sample, I get an error.

; *****************************************************************************
; Example 1
; Add a user to a specified group.
; *****************************************************************************
#include <AD.au3>
#include <ButtonConstants.au3>
#include <GUIConstantsEx.au3>
#include <WindowsConstants.au3>

; Open Connection to the Active Directory
_AD_Open()

$iReply = MsgBox(308, "Active Directory Functions - Example 1", "This script adds a user to a group." & @CRLF & @CRLF & _
        "Are you sure you want to change the Active Directory?")
If $iReply <> 6 Then Exit

; Enter user account and group
#Region ### START Koda GUI section ### Form=
$Form1 = GUICreate("Active Directory Functions - Example 1", 514, 124)
GUICtrlCreateLabel("Enter the user account (samAccountName):", 8, 10, 231, 17)
GUICtrlCreateLabel("Enter the group name (without leading CN=):", 8, 42, 231, 17)
$lUser = GUICtrlCreateInput(@UserName, 241, 8, 259, 21)
$IGroup = GUICtrlCreateInput("", 241, 40, 259, 21)
$BOK = GUICtrlCreateButton("Assign user to group", 8, 72, 121, 33)
$BCancel = GUICtrlCreateButton("Cancel", 428, 72, 73, 33, BitOR($GUI_SS_DEFAULT_BUTTON, $BS_DEFPUSHBUTTON))
GUISetState(@SW_SHOW)
#EndRegion ### END Koda GUI section ###

While 1
    $nMsg = GUIGetMsg()
    Switch $nMsg
        Case $GUI_EVENT_CLOSE, $BCancel
            Exit
        Case $BOK
            $sUser = _AD_SamAccountNameToFQDN(GUICtrlRead($lUser))
            $sGroup = _AD_SamAccountNameToFQDN(GUICtrlRead($IGroup))
            ExitLoop
    EndSwitch
WEnd

; Add user to group
$iValue = _AD_AddUserToGroup($sUser, $sGroup)
If $iValue = 1 Then
    MsgBox(64, "Active Directory Functions - Example 1", "User '" & $sUser & "' successfully assigned to group '" & $sGroup & "'")
ElseIf @error = 1 Then
    MsgBox(64, "Active Directory Functions - Example 1", "Group '" & $sGroup & "' does not exist")
ElseIf @error = 2 Then
    MsgBox(64, "Active Directory Functions - Example 1", "User '" & $sUser & "' does not exist")
ElseIf @error = 3 Then
    MsgBox(64, "Active Directory Functions - Example 1", "User '" & $sUser & "' is already a member of group '" & $sGroup & "'")
Else
    MsgBox(64, "Active Directory Functions - Example 1", "Return code '" & @error & "' from Active Directory")
EndIf

; Close Connection to the Active Directory
_AD_Close()

Here are the errors

COM Error Encountered

Scriptline = 403

and

COM Error Encountered

Scriptline = 1718

Thanks,

Share this post


Link to post
Share on other sites

Posted (edited)

Hi TheBib,

could you please give me the COM error codes you receive? This makes traking the error much easier.

And could you please give an example of the data you enter in the GUI?

Line 403 is in the function _IsMemberOf so the user might already be a member of the group.

Thanks

Edited by water

Share this post


Link to post
Share on other sites

Posted (edited)

Hi!

Thank you so far, good work! :-)

I have some problems with _AD_GetObjectAttribute(),

especially when querying a lot of attributes (30+) for quite a lot of users (300+).

Error:

### COM error! Number: 80020009 ScriptLine: 366 Description: Die Tabelle ist nicht vorhanden.

D:\AUTOIT\Include\Water\AD\AD.au3 (369) : ==> Object referenced outside a "With" statement.:

Local $sAD_LDAPEntry = $oAD_RecordSet.fields(0).value

Local $sAD_LDAPEntry = $oAD_RecordSet.fields(0)^ ERROR

When querying less users (but with the same set of attributes) it works without any errors...

Furthermore I would like to see _AD_GetObjectAttribute() to be able to return valid values

for "accountExpires", "lastLogon", "lastLogonTimestamp", "objectGUID" and "objectSID" (any many more :-)...

Therefore I have modified this function to feed my needs:

Func _AD_GetObjectAttribute2($sAD_SamAccountName, $sAD_Attribute)
	If _AD_ObjectExists($sAD_SamAccountName) = 0 Then Return SetError(1, 0, 0)
	Local $sAD_Query = "<LDAP://" & $sAD_HostServer & "/" & $sAD_DNSDomain & ">;(sAMAccountName=" & $sAD_SamAccountName & ");ADsPath;subtree"
	Local $oAD_RecordSet = $oAD_Connection.Execute($sAD_Query) ; Retrieve the FQDN for the object
	Local $sAD_LDAPEntry = $oAD_RecordSet.fields(0).value
	Local $oAD_Object = _AD_ObjGet($sAD_LDAPEntry) ; Retrieve the COM Object for the object
	Local $sAD_Result = $oAD_Object.Get($sAD_Attribute)
	; ----------
	Select
		Case $sAD_Attribute = "accountExpires" Or $sAD_Attribute = "lastLogon" Or $sAD_Attribute = "lastLogonTimestamp"
			Local $iAD_HighPart	= $sAD_Result.HighPart ; Convert IADsLargeInteger parts to 100ns count.
			Local $iAD_LowPart	= $sAD_Result.LowPart ; Convert IADsLargeInteger parts to 100ns count.
			If $iAD_LowPart < 0 Then $iAD_HighPart += 1 ; Compensate for IADsLargeInteger interface error.
			Local	$iAD_Dummy  = $iAD_HighPart * 2 ^ 32
					$iAD_Dummy += $iAD_LowPart
			If $iAD_Dummy = 0 Then
				$sAD_Result = 0 ; User has never logged on.
			Else
				Local $iAD_Floor = Floor($iAD_Dummy / 10000000) ; Convert 100ns count to integer seconds.
				$sAD_Result = _DateAdd("s", $iAD_Floor, "1601/01/01 00:00:00") ; Convert seconds since 12:00am January 01, 1601 to date string (Coordinated Universal Time (UTC)/Zulu Time).
			EndIf
		Case $sAD_Attribute = "objectGUID"
			Local $xAD_Dummy = DllStructCreate("byte[24]")
			DllStructSetData($xAD_Dummy, 1, $sAD_Result)
			$sAD_Result	= _WinAPI_StringFromGUID(DllStructGetPtr($xAD_Dummy))
			$xAD_Dummy	= 0
		Case $sAD_Attribute = "objectSID"
			Local $xAD_Dummy = DllStructCreate("byte[28]")
			DllStructSetData($xAD_Dummy, 1, $sAD_Result)
			$sAD_Result	= _Security__SidToStringSid(DllStructGetPtr($xAD_Dummy))
			$xAD_Dummy	= 0
	EndSelect
	; ----------
	$oAD_Object.PurgePropertyList
	If $iAD_COMError = 3 Then
		$iAD_COMError = 0
		Return SetError(2, 0, 0)
	EndIf
	If IsArray($sAD_Result) Then _ArrayInsert($sAD_Result, 0, UBound($sAD_Result, 1))
	Return $sAD_Result
EndFunc   ;==>_AD_GetObjectAttribute

Any ideas about the COM error?

Greets,

-supersonic.

Edited by supersonic

Share this post


Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!


Register a new account

Sign in

Already have an account? Sign in here.


Sign In Now

  • Recently Browsing   0 members

    No registered users viewing this page.