Home All Groups Group Topic Archive Search About

Re: Updating AD with a script

Author
12 Apr 2009 3:41 AM
Tcs
I made all three (3) changes.  And the script ran all the way thru. It
also did NOT find anyone to modify.  So I put back:

  If  ( intUAC <> 514 And Not ADS_UF_ACCOUNTDISABLE ) Then

This time it found five (5) users to modify...then errored out at:

  Set objUser = GetObject _
     ( "LDAP://" & objRecordset.Fields("distinguishedName") )

  Error:  0x80005000
  Code:   80005000
  Source: (null)

So then I changed:

  If  ( intUAC <> 514 And Not ADS_UF_ACCOUNTDISABLE ) Then

To:

  If  ( intUAC <> 514 And ADS_UF_ACCOUNTDISABLE = 0 ) Then

And it went back to finding NO ONE to change.  So...

I changed:

  If  ( intUAC <> 514 And ADS_UF_ACCOUNTDISABLE = 0 ) Then

To:

  If  ( intUAC And Not ADS_UF_ACCOUNTDISABLE ) Then

This time it found five (5) users to modify...then errored out at:

  Set objUser = GetObject _
     ( "LDAP://" & objRecordset.Fields("distinguishedName") )

  Error:  0x80005000
  Code:   80005000
  Source: (null)

It did modify the five (5) that it found, the way I wanted.  So...it
WAS an improvement.  Now if I could just fix the remaining 250+
users...  :)

Any ideas?

Thanks again,

Tom

On Mon, 6 Apr 2009 14:56:21 -0500, "Richard Mueller [MVP]"
<rlmueller-nospam@ameritech.nospam.net> wrote:

Show quoteHide quote
>Tom wrote:
>
>> I've been trying to update our AD with a script.  ( We currently run
>My theory is that you added a contact to your AD. Your filter
>(objectCategory=user) will return return all user and contact objects in the
>domain, but contact objects do not have a userAccountControl attribute. This
>should raise an error. Assuming no other problems, the fix would be to use
>the filter (&(objectCategory=person)(objectClass=user)). For example:
>
>    objCommand.CommandText = _
>        "<GC://dc=EastPointCity,dc=org>;(&(objectCategory=person)(objectClass=user))"
>& _
>
>A few other points. I'm not sure this would work:
>
>    intUAC=objRecordset.Fields("userAccountControl")
>    If  ( intUAC <> 514 And Not ADS_UF_ACCOUNTDISABLE ) Then
>
>I would instead use:
>
>    intUAC=objRecordset.Fields("userAccountControl")
>    If (intUAC And ADS_UF_ACCOUNTDISABLE = 0) Then
>
>This ensures that only accounts not disabled are processed. Also, objUser.c
>should be "US" instead of "United States". When you assign the proper two
>letter abbreviation to the c attribute, AD assigns "United States" to the co
>attibute and "840" to the CountryCode attribute.
>
>--
>Richard Mueller
>MVP Directory Services
>Hilltop Lab - http://www.rlmueller.net

Author
12 Apr 2009 6:06 PM
Richard Mueller [MVP]
The only situation I am aware of that will cause the error on this statement
(where the DN is retrieved by ADO):

  Set objUser = GetObject _
     ( "LDAP://" & objRecordset.Fields("distinguishedName") )

is when the DistinguishedName has a forward slash character, "/". In
VBScript this must be escaped with the backslash escape character, "\". For
example:

strUserDN = objRecordset.Fields("distinguishedName").Value
strUserDN = Replace(strUserDN, "/", "\/")
Set objUser = GetOBject("LDAP://" & strUserD)

For more on escaping characters in VBScript, see this link:

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

I've recently learned that two other characters must also be escaped, a
leading blank and a trailing blank (for example, if the Common Name is " Jim
Smith" or "Jim Smith "). However, the only character that is not already
escaped by ADO (so that you must test for it and escape it yourself) is the
forward slash. It is an unfortunate quirk that only arises in methods that
use ADSI (like VBScript). As for the statement:

If ( intUAC <> 514 And Not ADS_UF_ACCOUNTDISABLE ) Then

I had no idea what that would do (it is not clear at all), so I had to test.
It does not result in the script operating on all users that are not
disabled. Instead, the script will operate on all users where intUAC is not
514. This will include some disabled users who have other bits (flags) of
the userAccountControl attribute set (like password never expires).

I believe your clause is equivalent to:

If (intUAC <> 514) And (intUAC And ADS_UF_ACCOUNTDISABLE <> 0) Then

Which is exactly the same as:

If (intUAC <> 514) Then

In my domain, the script will not operate on the krbtgt account, since
userAccountControl is 514. However, it will operate on the guest account
where userAccountControl is 66082. 514 means:

    account disabled
    default account for typical user

whereas 66082 means:

    account disabled
    no password required
    default account for typical user
    password does not expire

The userAccountControl attribute is a "flag" attribute. It is an integer
value that indicates the status of several flags. It is tested using bit
masks, one bit mask for each setting. The proper way to test for a given
setting is to AND the value of the attribute with the corresponding bit
mask. Any non-zero result means the flag is set, a zero result means the
flag is NOT set. You set a bit using the OR operator. If you OR the value
with a bit mask, you set the corresponding flag. The XOR operator toggles
the corresponding bit (from on to off, or from off to on). To unset a flag,
you first must test if the bit is set (using the AND operator), then use the
XOR operator to toggle the bit off. For example, to test if an account is
disabled:

Const ADS_UF_ACCOUNTDISABLE = &H02
intUAC = objUser.userAccountControl
If (intUAC And ADS_UF_ACCOUNTDISABLE <> 0) Then
    ' The account is disabled.
End If

If (intUAC And ADS_UF_ACCOUNTDISABLE = 0) Then
    ' The account is NOT disabled (the account is enabled).
End If

To disable an account:

Const ADS_UF_ACCOUNTDISABLE = &H02
intUAC = objUser.userAccountControl
intUAC = intUAC Or ADS_UF_ACCOUNTDISABLE
objUser.userAccountControl = intUAC
objUser.SetInfo

Finally, to enable an account:

intUAC = objUser.userAccountControl
If (intUAC And ADS_UF_ACCOUNTDISABLE <> 0) Then
    intUAC = intUAC Xor ADS_UF_ACCOUNTDISABLE
    objUser.userAccountControl = intUAC
    objUser.SetInfo
End If

One source of confusion is that the AND operator has two meanings. It can
mean the bitwise And'ing of two values, or it can mean the combining of two
conditional clauses so that both must be True for the whole to be True.
Remember also that in VBScript 0 is False, anything else is True.

--
Richard Mueller
MVP Directory Services
Hilltop Lab - http://www.rlmueller.net
--

Show quoteHide quote
"Tcs" <some***@somewhere.com> wrote in message
news:gcm2u49p36imbnh205tlelhoi7hobel5hb@4ax.com...
>I made all three (3) changes.  And the script ran all the way thru. It
> also did NOT find anyone to modify.  So I put back:
>
>  If  ( intUAC <> 514 And Not ADS_UF_ACCOUNTDISABLE ) Then
>
> This time it found five (5) users to modify...then errored out at:
>
>  Set objUser = GetObject _
>     ( "LDAP://" & objRecordset.Fields("distinguishedName") )
>
>  Error:  0x80005000
>  Code:   80005000
>  Source: (null)
>
> So then I changed:
>
>  If  ( intUAC <> 514 And Not ADS_UF_ACCOUNTDISABLE ) Then
>
> To:
>
>  If  ( intUAC <> 514 And ADS_UF_ACCOUNTDISABLE = 0 ) Then
>
> And it went back to finding NO ONE to change.  So...
>
> I changed:
>
>  If  ( intUAC <> 514 And ADS_UF_ACCOUNTDISABLE = 0 ) Then
>
> To:
>
>  If  ( intUAC And Not ADS_UF_ACCOUNTDISABLE ) Then
>
> This time it found five (5) users to modify...then errored out at:
>
>  Set objUser = GetObject _
>     ( "LDAP://" & objRecordset.Fields("distinguishedName") )
>
>  Error:  0x80005000
>  Code:   80005000
>  Source: (null)
>
> It did modify the five (5) that it found, the way I wanted.  So...it
> WAS an improvement.  Now if I could just fix the remaining 250+
> users...  :)
>
> Any ideas?
>
> Thanks again,
>
> Tom
>
> On Mon, 6 Apr 2009 14:56:21 -0500, "Richard Mueller [MVP]"
> <rlmueller-nospam@ameritech.nospam.net> wrote:
>
>>Tom wrote:
>>
>>> I've been trying to update our AD with a script.  ( We currently run
>>My theory is that you added a contact to your AD. Your filter
>>(objectCategory=user) will return return all user and contact objects in
>>the
>>domain, but contact objects do not have a userAccountControl attribute.
>>This
>>should raise an error. Assuming no other problems, the fix would be to use
>>the filter (&(objectCategory=person)(objectClass=user)). For example:
>>
>>    objCommand.CommandText = _
>>
>> "<GC://dc=EastPointCity,dc=org>;(&(objectCategory=person)(objectClass=user))"
>>& _
>>
>>A few other points. I'm not sure this would work:
>>
>>    intUAC=objRecordset.Fields("userAccountControl")
>>    If  ( intUAC <> 514 And Not ADS_UF_ACCOUNTDISABLE ) Then
>>
>>I would instead use:
>>
>>    intUAC=objRecordset.Fields("userAccountControl")
>>    If (intUAC And ADS_UF_ACCOUNTDISABLE = 0) Then
>>
>>This ensures that only accounts not disabled are processed. Also,
>>objUser.c
>>should be "US" instead of "United States". When you assign the proper two
>>letter abbreviation to the c attribute, AD assigns "United States" to the
>>co
>>attibute and "840" to the CountryCode attribute.
>>
>>--
>>Richard Mueller
>>MVP Directory Services
>>Hilltop Lab - http://www.rlmueller.net
Author
18 Apr 2009 12:42 PM
Tcs
Thank you.  I'll take another stab at it.

I do appreciate your time and effort.

On Sun, 12 Apr 2009 13:06:32 -0500, "Richard Mueller [MVP]"
<rlmueller-nospam@ameritech.nospam.net> wrote:

Show quoteHide quote
>The only situation I am aware of that will cause the error on this statement
>(where the DN is retrieved by ADO):
>
>  Set objUser = GetObject _
>     ( "LDAP://" & objRecordset.Fields("distinguishedName") )
>
>is when the DistinguishedName has a forward slash character, "/". In
>VBScript this must be escaped with the backslash escape character, "\". For
>example:
>
>strUserDN = objRecordset.Fields("distinguishedName").Value
>strUserDN = Replace(strUserDN, "/", "\/")
>Set objUser = GetOBject("LDAP://" & strUserD)
>
>For more on escaping characters in VBScript, see this link:
>
>http://www.rlmueller.net/CharactersEscaped.htm
>
>I've recently learned that two other characters must also be escaped, a
>leading blank and a trailing blank (for example, if the Common Name is " Jim
>Smith" or "Jim Smith "). However, the only character that is not already
>escaped by ADO (so that you must test for it and escape it yourself) is the
>forward slash. It is an unfortunate quirk that only arises in methods that
>use ADSI (like VBScript). As for the statement:
>
>If ( intUAC <> 514 And Not ADS_UF_ACCOUNTDISABLE ) Then
>
>I had no idea what that would do (it is not clear at all), so I had to test.
>It does not result in the script operating on all users that are not
>disabled. Instead, the script will operate on all users where intUAC is not
>514. This will include some disabled users who have other bits (flags) of
>the userAccountControl attribute set (like password never expires).
>
>I believe your clause is equivalent to:
>
>If (intUAC <> 514) And (intUAC And ADS_UF_ACCOUNTDISABLE <> 0) Then
>
>Which is exactly the same as:
>
>If (intUAC <> 514) Then
>
>In my domain, the script will not operate on the krbtgt account, since
>userAccountControl is 514. However, it will operate on the guest account
>where userAccountControl is 66082. 514 means:
>
>    account disabled
>    default account for typical user
>
>whereas 66082 means:
>
>    account disabled
>    no password required
>    default account for typical user
>    password does not expire
>
>The userAccountControl attribute is a "flag" attribute. It is an integer
>value that indicates the status of several flags. It is tested using bit
>masks, one bit mask for each setting. The proper way to test for a given
>setting is to AND the value of the attribute with the corresponding bit
>mask. Any non-zero result means the flag is set, a zero result means the
>flag is NOT set. You set a bit using the OR operator. If you OR the value
>with a bit mask, you set the corresponding flag. The XOR operator toggles
>the corresponding bit (from on to off, or from off to on). To unset a flag,
>you first must test if the bit is set (using the AND operator), then use the
>XOR operator to toggle the bit off. For example, to test if an account is
>disabled:
>
>Const ADS_UF_ACCOUNTDISABLE = &H02
>intUAC = objUser.userAccountControl
>If (intUAC And ADS_UF_ACCOUNTDISABLE <> 0) Then
>    ' The account is disabled.
>End If
>
>If (intUAC And ADS_UF_ACCOUNTDISABLE = 0) Then
>    ' The account is NOT disabled (the account is enabled).
>End If
>
>To disable an account:
>
>Const ADS_UF_ACCOUNTDISABLE = &H02
>intUAC = objUser.userAccountControl
>intUAC = intUAC Or ADS_UF_ACCOUNTDISABLE
>objUser.userAccountControl = intUAC
>objUser.SetInfo
>
>Finally, to enable an account:
>
>intUAC = objUser.userAccountControl
>If (intUAC And ADS_UF_ACCOUNTDISABLE <> 0) Then
>    intUAC = intUAC Xor ADS_UF_ACCOUNTDISABLE
>    objUser.userAccountControl = intUAC
>    objUser.SetInfo
>End If
>
>One source of confusion is that the AND operator has two meanings. It can
>mean the bitwise And'ing of two values, or it can mean the combining of two
>conditional clauses so that both must be True for the whole to be True.
>Remember also that in VBScript 0 is False, anything else is True.
>
>--
>Richard Mueller
>MVP Directory Services
>Hilltop Lab - http://www.rlmueller.net