Sign in to follow this  
Followers 0
shornw

_AD query

49 posts in this topic

I may be missing something obvious here, but I've probably been looking at it for too long, and can now not see the wood for the trees.

Is there a function in the AD.au3 UDF whereby I can query the age of a computer password, or more precisely generate a list of computers where the password is over x days old.

A bit like DSQuery computer -stalepwd 60 DC=domain,DC=com generates, but I want to do it all within AutoIT.

I've looked at _AD_GetAccountExpired() which looks like the closest thing, but can't get it to work properly for what I want to achieve.

Thanks


[font='Comic Sans MS']Eagles may soar high but weasels dont get sucked into jet engines[/font]

Share this post


Link to post
Share on other sites



#2 ·  Posted (edited)

You could use _AD_GetPasswordinfo. Elements[8] or [10] contain the date when the user last changed the password. Subtract this date form todays date using _DateDiff.

If you want to get a list of users with passwords older x days you have to calculate this date yourself and then use _AD_GetObjectsInOU to run the query.

I will check if I can find an example.

Edited by water

My UDFs and Tutorials:

Spoiler

UDFs:
Active Directory (NEW 2017-04-18 - Version 1.4.8.0) - Download - General Help & Support - Example Scripts - Wiki
OutlookEX (NEW 2017-02-27 - Version 1.3.1.0) - Download - General Help & Support - Example Scripts - Wiki
ExcelChart (2015-04-01 - Version 0.4.0.0) - Download - General Help & Support - Example Scripts
Excel - Example Scripts - Wiki
Word - Wiki
PowerPoint (2015-06-06 - Version 0.0.5.0) - Download - General Help & Support

Tutorials:
ADO - Wiki

 

Share this post


Link to post
Share on other sites

#3 ·  Posted (edited)

Hi Water. Thanks for the quick reply.

I specifically want to query computer accounts, not user accounts. I may be mistaken, but I read the $sAD_SamAccountName = @UserName to mean that it only applied to users. If this is not the case, I will give it a go.

Edited by shornw

[font='Comic Sans MS']Eagles may soar high but weasels dont get sucked into jet engines[/font]

Share this post


Link to post
Share on other sites

#4 ·  Posted (edited)

I just tested - _AD_GetPasswordInfo works for computers as well. You can pass the FQDN or the SamAccountName of the computer. Keep in mind that you must append a dollar sign to the samaccountname.

$aresult = _AD_GetPasswordInfo(@ComputerName & "$")

returns the passwordinfo for the computer you are logged on.

I've extended the docu accordingly.

Edited by water

My UDFs and Tutorials:

Spoiler

UDFs:
Active Directory (NEW 2017-04-18 - Version 1.4.8.0) - Download - General Help & Support - Example Scripts - Wiki
OutlookEX (NEW 2017-02-27 - Version 1.3.1.0) - Download - General Help & Support - Example Scripts - Wiki
ExcelChart (2015-04-01 - Version 0.4.0.0) - Download - General Help & Support - Example Scripts
Excel - Example Scripts - Wiki
Word - Wiki
PowerPoint (2015-06-06 - Version 0.0.5.0) - Download - General Help & Support

Tutorials:
ADO - Wiki

 

Share this post


Link to post
Share on other sites

Excellent stuff.

At the risk of sounding like I'm never satisfied, is there a way I can run a query on the entire domain (ie all computer accounts) without having to specify each account individually, which would involve generating a list, then running a query against said list.

Thanks for your help thus far, it's very much appreciated


[font='Comic Sans MS']Eagles may soar high but weasels dont get sucked into jet engines[/font]

Share this post


Link to post
Share on other sites

Hi Shornw,

yes you can!

Take function _AD_GetpasswordExpired and change the following line

$sAD_DTExpire = _DateAdd("D", $aAD_Temp[1] * - 1, $sAD_DTExpire) ; substract maximum password age
$aAD_Temp[1] should be the maximum age of the password e.g. set this value to 20 if you want ot get a list of all accounts where the password is older than 20 days.

Plus you have to change line

$oAD_Command.CommandText = "<LDAP://" & $sAD_HostServer & "/" & $sAD_Root & ">;(&(objectCategory=person)(objectClass=user)" & _
to
$oAD_Command.CommandText = "<LDAP://" & $sAD_HostServer & "/" & $sAD_Root & ">;(&(objectCategory=person)(objectClass=computer)" & _

HTH!


My UDFs and Tutorials:

Spoiler

UDFs:
Active Directory (NEW 2017-04-18 - Version 1.4.8.0) - Download - General Help & Support - Example Scripts - Wiki
OutlookEX (NEW 2017-02-27 - Version 1.3.1.0) - Download - General Help & Support - Example Scripts - Wiki
ExcelChart (2015-04-01 - Version 0.4.0.0) - Download - General Help & Support - Example Scripts
Excel - Example Scripts - Wiki
Word - Wiki
PowerPoint (2015-06-06 - Version 0.0.5.0) - Download - General Help & Support

Tutorials:
ADO - Wiki

 

Share this post


Link to post
Share on other sites

Fantastic!! max respect to you Water:-

a) for creating and sharing the UDF so that we mortals get the benefit

:D For coming up trumps yet again

I can't begin to say how much I value this forum, for the kindness and helpfulness of the members - this is just another example.

Have a great weekend


[font='Comic Sans MS']Eagles may soar high but weasels dont get sucked into jet engines[/font]

Share this post


Link to post
Share on other sites

#8 ·  Posted (edited)

Thanks a lot for the compliments :D

I just added two additional parameters to _AD_GetPasswordExpired so you can now pass the password age and the type you want to query:

; #FUNCTION# ====================================================================================================================
; Name...........: _AD_GetPasswordExpired
; Description ...: Returns an array of FQDNs of user account with expired passwords.
; Syntax.........: _AD_GetPasswordExpired([$sAD_Root = ""[, $bAD_NeverChanged = False]])
; Parameters ....: $sAD_Root         - Optional: FQDN of the OU where the search should start (default = "" = search the whole tree)
;                 $bAD_NeverChanged - Optional: If set to True returns all users who have never changed their password as well (default = False)
;                 $iAD_PasswordAge  - Optional: Takes the max. password age from the AD or uses this value if > 0
;                 $bAD_Computer  - Optional: If True queries computer accounts, if False queries user accounts (default = False)
; Return values .: Success - One-based two dimensional array of FQDNs of user accounts with expired passwords
;                 |0 - FQDNs of user accounts with expired password
;                 |1 - password last set YYYY/MM/DD HH:NMM:SS UTC
;                 |2 - password last set YYYY/MM/DD HH:NMM:SS local time of calling user
;                 Failure - "", sets @error to:
;                 |1 - No expired passwords found
;                 |2 - Specified $sAD_Root does not exist
;                 |3 - $iAD_PasswordAge is not numeric
; Author ........: water
; Modified.......:
; Remarks .......:
; Related .......: _AD_IsPasswordExpired, _AD_GetPasswordDontExpire, _AD_SetPassword, _AD_DisablePasswordExpire, _AD_EnablePasswordExpire, _AD_EnablePasswordChange,  _AD_DisablePasswordChange, _AD_GetPasswordInfo
; Link ..........:
; Example .......: Yes
; ===============================================================================================================================
Func _AD_GetPasswordExpired($sAD_Root = "", $bAD_NeverChanged = False, $iAD_PasswordAge = 0, $bAD_Computer = False)

    If $sAD_Root = "" Then
        $sAD_Root = $sAD_DNSDomain
    Else
        If _AD_ObjectExists($sAD_Root, "distinguishedName") = 0 Then Return SetError(2, 0, "")
    EndIf
    If $iAD_PasswordAge <> 0 And Not IsNumber($iAD_PasswordAge) Then Return SetError(3, 0, "")
    Local $aAD_Temp = _AD_GetPasswordInfo()
    Local $sAD_DTExpire = _Date_Time_GetSystemTime() ; Get current date/time
    $sAD_DTExpire = _Date_Time_SystemTimeToDateTimeStr($sAD_DTExpire, 1) ; convert to system time
    If $iAD_PasswordAge <> 0 Then
        $sAD_DTExpire = _DateAdd("D", $iAD_PasswordAge * - 1, $sAD_DTExpire) ; substract maximum password age
    Else
        $sAD_DTExpire = _DateAdd("D", $aAD_Temp[1] * - 1, $sAD_DTExpire) ; substract maximum password age
    EndIf
    Local $iAD_DTExpire = _DateDiff("s", "1601/01/01 00:00:00", $sAD_DTExpire) * 10000000 ; convert to Integer8
    Local $sAD_DTStruct = DllStructCreate("dword low;dword high")
    Local $sAD_Temp, $iAD_Temp, $iAD_LowerDate = 110133216000000001 ; 110133216000000001 = 01/01/1959 00:00:00 UTC
    If $bAD_NeverChanged = True Then $iAD_LowerDate = 0
    Local $sAD_Category = "(objectCategory=Person)(objectClass=User)"
    If $bAD_Computer = True Then $sAD_Category = "(objectCategory=computer)"
    $oAD_Command.CommandText = "<LDAP://" & $sAD_HostServer & "/" & $sAD_Root & ">;(&" & $sAD_Category & _
        "(pwdLastSet<=" & Int($iAD_DTExpire) & ")(pwdLastSet>=" & $iAD_LowerDate & "));distinguishedName,pwdlastset,useraccountcontrol;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][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
        $iAD_Temp = $oAD_RecordSet.Fields(1).Value
        If BitAND($oAD_RecordSet.Fields(2).Value, $ADS_UF_DONT_EXPIRE_PASSWD) <> $ADS_UF_DONT_EXPIRE_PASSWD Then
            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)
            $sAD_Temp = _Date_Time_SystemTimeToTzSpecificLocalTime(DllStructGetPtr($sAD_Temp))
            $aAD_FQDN[$iAD_Count][2] = _Date_Time_SystemTimeToDateTimeStr($sAD_Temp, 1)
        EndIf
        $iAD_Count += 1
        $oAD_RecordSet.MoveNext
    WEnd
    ; Delete records with UAC set to password not expire
    $aAD_FQDN[0][0] = UBound($aAD_FQDN) - 1
    For $iAD_Count = $aAD_FQDN[0][0] To 1 Step -1
        If $aAD_FQDN[$iAD_Count][1] = "" Then _ArrayDelete($aAD_FQDN, $iAD_Count)
    Next
    $aAD_FQDN[0][0] = UBound($aAD_FQDN) - 1
    Return $aAD_FQDN

EndFunc   ;==>_AD_GetPasswordExpired

To query all computers where the password is older than 20 days you would use:

$aResult = _AD_GetPasswordExpired("", False, 20, True)
Edited by water

My UDFs and Tutorials:

Spoiler

UDFs:
Active Directory (NEW 2017-04-18 - Version 1.4.8.0) - Download - General Help & Support - Example Scripts - Wiki
OutlookEX (NEW 2017-02-27 - Version 1.3.1.0) - Download - General Help & Support - Example Scripts - Wiki
ExcelChart (2015-04-01 - Version 0.4.0.0) - Download - General Help & Support - Example Scripts
Excel - Example Scripts - Wiki
Word - Wiki
PowerPoint (2015-06-06 - Version 0.0.5.0) - Download - General Help & Support

Tutorials:
ADO - Wiki

 

Share this post


Link to post
Share on other sites

Thank you for the work you have done so far.

Unfortunately, when I try this, I get an error that it is called with wrong number of arguments.

To clarify - I have replaced the function in AD.au3 with the one posted. Is there something I'm missing?


[font='Comic Sans MS']Eagles may soar high but weasels dont get sucked into jet engines[/font]

Share this post


Link to post
Share on other sites

How do you call _AD_GetPasswordExpired? Could you please show an example?

All parameters are optional, so you shouldn't get this error message.


My UDFs and Tutorials:

Spoiler

UDFs:
Active Directory (NEW 2017-04-18 - Version 1.4.8.0) - Download - General Help & Support - Example Scripts - Wiki
OutlookEX (NEW 2017-02-27 - Version 1.3.1.0) - Download - General Help & Support - Example Scripts - Wiki
ExcelChart (2015-04-01 - Version 0.4.0.0) - Download - General Help & Support - Example Scripts
Excel - Example Scripts - Wiki
Word - Wiki
PowerPoint (2015-06-06 - Version 0.0.5.0) - Download - General Help & Support

Tutorials:
ADO - Wiki

 

Share this post


Link to post
Share on other sites

#11 ·  Posted (edited)

I have deliberately stripped it down to an absolute minimum to reduce the chance of errors.

It may not be relevant, but when I type the command in SciTe manually, where I would expect to see the options, all I see is AD_GetPasswordExpired([$sAD_Root = ""]) without any other options. This is the case for the modified, and the original AD.au3

_AD_Open()[AD

Global $aExpired[1]
$aExpired = _AD_GetPasswordExpired("", False, 20, True)
_ArrayDisplay($aExpired, "Active Directory Functions - Example 1 - User accounts with expired password")
_AD_Close()
Edited by shornw

[font='Comic Sans MS']Eagles may soar high but weasels dont get sucked into jet engines[/font]

Share this post


Link to post
Share on other sites

#12 ·  Posted (edited)

SciTe seems to point to an old version of the UDF.

Please open your script in SciTe, place the cursor somewhere in the line

#include <AD.au3>
and press Alt+i.

Now you see the UDF which is used by your script. Is this the version where you changed _AD_GetPasswordExpired?

Edited by water

My UDFs and Tutorials:

Spoiler

UDFs:
Active Directory (NEW 2017-04-18 - Version 1.4.8.0) - Download - General Help & Support - Example Scripts - Wiki
OutlookEX (NEW 2017-02-27 - Version 1.3.1.0) - Download - General Help & Support - Example Scripts - Wiki
ExcelChart (2015-04-01 - Version 0.4.0.0) - Download - General Help & Support - Example Scripts
Excel - Example Scripts - Wiki
Word - Wiki
PowerPoint (2015-06-06 - Version 0.0.5.0) - Download - General Help & Support

Tutorials:
ADO - Wiki

 

Share this post


Link to post
Share on other sites

To be completely sure, I uninstalled AutoIT and SciTe and deleted AutoIT folder from Program Files. I then downloaded (to be sure of latest version) and re-installed (remembering to copy the files into the relevant Include and SciTe folders. I then copied and pasted the _AD_GetPasswordExpired function into AD.au3, labelling it as Modified 14/11/2011. Alt+i shows that it is the modified AD.au3 that is being used, but now when I run the script, the AutoIT icon appears momentarily in SysTray then disappears.

I ran

#include <AD.au3>
#include <Process.au3>
#include <Array.au3>


_AD_Open()

Global $aExpired[1]

$aExpired = _AD_GetPasswordExpired()
;$aExpired = _AD_GetPasswordExpired("", False, 20, True)
_ArrayDisplay($aExpired, "Active Directory Functions - Example 1 - User accounts with expired password")

_AD_Close()

and the list was generated fine.

I have also tried this on another PC, with exactly the same result. I must be missing something, but I really don't know what


[font='Comic Sans MS']Eagles may soar high but weasels dont get sucked into jet engines[/font]

Share this post


Link to post
Share on other sites

Hi shornw,

I was able to reproduce your error:

I have a full SciTe/AutoIt installation with the include directory, a development directory for the AD UDF where my test script resides PLUS an another directory for the additional UDFs I have downloaded and which are used by all other scripts.

In this directory there was an "old" AD UDF which caused the error messages.

H:\tools\AutoIt3\AD\AD_Test2.au3(4,61) : ERROR: _AD_GetPasswordExpired() called with wrong number of args.

Global $aResult = _AD_GetPasswordExpired("", False, 20, True)

~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~^

H:\tools\AutoIt3\Include\ad.au3(1870,71) : REF: definition of _AD_GetPasswordExpired().

Func _AD_GetPasswordExpired($sAD_Root = "", $bAD_NeverChanged = False)

~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~^

H:\tools\AutoIt3\AD\AD_Test2.au3 - 1 error(s), 0 warning(s)

The path marked red was the path holding the "old" AD UDF.

Check if the paths in the error message you get are identical and point to the same AD UDF.


My UDFs and Tutorials:

Spoiler

UDFs:
Active Directory (NEW 2017-04-18 - Version 1.4.8.0) - Download - General Help & Support - Example Scripts - Wiki
OutlookEX (NEW 2017-02-27 - Version 1.3.1.0) - Download - General Help & Support - Example Scripts - Wiki
ExcelChart (2015-04-01 - Version 0.4.0.0) - Download - General Help & Support - Example Scripts
Excel - Example Scripts - Wiki
Word - Wiki
PowerPoint (2015-06-06 - Version 0.0.5.0) - Download - General Help & Support

Tutorials:
ADO - Wiki

 

Share this post


Link to post
Share on other sites

I don't get any 'Wrong number of argument' errors since removing everything and re-installing. All that happens now, is the AutoIT icon appears in SysTray for a very short time, then disappears, nothing else at all

I get an @error of 1 if I run _AD_GetPasswordExpired("", False, 20, True)

but an @error 0 if I run _AD_GetPasswordExpired() and a list of around 1400 accounts


[font='Comic Sans MS']Eagles may soar high but weasels dont get sucked into jet engines[/font]

Share this post


Link to post
Share on other sites

Water - First off, thanks for your patience

Can I confirm something - in your previous post you said replace line:

$oAD_Command.CommandText = "<LDAP://" & $sAD_HostServer & "/" & $sAD_Root & ">;(&(objectCategory=person)(objectClass=user)" &

with

$oAD_Command.CommandText = "<LDAP://" & $sAD_HostServer & "/" & $sAD_Root & ">;(&(objectCategory=person)(objectClass=computer)" &

which contains the ObjectClass=Computer

This is NOT the case in the revised Func you posted. Am I right in assuming that I should copy the entire func from your post, and replace the same func in AD.au3?


[font='Comic Sans MS']Eagles may soar high but weasels dont get sucked into jet engines[/font]

Share this post


Link to post
Share on other sites

That's right. Take the complete function and replace the same func in AD.au3 OR

put the new function into your script, name it _AD_GetPasswordExpiredEX and call this renamed function.


My UDFs and Tutorials:

Spoiler

UDFs:
Active Directory (NEW 2017-04-18 - Version 1.4.8.0) - Download - General Help & Support - Example Scripts - Wiki
OutlookEX (NEW 2017-02-27 - Version 1.3.1.0) - Download - General Help & Support - Example Scripts - Wiki
ExcelChart (2015-04-01 - Version 0.4.0.0) - Download - General Help & Support - Example Scripts
Excel - Example Scripts - Wiki
Word - Wiki
PowerPoint (2015-06-06 - Version 0.0.5.0) - Download - General Help & Support

Tutorials:
ADO - Wiki

 

Share this post


Link to post
Share on other sites

Well, I copied the function into the script and after a bit of jiggery-pokery got it to run with the following results:

_AD_GetPasswordExpired() and return a list of accounts (all User accounts) (@error of 0)

_AD_GetPasswordExpired("", False, 20, True) - I get nothing (@error of 1)

I have DSQuery'd and get loads of machine accounts (Thin clients don't update their password) so I know that there are accounts that fit the criterion


[font='Comic Sans MS']Eagles may soar high but weasels dont get sucked into jet engines[/font]

Share this post


Link to post
Share on other sites

I still try to understand how the computer password works. I think I've found a good description here.

Did the first change I posted work for you? If yes, then there has to be a bug in function I posted as a


My UDFs and Tutorials:

Spoiler

UDFs:
Active Directory (NEW 2017-04-18 - Version 1.4.8.0) - Download - General Help & Support - Example Scripts - Wiki
OutlookEX (NEW 2017-02-27 - Version 1.3.1.0) - Download - General Help & Support - Example Scripts - Wiki
ExcelChart (2015-04-01 - Version 0.4.0.0) - Download - General Help & Support - Example Scripts
Excel - Example Scripts - Wiki
Word - Wiki
PowerPoint (2015-06-06 - Version 0.0.5.0) - Download - General Help & Support

Tutorials:
ADO - Wiki

 

Share this post


Link to post
Share on other sites

Nevermind, I think I found the problem. I will post an enhanced version tomorrow (here it is time to leave work and have a beer :D)


My UDFs and Tutorials:

Spoiler

UDFs:
Active Directory (NEW 2017-04-18 - Version 1.4.8.0) - Download - General Help & Support - Example Scripts - Wiki
OutlookEX (NEW 2017-02-27 - Version 1.3.1.0) - Download - General Help & Support - Example Scripts - Wiki
ExcelChart (2015-04-01 - Version 0.4.0.0) - Download - General Help & Support - Example Scripts
Excel - Example Scripts - Wiki
Word - Wiki
PowerPoint (2015-06-06 - Version 0.0.5.0) - Download - General Help & Support

Tutorials:
ADO - Wiki

 

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
Sign in to follow this  
Followers 0