Jump to content

Active Directory UDF


water
 Share

Recommended Posts

Changing _AD_Int8ToSec isn't the way to go - I will have to change _AD_IsObjectLocked.

Now _AD_IsObjectLocked returns 1 and sets @error to the number of minutes until the account is unlocked.

If the account has to be unlocked by an admin the function should still return 1 but set @error to -1.

What doy ou think?

That would be nice and far better by design! :)
Link to comment
Share on other sites

I can't test it here but (I hope) this will work. Could you please replace the two functions in the UDF and try again?

If an account is locked and the lockout duration time is set to 0 then function _AD_IsObjectLocked returns 1 and sets @error to -1.

Func _AD_IsObjectLocked($sAD_Object = @UserName)

    If Not _AD_ObjectExists($sAD_Object) Then Return SetError(1, 0, 0)
    Local $sAD_Property = "sAMAccountName"
    If StringMid($sAD_Object, 3, 1) = "=" Then $sAD_Property = "distinguishedName"; FQDN provided
    $oAD_Command.CommandText = "<LDAP://" & $sAD_HostServer & "/" & $sAD_DNSDomain & ">;(" & $sAD_Property & "=" & $sAD_Object & ");ADsPath;subtree"
    Local $oAD_RecordSet = $oAD_Command.Execute ; Retrieve the ADsPath 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 $oAD_LockoutTime = $oAD_Object.LockoutTime
    ; Object is not locked out
    If Not IsObj($oAD_LockoutTime) Then Return
    ; Calculate lockout time (UTC)
    Local $sAD_LockoutTime = _DateAdd("s", Int(_AD_LargeInt2Double($oAD_LockoutTime.LowPart, $oAD_LockoutTime.HighPart) / (10000000)), "1601/01/01 00:00:00")
    ; Object is not locked out
    If $sAD_LockoutTime = "1601/01/01 00:00:00" Then Return
    ; Get password info - Account Lockout Duration
    Local $aAD_Temp = _AD_GetPasswordInfo($sAD_Object)
    ; if lockout duration is 0 (= unlock manually by admin needed) then no calculation is necessary. Set @error to -1 (minutes till the account is unlocked)
    If $aAD_Temp[5] = 0 Then Return SetError(-1, 0, 1)
    ; Calculate when the lockout will be reset
    Local $sAD_ResetLockoutTime = _DateAdd("n", $aAD_Temp[5], $sAD_LockoutTime)
    ; Compare to current date/time (UTC)
    Local $sAD_Now = _Date_Time_GetSystemTime()
    $sAD_Now = _Date_Time_SystemTimeToDateTimeStr($sAD_Now, 1)
    If $sAD_ResetLockoutTime >= $sAD_Now Then Return SetError(_DateDiff("n", $sAD_Now, $sAD_ResetLockoutTime), 0, 1)
    Return

EndFunc   ;==>_AD_IsObjectLocked

Func _AD_GetPasswordInfo($sAD_Object = @UserName)

    If _AD_ObjectExists($sAD_Object) = 0 Then Return SetError(1, 0, "")
    If StringMid($sAD_Object, 3, 1) <> "=" Then $sAD_Object = _AD_SamAccountNameToFQDN($sAD_Object) ; sAMAccountName provided
    Local $iAD_Error = 0
    Local $aAD_PwdInfo[12] = [11]
    Local $oAD_Object = ObjGet("LDAP://" & $sAD_DNSDomain)
    $aAD_PwdInfo[1] = Int(_AD_Int8ToSec($oAD_Object.Get("maxPwdAge"))) / 86400 ; Convert to Days
    $aAD_PwdInfo[2] = _AD_Int8ToSec($oAD_Object.Get("minPwdAge")) / 86400 ; Convert to Days
    $aAD_PwdInfo[3] = $oAD_Object.Get("pwdHistoryLength")
    $aAD_PwdInfo[4] = $oAD_Object.Get("minPwdLength")
    ; Account lockout duration: http://msdn.microsoft.com/en-us/library/ms813429.aspx
    Local $oAD_Temp = $oAD_Object.Get("lockoutDuration")
    If $oAD_Temp.HighPart = 0x7FFFFFFF And $oAD_Temp.LowPart = 0xFFFFFFFF Then 
        $aAD_PwdInfo[5] = 0 ; Account has to be unlocked manually by an admin
    Else
        $aAD_PwdInfo[5] = _AD_Int8ToSec($oAD_Object.Get("lockoutDuration")) / 60 ; Convert to Minutes
    EndIf
    $aAD_PwdInfo[6] = $oAD_Object.Get("lockoutThreshold")
    $aAD_PwdInfo[7] = _AD_Int8ToSec($oAD_Object.Get("lockoutObservationWindow")) / 60 ; Convert to Minutes
    Local $oAD_User = _AD_ObjGet("LDAP://" & $sAD_HostServer & "/" & $sAD_Object)
    Local $sAD_PwdLastChanged = $oAD_User.Get("PwdLastSet")
    Local $iAD_UAC = $oAD_User.userAccountControl
    ; Has user account password been changed before?
    If $sAD_PwdLastChanged.LowPart = 0 And $sAD_PwdLastChanged.HighPart = 0 Then
        $iAD_Error = +3
        $aAD_PwdInfo[8] = "1601/01/01 00:00:00"
        $aAD_PwdInfo[10] = "1601/01/01 00:00:00"
    Else
        ; Is user account password set to expire?
        If BitAND($iAD_UAC, $ADS_UF_DONT_EXPIRE_PASSWD) = $ADS_UF_DONT_EXPIRE_PASSWD Or $aAD_PwdInfo[1] = 0 Then
            If BitAND($iAD_UAC, $ADS_UF_DONT_EXPIRE_PASSWD) = $ADS_UF_DONT_EXPIRE_PASSWD Then $iAD_Error += 2
            If $aAD_PwdInfo[1] = 0 Then $iAD_Error += 4 ; The Maximum Password Age is set to 0 in the domain. Therefore, the password does not expire
        Else
            Local $sAD_Temp = DllStructCreate("dword low;dword high")
            DllStructSetData($sAD_Temp, "Low", $sAD_PwdLastChanged.LowPart)
            DllStructSetData($sAD_Temp, "High", $sAD_PwdLastChanged.HighPart)
            ; Have to convert to SystemTime because _Date_Time_FileTimeToStr has a bug (#1638)
            Local $sAD_Temp2 = _Date_Time_FileTimeToSystemTime(DllStructGetPtr($sAD_Temp))
            $aAD_PwdInfo[10] = _Date_Time_SystemTimeToDateTimeStr($sAD_Temp2, 1)
            $aAD_PwdInfo[11] = _DateAdd("d", $aAD_PwdInfo[1], $aAD_PwdInfo[10])
            ; Convert PwdlastSet and PasswordExpires from UTC to Local Time
            $sAD_Temp2 = _Date_Time_SystemTimeToTzSpecificLocalTime(DllStructGetPtr($sAD_Temp2))
            $aAD_PwdInfo[8] = _Date_Time_SystemTimeToDateTimeStr($sAD_Temp2, 1)
            $sAD_Temp2 = _Date_Time_EncodeSystemTime(StringMid($aAD_PwdInfo[11], 6, 2), StringMid($aAD_PwdInfo[11], 9, 2), StringMid($aAD_PwdInfo[11], 1, 4), StringMid($aAD_PwdInfo[11], 12, 2), StringMid($aAD_PwdInfo[11], 15, 2), StringMid($aAD_PwdInfo[11], 18, 2))
            $sAD_Temp2 = _Date_Time_SystemTimeToTzSpecificLocalTime(DllStructGetPtr($sAD_Temp2))
            $aAD_PwdInfo[9] = _Date_Time_SystemTimeToDateTimeStr($sAD_Temp2, 1)
        EndIf
    EndIf
    Return SetError($iAD_Error, 0, $aAD_PwdInfo)

EndFunc   ;==>_AD_GetPasswordInfo

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

Thanks for the quick code change!

If I change these two lines in _AD_IsObjectLocked it works! (tested with 1 and later 2 locked users)

;    $oAD_Command.CommandText = "<LDAP://" & $sAD_HostServer & "/" & $sAD_DNSDomain & ">;(" & $sAD_Property & "=" & $sAD_Object & ");ADsPath;subtree"
;    Local $oAD_RecordSet = $oAD_Command.Execute ; Retrieve the ADsPath for the object
     Local $sAD_Query = "<LDAP://" & $sAD_HostServer & "/" & $sAD_DNSDomain & ">;(" & $sAD_Property & "=" & $sAD_Object & ");ADsPath;subtree"
     Local $oAD_RecordSet = $oAD_Connection.Execute($sAD_Query) ; Retrieve the ADsPath for the object
Link to comment
Share on other sites

Thanks for the quick code change!

If I change these two lines in _AD_IsObjectLocked it works! (tested with 1 and later 2 locked users)

;    $oAD_Command.CommandText = "<LDAP://" & $sAD_HostServer & "/" & $sAD_DNSDomain & ">;(" & $sAD_Property & "=" & $sAD_Object & ");ADsPath;subtree"
;    Local $oAD_RecordSet = $oAD_Command.Execute ; Retrieve the ADsPath for the object
    Local $sAD_Query = "<LDAP://" & $sAD_HostServer & "/" & $sAD_DNSDomain & ">;(" & $sAD_Property & "=" & $sAD_Object & ");ADsPath;subtree"
    Local $oAD_RecordSet = $oAD_Connection.Execute($sAD_Query) ; Retrieve the ADsPath for the object

That's fine!

Sorry I didn't realize that I changed the function in another place as well.

I think it's time to create the package and release a new version of the UDF.

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

Version 0.43 has been released.

Please test before using in production!

For download please see my signature.

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

:)

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

hey water - thanks for keeping this script up to date with fixes and additions.. it truly is one of the best/most useful UDFs out there in my opinion

i am having some trouble with the COM error you are registering as it is conflicting with the one i am trying to register.

im using some IE.au3 functions (yet another awesome UDF!) and i get console messages that say " Cannot register internal error handler, cannot trap COM errors (Use _IEErrorHandlerRegister() to register a user error handler)" if i DONT use _IEErrorHandlerRegister() but if i do use it, i get a message saying theres already a COM ERror handler already active (which is a message coming from your COM handler)

Link to comment
Share on other sites

Hi gcue,

the AD UDF checks in function _AD_Open() if there is already a COM error handler installed. The AD COM error handler is only installed when no other COM error handler is installed.

The AD COM error handler is uninstalled when _AD_Close() is called.

If you can "serialize" your script then this problem can be solved.

  • Check for an COM error handler
  • If you find one store it in a global variable
  • Remove the COM error handler
  • Call _AD_Open(). The AD COM error handler will be installed
  • Do you AD stuff
  • Call _AD_Close() to remove the AD COM error handler
  • Restore the COM error handler from the global variable
COM error handling can become complicated because AutoIt doesn't allow for multiple error handlers at the same time.

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 don't know.

Unfortunately I don't get the Stores from our environment. And I have no knowledge about the information Exchange stores in the Active Directory.

If you (or anyone else) can point me to a site describing the Exchange information I can extract from Active Directory I will be happy to implement whatever you need.

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

this is a vbs script used for monitor Exchange server --> http://gallery.technet.microsoft.com/scriptcenter/e5dd50bc-5e69-4eb9-b544-221493e12f0d

my goal is to check Exchange Services and DataStores

Do you think is possible to write an udf to do it ?

big thx :)

Link to comment
Share on other sites

Most of the script is using WMI to check the Exchange server.

There's only a small part using the AD to check TLOG Drive Util for every storage group.

This can easily be done with the AD UDF as it is.

The rest has to be converted by you. The example script is visual basic and AutoIt is basic like so this shouldn't be a big deal.

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 am under a big Forest and many DC/Sites are not under my control.

So I needed to point only on those that I am in control, and if I wanted to have a better result of the real "Last Login", I needed all of them. But they are under multiple sites, so I had to modify your _AD_GetLastLoginDate() to accept an Array as $sAD_Site. (Don't know if I should have renamed it $aAD_Sites... ?)

Let me know if there was already something for this or if I should have done it another way.

Anyway, it's yours, you can include it in your code if you like, for the next version. (The Func was taken from your 2011/03/01 version)

Func _AD_GetLastLoginDateEx($sAD_User = @UserName, $sAD_Site = "")

    If _AD_ObjectExists($sAD_User) = 0 Then Return SetError(1, 0, 0)
    Local $aAD_DCList = _AD_ListDomainControllers()
    Local $sAD_SingleDC, $bAD_WasIn
    ; Delete all DCs not belonging to the specified site
    If IsArray($sAD_Site) Then
        If UBound($sAD_Site) > 0 Then
            For $iAD_Count1 = $aAD_DCList[0][0] To 1 Step -1
                $bAD_WasIn = False
                For $sAD_SingleDC in $sAD_Site
                    If $aAD_DCList[$iAD_Count1][3] = $sAD_SingleDC Then $bAD_WasIn = True
                Next
                If Not $bAD_WasIn Then _ArrayDelete($aAD_DCList, $iAD_Count1)
            Next
            $aAD_DCList[0][0] = UBound($aAD_DCList, 1) - 1
        EndIf
    Else
        If $sAD_Site <> "" Then
            For $iAD_Count1 = $aAD_DCList[0][0] To 1 Step -1
                If $aAD_DCList[$iAD_Count1][3] <> $sAD_Site Then _ArrayDelete($aAD_DCList, $iAD_Count1)
            Next
            $aAD_DCList[0][0] = UBound($aAD_DCList, 1) - 1
        EndIf
    EndIf
    ; Get LastLogin from all DCs
    Local $aAD_Result[$aAD_DCList[0][0] + 1]
    Local $sAD_LDAPEntry, $oAD_Object, $oAD_RecordSet
    Local $iAD_Error1 = 0, $iAD_Error2 = 0
    For $iCount1 = 1 To $aAD_DCList[0][0]
        If Ping($aAD_DCList[$iCount1][2]) = 0 Then
            $iAD_Error1 += 1
            ContinueLoop
        EndIf
        $oAD_Command.CommandText = "<LDAP://" & $aAD_DCList[$iCount1][2] & "/" & $sAD_DNSDomain & ">;(sAMAccountName=" & $sAD_User & ");ADsPath;subtree"
        $oAD_RecordSet = $oAD_Command.Execute ; Retrieve the ADsPath for the object
        ; -2147352567 or 0x80020009 is returned when the service is not operational
        If @error = -2147352567 Or $oAD_RecordSet.RecordCount = 0 Then
            $iAD_Error1 += 1
        Else
            $sAD_LDAPEntry = $oAD_RecordSet.fields(0).value
            $oAD_Object = _AD_ObjGet($sAD_LDAPEntry) ; Retrieve the COM Object for the object
            $aAD_Result[$iCount1] = $oAD_Object.LastLogin
            ; -2147352567 or 0x80020009 is returned when the attribute "LastLogin" isn't defined on this DC
            If @error = -2147352567 Then $iAD_Error2 += 1
            $oAD_Object.PurgePropertyList
        EndIf
    Next
    _ArraySort($aAD_Result, 1, 1)
    ; If error count equals the number of DCs then the user has never logged in
    If $iAD_Error2 = $aAD_DCList[0][0] Then Return SetError(2, 0, 0)
    Return SetError($iAD_Error1, $aAD_DCList[0][0], $aAD_Result[1])

EndFunc   ;==>_AD_GetLastLoginDate

Version 0.43 has been released.

Please test before using in production!

For download please see my signature.

Link to comment
Share on other sites

Thanks so much for these tools! I wish I had discovered this a long time ago. It's helping me a lot.

I do have one question about _AD_GetPasswordDontExpire. I would like to use it in just a single OU, not the whole domain. However, there's no option for that, and when I try to connect with _AD_Open only specifying the OU I want, I still get a list of every account in the domain whose passwords don't expire. I'm using this format:

_AD_Open("", "", "", "domain controller", "OU=TheOUIWant,OU=MainOU,DC=something,DC=com")
$array = _AD_GetPasswordDontExpire()
I know it's probably something I'm doing wrong. I just discovered these tools today. Edited by Katharsis
Link to comment
Share on other sites

@Stephane

Thank you very much for this addition. Everything that enhances the UDF is welcome. I will include it in the next version.

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

@Katharsis

At the moment you can't specify the OU to limit the search. I will have a look at it next week and maybe can come up with a solution.

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

@Katharsis

please replace function _AD_GetpasswordDontExpire with this modified version. As first parameter pass the OU (Fully qualified domain name) where the search should start.

In your case:

$array = _AD_GetPasswordDontExpire("OU=TheOUIWant,OU=MainOU,DC=something,DC=com")

Please test and post the results. If it works I will change more functions so that you can pass the starting point for the search:

; #FUNCTION# ====================================================================================================================
; Name...........: _AD_GetPasswordDontExpire
; Description ...: Returns an array of user account FQDNs where the password does not expire.
; Syntax.........: _AD_GetPasswordDontExpire([$sAD_OU = ""])
; Parameters ....: $sAD_OU - Optional: FQDN of the OU where the search should start (default = "" = serach the whole tree)
; Return values .: Success - Array with FQDNs of user accounts for which the password does not expire
;               Failure - "", sets @error to:
;               |1 - No user accounts for which the password does not expire
; Author ........: Jonathan Clelland
; Modified.......: water
; Remarks .......:
; Related .......: _AD_IsPasswordExpired, _AD_GetPasswordExpired, _AD_SetPassword, _AD_DisablePasswordExpire, _AD_EnablePasswordExpire, _AD_EnablePasswordChange,  _AD_DisablePasswordChange, _AD_GetPasswordInfo
; Link ..........:
; Example .......: Yes
; ===============================================================================================================================
Func _AD_GetPasswordDontExpire($sAD_OU = "")

    If $sAD_OU = "" Then $sAD_OU = $sAD_DNSDomain
    $oAD_Command.CommandText = "<LDAP://" & $sAD_HostServer & "/" & $sAD_OU & ">;(&(objectcategory=user)(userAccountControl:1.2.840.113556.1.4.803:=" & _
            $ADS_UF_DONT_EXPIRE_PASSWD & "));distinguishedName;subtree"
    Local $oAD_RecordSet = $oAD_Command.Execute
    If Not IsObj($oAD_RecordSet) Or $oAD_RecordSet.RecordCount = 0 Then Return SetError(1, 0, "")
    Local $aAD_FQDN[$oAD_RecordSet.RecordCount + 1]
    $aAD_FQDN[0] = $oAD_RecordSet.RecordCount
    Local $iCount1 = 1
    While Not $oAD_RecordSet.EOF
        $aAD_FQDN[$iCount1] = $oAD_RecordSet.Fields(0).Value
        $iCount1 += 1
        $oAD_RecordSet.MoveNext
    WEnd
    Return $aAD_FQDN

EndFunc   ;==>_AD_GetPasswordDontExpire

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

@Stephane,

I've modified the function a bit. You can now specifiy multiple sites as a comma separated list. No need to create an array before calling the function. If you already have an array you can easily make a string out of it using _ArrayToString($avArray , ","). The benefit is that the user calling this function does not have to switch between string and array. And yes, the code got a lot smaller.

The modified function will be part of the next release.

Thanks for taking the time to enhance the UDF!

Func _AD_GetLastLoginDate($sAD_User = @UserName, $sAD_Site = "")

    If _AD_ObjectExists($sAD_User) = 0 Then Return SetError(1, 0, 0)
    Local $aAD_DCList = _AD_ListDomainControllers()
    Local $aAD_Site, $sAD_SingleDC, $bAD_WasIn
    ; Delete all DCs not belonging to the specified site
    $aAD_Site = StringSplit($sAD_Site, ",", 2)
    If UBound($aAD_Site) > 0 And $aAD_Site[0] <> "" Then
        For $iAD_Count1 = $aAD_DCList[0][0] To 1 Step -1
            $bAD_WasIn = False
            For $sAD_SingleDC In $aAD_Site
                If $aAD_DCList[$iAD_Count1][3] = $sAD_SingleDC Then $bAD_WasIn = True
            Next
            If Not $bAD_WasIn Then _ArrayDelete($aAD_DCList, $iAD_Count1)
        Next
        $aAD_DCList[0][0] = UBound($aAD_DCList, 1) - 1
    EndIf
    ; Get LastLogin from all DCs
    Local $aAD_Result[$aAD_DCList[0][0] + 1]
    Local $sAD_LDAPEntry, $oAD_Object, $oAD_RecordSet
    Local $iAD_Error1 = 0, $iAD_Error2 = 0
    For $iCount1 = 1 To $aAD_DCList[0][0]
        If Ping($aAD_DCList[$iCount1][2]) = 0 Then
            $iAD_Error1 += 1
            ContinueLoop
        EndIf
        $oAD_Command.CommandText = "<LDAP://" & $aAD_DCList[$iCount1][2] & "/" & $sAD_DNSDomain & ">;(sAMAccountName=" & $sAD_User & ");ADsPath;subtree"
        $oAD_RecordSet = $oAD_Command.Execute ; Retrieve the ADsPath for the object
        ; -2147352567 or 0x80020009 is returned when the service is not operational
        If @error = -2147352567 Or $oAD_RecordSet.RecordCount = 0 Then
            $iAD_Error1 += 1
        Else
            $sAD_LDAPEntry = $oAD_RecordSet.fields(0).value
            $oAD_Object = _AD_ObjGet($sAD_LDAPEntry) ; Retrieve the COM Object for the object
            $aAD_Result[$iCount1] = $oAD_Object.LastLogin
            ; -2147352567 or 0x80020009 is returned when the attribute "LastLogin" isn't defined on this DC
            If @error = -2147352567 Then $iAD_Error2 += 1
            $oAD_Object.PurgePropertyList
        EndIf
    Next
    _ArraySort($aAD_Result, 1, 1)
    ; If error count equals the number of DCs then the user has never logged in
    If $iAD_Error2 = $aAD_DCList[0][0] Then Return SetError(2, 0, 0)
    Return SetError($iAD_Error1, $aAD_DCList[0][0], $aAD_Result[1])

EndFunc   ;==>_AD_GetLastLoginDate

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...