Jump to content

Active Directory UDF


water
 Share

Recommended Posts

Hi Thomas,

Having a function _AD_GetAccountsExpired with a date + time? option would be very nice feature. An additional plus would be if it could filter $sUser so we could use smith* to select all accounts that start with smith.

Thanks,

Tom

Hi Tom,

at the moment it is not possible to do this in one go. Every AD function has a single purpose.

As _AD_GetAccountsExpired returns an array containing the FQDN you can either split the FQDN and check the CN=xxx part or you can get the name of each user by calling _AD_GetObjectAttribute.

Thomas

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

Hi Tom,

at the moment it is not possible to do this in one go. Every AD function has a single purpose.

As _AD_GetAccountsExpired returns an array containing the FQDN you can either split the FQDN and check the CN=xxx part or you can get the name of each user by calling _AD_GetObjectAttribute.

Thomas

Yes, that is easy enough to do by looping in the array and testing.

Thanks,

Tom

Link to comment
Share on other sites

Having a function _AD_GetAccountsExpired with a date + time? option would be very nice feature.

Hi Tom,

here is the _AD_GetAccountsExpired function with two new parameters. You can define a start and end date/time. All accounts that expire within this "window" are returned.

Note: the 2nd parameter is the end date/time of the window and the 3rd parameter is the start date/time.

; #FUNCTION# ====================================================================================================================
; Name...........: _AD_GetAccountsExpired
; Description ...: Returns an array with FQDNs of expired accounts (user, computer).
; Syntax.........: _AD_GetAccountsExpired([$sAD_Class = "user"[ ,$sAD_DTEExpire = ""[ ,$sAD_DTSExpire = ""]]])
; Parameters ....: $sAD_Class - Optional: Specifies if expired user accounts or computer accounts should be returned (default = "user").
;   "user" - Returns objects of category "user"
;   "computer" - Returns objects of category "computer"
;   $sAD_DTEExpire - YYYY/MM/DD HH:MM:SS (local time) returns all accounts that expire between $sAD_DTSExpire and the specified date/time (default = "" = Now)
;   $sAD_DTSExpire - YYYY/MM/DD HH:MM:SS (local time) returns all accounts that expire between the specified date/time and $sAD_DTEExpire (default = "1601/01/01 00:00:00)
; Return values .: Success - One-based two dimensional array of FQDNs of expired accounts
;   |1 - FQDNs of expired accounts
;   |2 - account expired YYYY/MM/DD HH:NMM:SS UTC
;   |3 - account expired YYYY/MM/DD HH:NMM:SS local time of calling user
;   Failure - "", sets @error to:
;   |1 - No expired accounts found
;   |2 - Specified date/time is invalid
;   |3 - Invalid value for $sAD_Class. Has to be "user" or "computer"
; Author ........: Thomas Rupp
; Modified.......:
; Remarks .......:
; Related .......: _AD_IsAccountExpired, _AD_SetAccountExpire
; Link ..........:
; Example .......: Yes
; ===============================================================================================================================
Func _AD_GetAccountsExpired($sAD_Class = "user",$sAD_DTEExpire = "", $sAD_DTSExpire = "")

    If $sAD_Class <> "user" And $sAD_Class <> "computer" Then Return SetError(3,0,0)
    ; process end date/time
    If $sAD_DTEExpire = "" Then
        $sAD_DTEExpire = _Date_Time_GetSystemTime() ; Get current date/time (UTC)
        $sAD_DTEExpire = _Date_Time_SystemTimeToDateTimeStr($sAD_DTEExpire, 1) ; convert to format yyyy/mm/dd hh:mm:ss
    ElseIf Not _DateIsValid($sAD_DTEExpire) Then
        Return SetError(2,0,0)
    Else
        $sAD_DTEExpire = _Date_Time_EncodeSystemTime(StringMid($sAD_DTEExpire,6,2),StringMid($sAD_DTEExpire,9,2),StringLeft($sAD_DTEExpire,4), _ ; encode input
            StringMid($sAD_DTEExpire,12,2),StringMid($sAD_DTEExpire,15,2),StringMid($sAD_DTEExpire,18,2))
        Local $sAD_DTEExpireUTC = _Date_Time_TzSpecificLocalTimeToSystemTime(DllStructGetPtr($sAD_DTEExpire)) ; convert local time to UTC
        $sAD_DTEExpire = _Date_Time_SystemTimeToDateTimeStr($sAD_DTEExpireUTC, 1) ; convert to format yyyy/mm/dd hh:mm:ss
    EndIf
    ; process start date/time
    If $sAD_DTSExpire = "" Then $sAD_DTSExpire = "1600/01/01 00:00:00"
    If Not _DateIsValid($sAD_DTSExpire) Then
        Return SetError(2,0,0)
    Else
        $sAD_DTSExpire = _Date_Time_EncodeSystemTime(StringMid($sAD_DTSExpire,6,2),StringMid($sAD_DTSExpire,9,2),StringLeft($sAD_DTSExpire,4), _ ; encode input
            StringMid($sAD_DTSExpire,12,2),StringMid($sAD_DTSExpire,15,2),StringMid($sAD_DTSExpire,18,2))
        Local $sAD_DTSExpireUTC = _Date_Time_TzSpecificLocalTimeToSystemTime(DllStructGetPtr($sAD_DTSExpire)) ; convert local time to UTC
        $sAD_DTSExpire = _Date_Time_SystemTimeToDateTimeStr($sAD_DTSExpireUTC, 1) ; convert to format yyyy/mm/dd hh:mm:ss
    EndIf
    Local $iAD_DTEExpire = _DateDiff("s", "1601/01/01 00:00:00", $sAD_DTEExpire) * 10000000 ; convert end date/time to Integer8
    Local $iAD_DTSExpire = _DateDiff("s", "1601/01/01 00:00:00", $sAD_DTSExpire) * 10000000 ; convert start date/time to Integer8
    Local $iAD_Temp, $sAD_Temp
    Local $sAD_DTStruct = DllStructCreate("dword low;dword high")
    ; -1 to remove rounding errors
    Local $sAD_Query = "<LDAP://" & $sAD_HostServer & "/" & $sAD_DNSDomain & ">;(&(objectCategory=person)(objectClass=" & $sAD_Class & ")" & _
        "(!accountExpires=0)(accountExpires<=" & Int($iAD_DTEExpire)-1 & ")(accountExpires>=" & Int($iAD_DTSExpire)-1 &"));distinguishedName,accountExpires;subtree"
    Local $oAD_RecordSet = $oAD_Connection.Execute($sAD_Query)
    If Not IsObj($oAD_RecordSet) Or $oAD_RecordSet.RecordCount = 0 Then Return SetError(1, 0, "")
    Local $aAD_FQDN[$oAD_RecordSet.RecordCount + 1][3]
    $aAD_FQDN[0][0] = $oAD_RecordSet.RecordCount
    Local $iAD_Count = 1
    While Not $oAD_RecordSet.EOF
        $aAD_FQDN[$iAD_Count][0] = $oAD_RecordSet.Fields(0).Value ; distinguishedName
        $iAD_Temp = $oAD_RecordSet.Fields(1).Value ; accountExpires
        DllStructSetData($sAD_DTStruct, "Low", $iAD_Temp.LowPart)
        DllStructSetData($sAD_DTStruct, "High", $iAD_Temp.HighPart)
        $sAD_Temp = _Date_Time_FileTimeToSystemTime(DllStructGetPtr($sAD_DTStruct))
        $aAD_FQDN[$iAD_Count][1] = _Date_Time_SystemTimeToDateTimeStr($sAD_Temp, 1) ; accountExpires as UTC
        $sAD_Temp = _Date_Time_SystemTimeToTzSpecificLocalTime(DllStructGetPtr($sAD_Temp))
        $aAD_FQDN[$iAD_Count][2] = _Date_Time_SystemTimeToDateTimeStr($sAD_Temp, 1) ; accountExpires as local time
        $iAD_Count += 1
        $oAD_RecordSet.MoveNext
    WEnd
    $aAD_FQDN[0][0] = UBound($aAD_FQDN) - 1
    Return $aAD_FQDN

EndFunc ;==>_AD_GetAccountsExpired

What do you think?

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

I missed to attach the example script for _AD_GetAccountsExpired:

#AutoIt3Wrapper_AU3Check_Parameters= -d -w 1 -w 2 -w 3 -w 4 -w 5 -w 6
#AutoIt3Wrapper_AU3Check_Stop_OnWarning=Y
#include <AD.au3>

; Open Connection to the Active Directory
_AD_Open()

Global $aDisabled[1]
; *****************************************************************************
; Example 1
; Get a list of expired user accounts
; *****************************************************************************
$aDisabled = _AD_GetAccountsExpired()
If @error > 0 Then
    MsgBox(64, "Active Directory Functions - Example 1", "No expired user accounts could be found")
Else
    _ArrayDisplay($aDisabled, "Active Directory Functions - Example 1 - Expired User Accounts")
EndIf

; *****************************************************************************
; Example 2
; Get a list of user accounts that expire end of this year
; *****************************************************************************
$aDisabled = _AD_GetAccountsExpired("user", @YEAR & "/12/31")
If @error = 0 Then
    _ArrayDisplay($aDisabled, "Active Directory Functions - Example 2 - Expired User Accounts")
ElseIf @error = 1 Then
    MsgBox(64, "Active Directory Functions - Example 2", "No expired user accounts could be found")
Else
    MsgBox(64, "Active Directory Functions - Example 2", "Invalid parameters provided")
EndIf

; *****************************************************************************
; Example 3
; Get a list of user accounts that expire between january and october this year
; *****************************************************************************
$aDisabled = _AD_GetAccountsExpired("user", @YEAR & "/10/31", @YEAR & "/01/01")
If @error = 0 Then
    _ArrayDisplay($aDisabled, "Active Directory Functions - Example 3 - Expired User Accounts")
ElseIf @error = 1 Then
    MsgBox(64, "Active Directory Functions - Example 3", "No expired user accounts could be found")
Else
    MsgBox(64, "Active Directory Functions - Example 3", "Invalid parameters provided")
EndIf

; *****************************************************************************
; Example 4
; Get a list of expired computer accounts
; *****************************************************************************
$aDisabled = _AD_GetAccountsExpired("computer")
If @error > 0 Then
    MsgBox(64, "Active Directory Functions - Example 4", "No expired computer accounts could be found")
Else
    _ArrayDisplay($aDisabled, "Active Directory Functions - Example 4 - Expired Computer Accounts")
EndIf

; Close Connection to the Active Directory
_AD_Close()

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

Glad to hear.

Will be part of the upcoming version 0.40.

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

Glad to hear.

Will be part of the upcoming version 0.40.

This seems like the most logical place to give feedback / comments / suggestions / questions about the AD UDF you've written (awesome work, by the way!). This is, by the way, basically directed at water - though I encourage anyones comments/thoughts.

I'm working on a script for our employees home machines (e.g. not domain machines), when on the VPN, to check their credentials and then map network drives. I have it working, but had to disable the checks I was using to test if their password is expired or if their account was disabled. It appears that the problem is because _AD_IsPasswordExpired and _AD_IsObjectLocked eventually call _AD_GetPasswordInfo() which doesn't make use of $oAD_Connection at all. In doing some searches, it looks like there are probably some other functions that do direct .Get()'s on hand-rolled LDAP queries instead of going through the existing connection.

My question is twofold - one, is there any reason (beyond historic / that's how it was written) it's done this way, and two should I endeavor to rewrite _AD_GetPasswordInfo for you, or would you rather make the changes yourself? As it stands I can pull out the bits I need with _AD_GetObjectAttribute calls for what little I need, but it probably won't be much more effort to change it over if you'd rather.

Thanks,

-Martin

Link to comment
Share on other sites

This seems like the most logical place to give feedback / comments / suggestions / questions about the AD UDF you've written (awesome work, by the way!). This is, by the way, basically directed at water - though I encourage anyones comments/thoughts.

I'm working on a script for our employees home machines (e.g. not domain machines), when on the VPN, to check their credentials and then map network drives. I have it working, but had to disable the checks I was using to test if their password is expired or if their account was disabled. It appears that the problem is because _AD_IsPasswordExpired and _AD_IsObjectLocked eventually call _AD_GetPasswordInfo() which doesn't make use of $oAD_Connection at all. In doing some searches, it looks like there are probably some other functions that do direct .Get()'s on hand-rolled LDAP queries instead of going through the existing connection.

My question is twofold - one, is there any reason (beyond historic / that's how it was written) it's done this way, and two should I endeavor to rewrite _AD_GetPasswordInfo for you, or would you rather make the changes yourself? As it stands I can pull out the bits I need with _AD_GetObjectAttribute calls for what little I need, but it probably won't be much more effort to change it over if you'd rather.

Thanks,

-Martin

Hi Martin,

there are two reasons why this is done the way it is:

  • historical: I started with just converting the adfunctions to a UDF adding documentation, examples and a help file. Later new functions were added.
  • technical: _AD_GetPasswordInfo directly connects to the PDC and therefore doesn't use $oAD_Connection. The PDC handles the login requests and "knows" about the locked out or disabled accounts, expired passwords etc. without having to wait for synchronization to occur.
My knowledge of AD is quite limited (I'm learning as I'm working on this UDF) and I only have readonly access to our AD.

If you have enhancements for the UDF I will be glad to incorporate them!

Thomas

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

I enhanced the _AD_Open function to get more information if the connection to the AD could not be established.

When you provide a userid/password _AD_Open tries to test the credentials and returns an array with extended information in case of an error (for more details please see the heading of the _AD_Open function, return value: x).

Unfortunately this only works with Windows 7 (and later). For Windows XP and lower you only get @error = 8.

If you want to test it with Windows Vista (it should work but I can't test it) then you have to change the line containing

If @OSVersion = "Win_7" Then
to
If @OSVersion = "Win_VISTA" Then

Anyone willing to test and post the results?

Edit: I combined everything in the following attachment. Just run the following code:

#include <AD.au3>
$R = _AD_OpenEx("domain\userid","password")
If @error <> 0 Then
    If @error <= 8 Then
        MsgBox(0,"AD Test Script","Error Code: " & @error & ", Extended: " & @extended & " returned by _AD_Open")
    Else
        If IsArray($R) Then _ArrayDisplay($R)
    EndIf
EndIf
_AD_Close()
Exit

; #FUNCTION# ====================================================================================================================
; Name...........: _AD_Open
; Description ...: Opens a connection to the Active Directory.
; Syntax.........: _AD_Open([$sAD_UserIdParam = "", $sAD_PasswordParam = ""[, $sAD_DNSDomainParam = "", $sAD_HostServerParam = "", $sAD_ConfigurationParam = ""]])
; Parameters ....: $sAD_UserIdParam - Optional: UserId to authenticate with. This has to be a valid domain user
;   $sAD_PasswordParam - Optional: Password to authenticate with
;   $sAD_DNSDomainParam - Optional: Active Directory domain name if you want to connect to a different domain
;   $sAD_HostServerParam - Optional: Name of the connected Domain Controller if you want to connect to a different domain
;   $sAD_ConfigurationParam - Optional: Configuration naming context if you want to connect to a different domain
; Return values .: Success - 1
;   Failure - 0 or array, sets @error to:
;   |1 - Installation of the custom error handler failed. @extended set to error code of ObjEvent
;   |2 - Creation of the COM object to the AD failed. @extended set to error code of ObjCreate
;   |3 - Open the connection to AD failed. @extended set to error code received by the COM error handler.
;   |   Happens when the User doesn't have query / modify access
;   |4 - Creation of the RootDSE object failed. @extended set to error code received by the COM error handler.
;   |   Happens when the connection to the domain isn't successful. @extended is set to -2147023541 (0x8007054B)
;   |5 - Creation of the DS object failed. @extended set to error code received by the COM error handler
;   |6 - Parameter $sAD_HostServerParam and $sAD_ConfigurationParam have to be specified when $sAD_DNSDomainParam is specified
;   |7 - Parameter $sAD_PasswordParam has to be specified when $sAD_UserIdParam is specified
;   |8 - OpenDSObject method failed. @extended set to error code received by the COM error handler.
;   |   On Windows XP or lower this shows that $sAD_UserIdParam and/or $sAD_PasswordParam are invalid
;   |x - For Windows 7 systems: Win32 error code (decimal). Returns an array with the following information:
;   |1 - ADSI error code (decimal)
;   |2 - Unicode string that describes the ADSI error
;   |3 - name of the provider that raised the error
;   |4 - Win32 error code extracted from element[2]
;   |5 - description of the Win32 error code as returned by _WinAPI_FormatMessage
; Author ........: Jonathan Clelland
; Modified.......: Thomas Rupp
; Remarks .......: To close the connection to the Active Directory, use the _AD_Close function.
;+
;   _AD_Open will use the alternative credentials $sAD_UserIdParam and $sAD_PasswordParam if passed as parameters.
;   $sAD_UserIdParam has to be in one of the following formats (assume the samAccountName = DJ)
;   * Windows Login Name e.g. "DJ"
;   * NetBIOS Login Name e.g. "<DOMAIN>\DJ"
;   * User Principal Name e.g. "DJ@domain.com"
;   All other name formats have not been successfully tested (see section "Link").
;+
;   If you want to connect to a different domain (not the domain your computer is a member of) or your computer is no domain member
;   then please provide $sAD_DNSDomainParam, $sAD_HostServerParam and $sAD_ConfigurationParam as FQDN as well as $sAD_UserIdParam and $sAD_PasswordParam.
;   Example:
;   $sAD_DNSDomainParam = "DC=subdomain,DC=example,DC=com"
;   $sAD_HostServerParam = "servername.subdomain.example.com"
;   $sAD_ConfigurationParam = "CN=Configuration,DC=subdomain,DC=example,DC=com"
;+
;   The COM error handler will be set up if there isn't an error handler already active.
;   But be aware that some functions will not work correctly any more because they handle error codes ($iAD_COMError) that are set by the error handler.
;+
;   If you specify $sAD_UserIdParam and the OS is Windows 7 then _AD_Open will try to verify the userid/password (see return values).
; Related .......: _AD_Close
; Link ..........: http://msdn.microsoft.com/en-us/library/cc223499(PROT.10).aspx (Simple Authentication), http://msdn.microsoft.com/en-us/library/aa746471(VS.85).aspx (ADO)
; Example .......: Yes
; ===============================================================================================================================
Func _AD_OpenEx($sAD_UserIdParam = "", $sAD_PasswordParam = "", $sAD_DNSDomainParam = "", $sAD_HostServerParam = "", $sAD_ConfigurationParam = "")

    ; A COM error handler will only be set up if there isn't an error handler already active.
    If ObjEvent("AutoIt.Error") = "" Then
        $oAD_MyError = ObjEvent("AutoIt.Error", "_AD_ErrorHandler") ; Install a custom error handler
        If @error <> 0 Then Return SetError(1, @error, 0)
    EndIf
    $iAD_COMError = 0
    $oAD_Connection = ObjCreate("ADODB.Connection") ; Create COM object to AD
    If Not IsObj($oAD_Connection) Or @error <> 0 Then Return SetError(2, @error, 0)
    ; ConnectionString Property (ADO): http://msdn.microsoft.com/en-us/library/ms675810.aspx
    $oAD_Connection.ConnectionString = "Provider=ADsDSOObject" ; Set Service providertype
    If $sAD_UserIdParam <> "" Then
        If $sAD_PasswordParam = "" Then Return SetError(7, 0, 0)
        $oAD_Connection.Properties("User ID") = $sAD_UserIdParam ; Authenticate User
        $oAD_Connection.Properties("Password") = $sAD_PasswordParam ; Authenticate User
        ; If userid is the Windows login name then set the flag for secure authentifiction
        If StringInStr($sAD_UserIdParam, "\") = 0 And StringInStr($sAD_UserIdParam, "@") = 0 Then
            $oAD_Connection.Properties("ADSI Flag") = $ADS_SECURE_AUTH
        Else
            $oAD_Connection.Properties("ADSI Flag") = 0x0
        EndIf
        $sAD_UserId = $sAD_UserIdParam
        $sAD_Password = $sAD_PasswordParam
    EndIf
    ; ADO Open Method: http://msdn.microsoft.com/en-us/library/ms676505.aspx
    $oAD_Connection.Open()
    If @error <> 0 Then Return SetError(3, @error, 0)
    ; Connect to another Domain if the Domain parameter is provided
    If $sAD_DNSDomainParam <> "" Then
        If $sAD_HostServerParam = "" Or $sAD_ConfigurationParam = "" Then Return SetError(6, 0, 0)
        $oAD_RootDSE = ObjGet("LDAP://" & $sAD_HostServerParam & "/RootDSE")
        If Not IsObj($oAD_RootDSE) Or @error <> 0 Then Return SetError(4, @error, 0)
        $sAD_DNSDomain = $sAD_DNSDomainParam
        $sAD_HostServer = $sAD_HostServerParam
        $sAD_Configuration = $sAD_ConfigurationParam
    Else
        $oAD_RootDSE = ObjGet("LDAP://RootDSE")
        If Not IsObj($oAD_RootDSE) Or @error <> 0 Then Return SetError(4, @error, 0)
        $sAD_DNSDomain = $oAD_RootDSE.Get("defaultNamingContext") ; Retrieve the current AD domain name
        $sAD_HostServer = $oAD_RootDSE.Get("dnsHostName") ; Retrieve the name of the connected DC
        $sAD_Configuration = $oAD_RootDSE.Get("ConfigurationNamingContext") ; Retrieve the Configuration naming context
    EndIf
    $oAD_OpenDS = ObjGet("LDAP:")
    If Not IsObj($oAD_OpenDS) Or @error <> 0 Then Return SetError(5, @error, 0)
    ; Check userid/password if provided
    If $sAD_UserIdParam <> "" Then
    Local $oAD_Temp = $oAD_OpenDS.OpenDSObject("LDAP://" & $sAD_HostServer, $sAD_UserId, $sAD_Password, $ADS_SERVER_BIND)
    If Not IsObj($oAD_Temp) Or @error <> 0 Then ; login error occurred - get extended information
            If @OSVersion = "Win_7" Then        ; Delivers detailed error information for Windows 7 and later, sets @error for all other OS.
                Local $aAD_Errors = _AD_GetLastErrorEx()
                If $aAD_Errors[4] <> 0 Then
                    If $iAD_Debug = 1 Then ConsoleWrite("_AD_Open: " & _ArrayToString($aAD_Errors, @CRLF, 1) & @CRLF)
                    If $iAD_Debug = 2 Then MsgBox(64, "Active Directory Functions - Debug Info - _AD_Open", _ArrayToString($aAD_Errors, @CRLF, 1))
                    If $iAD_Debug = 3 Then FileWrite("AD_Debug.txt", @YEAR & "." & @MON & "." & @MDAY & " " & @HOUR & ":" & @MIN & ":" & @SEC & " " & @CRLF & _
                        "-------------------" & @CRLF & "_AD_Open: " & _ArrayToString($aAD_Errors, @CRLF, 1) & @CRLF & _
                        "========================================================" & @CRLF)
                    Return Seterror(Dec($aAD_Errors[4]), 0, $aAD_Errors)
                Endif
            Else
                Return SetError(8, @error, 0)
            EndIf
    Endif
    Endif
    Return 1

EndFunc ;==>_AD_Open

; #INTERNAL_USE_ONLY#============================================================================================================
; Name...........: _AD_GetLastError
; Description ...: Uses the ADsGetLastError function to retrieve the calling thread's last-error code value.
; Syntax.........: _AD_GetLastError()
; Parameters ....: None
; Return values .: Success - An array containing the following values:
; |1 - ADSI error code (decimal)
; |2 - Unicode string that describes the error
; |3 - name of the provider that raised the error
; Failure - 0, sets @error to the return values of DLLCall
; Return values .:
; Author ........: Thomas Rupp
; Modified.......:
; Remarks .......: This function is used internally
; Related .......:
; Link ..........: http://msdn.microsoft.com/en-us/library/cc231199(PROT.10).aspx (Win32 Error Codes), http://forums.sun.com/thread.jspa?threadID=703398
; Example .......:
; ===============================================================================================================================
Func _AD_GetLastErrorEx()

    Local $aAD_LastError[6] = [5]
    Local $EC = DllStructCreate("DWord")
    Local $ED = DllStructCreate("wchar[256]")
    Local $PN = DllStructCreate("wchar[256]")
    DllCall("Activeds.dll", "DWORD", "ADsGetLastError", "ptr", DllStructGetPtr($EC), "ptr", DllStructGetPtr($ED), "DWORD", 256, "ptr", DllStructGetPtr($PN), "DWORD", 256)
    If @error <> 0 Then Return SetError(@error, @extended, "")
    $aAD_LastError[1] = DllStructGetData($EC, 1) ; error code (decimal)
    $aAD_LastError[2] = DllStructGetData($ED, 1) ; Unicode string that describes the error
    $aAD_LastError[3] = DllStructGetData($PN, 1) ; name of the provider that raised the error
    Local $sAD_Error = StringTrimLeft($aAD_LastError[2], StringInStr($aAD_LastError[2], "AcceptSecurityContext", 2))
    $sAD_Error = StringTrimLeft($sAD_Error, StringInStr($sAD_Error, " data", 2) + 5)
    $aAD_LastError[4] = StringTrimRight($sAD_Error, StringLen($sAD_Error) - StringInStr($sAD_Error, ", vece", 2) + 1)
    _WinAPI_FormatMessage($__WINAPICONSTANT_FORMAT_MESSAGE_FROM_SYSTEM, 0, Dec($aAD_LastError[4]), 0, $aAD_LastError[5], 4096, 0)
    Return $aAD_LastError

EndFunc ;==>_AD_GetLastError

Example of error array (on a german system - row 5 means: user not found):

Edited by water

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

Hi supersonic,

  • what OS do you run? The new feature only works for Windows 7. On Windows XP you should get @error = 8 (for this to work please download the changed code again).

    It might work for Vista but then you have to change the script according to my original posting

  • If you run Windows 7 how did you specify the userid (Domain\userid, userid or userid@microsoft.com)?
Edited by water

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

Hi water,

I run the example script as you provided:

$R = _AD_Open("DE01\Administrator","password")
If @error <> 0 Then
    If @error <= 7 Then
        MsgBox(0,"AD Test Script","Error Code: " & @error & " returned by _AD_Open")
    Else
        If IsArray($R) Then _ArrayDisplay($R)
    EndIf
EndIf
_AD_Close()
Exit
Edited by supersonic
Link to comment
Share on other sites

Hi supersonic,

I combined everything in one script. Coulde you please download the code again from this post?

So if you are running Windows XP you should at least get @error=8 when an invalid userid or password is provided.

Thanks

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

Hi supersonic,

BTW: Please change '_AD_GetLastError' in line 117 to '_AD_GetLastErrorEx'.

Done.

What can I do?

Could you please insert
#AutoIt3Wrapper_Run_Debug_Mode=y
before
$R = _AD_OpenEx("domain\userid","password")
and post the console output?

Thanks for testing!

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

Of course! ;)

0001: 0-0: #include ".\..\AUTOIT\Include\Water\AD\AD.au3"
0002: 0-0: #AutoIt3Wrapper_Run_Debug_Mode=y
0003: 0-0: $R = _AD_OpenEx("DOMAIN\Administrator", "password")
0071: 0-0:     If ObjEvent("AutoIt.Error") = "" Then
0072: 0-0:         $oAD_MyError = ObjEvent("AutoIt.Error", "_AD_ErrorHandler") ; Install a custom error handler
0073: 0-0:         If @error <> 0 Then Return SetError(1, @error, 0)
0074: 0-0:     EndIf
0075: 0-0:     $iAD_COMError = 0
0076: 0-0:     $oAD_Connection = ObjCreate("ADODB.Connection") ; Create COM object to AD
0077: 0-0:     If Not IsObj($oAD_Connection) Or @error <> 0 Then Return SetError(2, @error, 0)
0079: 0-0:     $oAD_Connection.ConnectionString = "Provider=ADsDSOObject" ; Set Service providertype
0080: 0-0:     If $sAD_UserIdParam <> "" Then
0081: 0-0:         If $sAD_PasswordParam = "" Then Return SetError(7, 0, 0)
0082: 0-0:         $oAD_Connection.Properties("User ID") = $sAD_UserIdParam ; Authenticate User
0083: 0-0:         $oAD_Connection.Properties("Password") = $sAD_PasswordParam ; Authenticate User
0085: 0-0:         If StringInStr($sAD_UserIdParam, "\") = 0 And StringInStr($sAD_UserIdParam, "@") = 0 Then
0088: 0-0:             $oAD_Connection.Properties("ADSI Flag") = 0x0
0089: 0-0:         EndIf
0090: 0-0:         $sAD_UserId = $sAD_UserIdParam
0091: 0-0:         $sAD_Password = $sAD_PasswordParam
0092: 0-0:     EndIf
0094: 0-0:     $oAD_Connection.Open()
0095: 0-0:     If @error <> 0 Then Return SetError(3, @error, 0)
0097: 0-0:     If $sAD_DNSDomainParam <> "" Then
0105: 0-0:         $oAD_RootDSE = ObjGet("LDAP://RootDSE")
0106: 0-0:         If Not IsObj($oAD_RootDSE) Or @error <> 0 Then Return SetError(4, @error, 0)
0107: 0-0:         $sAD_DNSDomain = $oAD_RootDSE.Get("defaultNamingContext") ; Retrieve the current AD domain name
0108: 0-0:         $sAD_HostServer = $oAD_RootDSE.Get("dnsHostName") ; Retrieve the name of the connected DC
0109: 0-0:         $sAD_Configuration = $oAD_RootDSE.Get("ConfigurationNamingContext") ; Retrieve the Configuration naming context
0110: 0-0:     EndIf
0111: 0-0:     $oAD_OpenDS = ObjGet("LDAP:")
0112: 0-0:     If Not IsObj($oAD_OpenDS) Or @error <> 0 Then Return SetError(5, @error, 0)
0114: 0-0:     If $sAD_UserIdParam <> "" Then
0115: 0-0:     Local $oAD_Temp = $oAD_OpenDS.OpenDSObject("LDAP://" & $sAD_HostServer, $sAD_UserId, $sAD_Password, $ADS_SERVER_BIND)
0116: 0-0:     If Not IsObj($oAD_Temp) Or @error <> 0 Then ; login error occurred - get extended information
0131: 0-0:     Endif
0132: 0-0:     Return 1
0004: 0-0: If @error <> 0 Then
0011: 0-0: _AD_Close()
0012: 0-0: Exit
Link to comment
Share on other sites

That helps a lot!

The difference is that line

Local $oAD_Temp = $oAD_OpenDS.OpenDSObject("LDAP://" & $sAD_HostServer, $sAD_UserId, $sAD_Password, $ADS_SERVER_BIND)
seems to return a different result.

Could you please insert

ConsoleWrite(IsObj($oAD_Temp) & "-" & @error & "-" & @extended & @CRLF)
after this line and post the output of the ConsoleWrite?

I get 0-0-0 if I provide an invalid userid/password.

BTW: What version is your Domain Controller? Windows 2003, Windows 2008?

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

Strange, strange...

Now it works!? ;)

But I haven't change anything...

The results are:

0-0-0 (invalid password and/or user, error code 8, extended code 0),

1-0-0 (valid password and user).

We are currently using MS-Windows 2003 R2 as domain controllers.

Edited by supersonic
Link to comment
Share on other sites

Strange, strange...

Now it works!? ;)

But I haven't change anything...

You didn't change anything but by inserting ConsoleWrite the script now checks the @error of ConsoleWrite which is always 0.

But I think I found the bug:

Could you please change the line

If Not IsObj($oAD_Temp) Or @error <> 0 Then
to
If @error <> 0 Or IsObj($oAD_Temp) = 0 Then

BTW: As you get returncode 8 I assume you are running Windows XP?

Edited by water

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

Guest
This topic is now closed to further replies.
 Share

×
×
  • Create New...