Re: ADSI User with Never expire password
- From: Cadstillo <Cadstillo@xxxxxxxxxxxxxxxxxxxxxxxxx>
- Date: Wed, 24 May 2006 19:21:01 -0700
Wow, excellent info. Thanks. I am going to check this out.
How can I tell if a user's password will never expire.
--
Cadstillo
"Richard Mueller" wrote:
Just to expand (laugh, laugh), I used LDAP syntax in my ADO query. The.
filter uses "&", the AND operator, and "|" (the pipe symbol), which is the
OR operator. You can also use "!", the NOT operator. The equivalent query
using SQL syntax would be:
strQuery = "SELECT sAMAccountName, distinguishedName " _
& "FROM 'LDAP://" & strDNSDomain & "' " _
& "WHERE objectCategory='person' " _
& "AND objectClass='user' " _
& "AND (accountExires=0 OR accountExpires=9223372036854775807)"
I use SQL queries all the time for SQL databases, but I stick to LDAP syntax
for AD. For more info on using LDAP syntax with ADO to retrieve information
from AD, see this link:
http://www.rlmueller.net/ADOSearchTips.htm
The link also has many examples of search filters.
--
Richard
Microsoft MVP Scripting and ADSI
Hilltop Lab - http://www.rlmueller.net
"Richard Mueller" <rlmueller-NOSPAM@xxxxxxxxxxxxxxxxxxxx> wrote in message
news:%23bhZ8dueGHA.5040@xxxxxxxxxxxxxxxxxxxxxxx
Cadstillo wrote:
In the link below the MS Scripting Guys post a script that returns all
users
whose passwords never expire.
http://www.microsoft.com/technet/scriptcenter/resources/qanda/sept05/hey0902.mspx
However, when I run the script all it does is echo all users in my
domain.
In addition, I cannot find the attribute "objUser.AccountExpirationDate"
in
adsiedit.msc.
Where is this attribute at and why does it return all users in my domain?
Thanks
Hi,
The linked program does not return users whose password do not expire, but
users whose accounts do not expire.
AccountExpirationDate is not an attribute of user objects. That's why it
is not revealed by ADSI Edit. It is what I call a property method. By this
I mean it is a method, in this case exposed by the IADsUser interface,
that returns a value based on other attributes. In this case,
AccountExpirationDate returns a value based on the value of the
accountExpires attribute of the user object. accountExpires is Integer8,
which is a 64-bit number that is difficult to deal with in VBScript.
That's why the program in the link binds to the user object, which makes
the program much slower. This bind is required to run the property method.
If it were an attribute it would be much more efficient to retrieve along
with AdsPath in the ADO query.
Actually, AdsPath is also a property method, since it is not an attribute
in AD (again ADSI Edit does not reveal it). However, ADO seems to have
some magic built in that allows it to retrieve a few property methods,
namely Name and AdsPath, but no others.
Note also that the linked program checks if AccountExpirationDate returns
"1/1/1970". This is a completely bogus date. I believe this was the "zero"
date in NT domains, so the property method apparently hard codes this date
if accountExpires is zero. In AD the "zero" date is actually 12:00 AM
January 1, 1601. The date 1/1/1970 has no significance at all in AD.
A better way to retrieve all users with accounts that do not expire is to
use ADO to retrieve users whose accountExpires attribute is either 0 or
2^63-1. The later is equal to 9,223,372,036,854,775,807. If an account had
an expiration date and you remove it, or you create an account with no
expiration, this value is assigned to accountExpires. You can also assign
the value -1 to account expires, which results in the same value, 2^63-1,
because of the way 64-bit numbers are handled. The AccountExpirationDate
property method raises an error if accountExpires is 2^63-1, which is why
the linked program uses "On Error Resume Next" and traps the error. I
don't want to criticize the Scripting Guy, but I avoid using "On Error
Resume Next" except on statements I expect to raise an error. There could
be an error in your version of the script, but with error handling
disabled you don't know this, and the script merrily spits out garbage, as
you are seeing. You might want to remove "On Error Resume Next" so see
what errors crop up.
Here is how I would code a VBScript program to document all user objects
that never expire:
============================
Option Explicit
Dim objRootDSE, strDNSDomain, objCommand, objConnection
Dim strBase, strFilter, strAttributes, strQuery, objRecordSet
Dim strNTName, strDN
' Determine DNS domain name.
Set objRootDSE = GetObject("LDAP://RootDSE")
strDNSDomain = objRootDSE.Get("defaultNamingContext")
' Use ADO to search Active Directory.
Set objCommand = CreateObject("ADODB.Command")
Set objConnection = CreateObject("ADODB.Connection")
objConnection.Provider = "ADsDSOObject"
objConnection.Open "Active Directory Provider"
objCommand.ActiveConnection = objConnection
' Search entire domain.
strBase = "<LDAP://" & strDNSDomain & ">"
' Filter on user objects that do not expire.
strFilter = "(&(objectCategory=person)(objectClass=user)" _
& "(|(accountExpires=9223372036854775807)(accountExpires=0)))"
' Comma delimited list of attribute values to retrieve.
strAttributes = "sAMAccountName,distinguishedName"
' Construct the ADO query, using LDAP syntax.
strQuery = strBase & ";" & strFilter & ";" & strAttributes & ";subtree"
' Run the query.
objCommand.CommandText = strQuery
objCommand.Properties("Page Size") = 100
objCommand.Properties("Timeout") = 30
objCommand.Properties("Cache Results") = False
Set objRecordSet = objCommand.Execute
' Enumerate the recordset and output the values retrieved.
Do Until objRecordSet.EOF
strNTName = objRecordSet.Fields("sAMAccountName").Value
strDN = objRecordSet.Fields("distinguishedName").Value
Wscript.Echo strNTName & "- " & strDN
objRecordSet.MoveNext
Loop
objRecordSet.Close
' Clean up.
objConnection.Close
Set objRootDSE = Nothing
Set objCommand = Nothing
Set objConnection = Nothing
Set objRecordSet = Nothing
====================
I output both the sAMAccountName and distinguishedName values. You might
want to use just one of these. The program you linked outputs the value
returned by the Name property method, which is the value of cn (Common
Name). Unfortunately, this does not uniquely identify the user, much less
tell you where they are in AD. My version should be faster because it does
not bind to the user objects. All the real work is done on the DC.
Finally, to retrieve users whose passwords do not expire, you want users
whose userAccountControl attribute has the appropriate bit set. For this,
use this filter:
strFilter = "(&(objectCategory=person)(objectClass=user)" _
& "(userAccountControl:1.2.840.113556.1.4.803:=65536))"
The ADS_UF_DONT_EXPIRE_PASSWD bit mask is &H10000, which is 65536 decimal.
--
Richard
Microsoft MVP Scripting and ADSI
Hilltop Lab - http://www.rlmueller.net
- References:
- Re: ADSI User with Never expire password
- From: Richard Mueller
- Re: ADSI User with Never expire password
- From: Richard Mueller
- Re: ADSI User with Never expire password
- Prev by Date: Re: Passing arguments to a function referred to using getref...
- Next by Date: Re: Removing default gateway
- Previous by thread: Re: ADSI User with Never expire password
- Next by thread: can this server side script run in firefox?
- Index(es):
Relevant Pages
|