Discussion:
Accessing the IsAccountLocked with ADSI using C#.
(too old to reply)
Antonio Tortora
2004-01-07 19:46:57 UTC
Permalink
I am trying to read the status of the IsAccountLocked field in a user object
in the Active Directory. I am able to read the user object with the "WinNT"
Provider. The WinNT provider returns a collection of 24 items. I suspect
the field I want is contained within the UserFlags. How can I access the
Field IsAccountLocked and change it to False, so an account is no longer
locked.

Thank you.
Patrick
2004-01-07 21:53:33 UTC
Permalink
Private Sub Command6_Click()
Dim Container As IADsContainer
Dim User As IADsUser

Set Container = GetObject("WinNT://MyDomain")
Set User = Container.GetObject("user", "DoeJohn")

Debug.Print User.IsAccountLocked
User.AccountDisabled = False
User.SetInfo

Set User = Nothing
Set Container = Nothing
End Sub

Patrick
-----Original Message-----
I am trying to read the status of the IsAccountLocked
field in a user object
in the Active Directory. I am able to read the user
object with the "WinNT"
Provider. The WinNT provider returns a collection of 24
items. I suspect
the field I want is contained within the UserFlags.
How can I access the
Field IsAccountLocked and change it to False, so an
account is no longer
locked.
Thank you.
.
Tony Tortora
2004-01-07 22:02:27 UTC
Permalink
Patrick:

I appreciate you taking a look. I already know how to perform the operation
in VB. I'm trying to convert that code to C# and from what I can see it
does not work the same way.

Antonio
Post by Patrick
Private Sub Command6_Click()
Dim Container As IADsContainer
Dim User As IADsUser
Set Container = GetObject("WinNT://MyDomain")
Set User = Container.GetObject("user", "DoeJohn")
Debug.Print User.IsAccountLocked
User.AccountDisabled = False
User.SetInfo
Set User = Nothing
Set Container = Nothing
End Sub
Patrick
-----Original Message-----
I am trying to read the status of the IsAccountLocked
field in a user object
in the Active Directory. I am able to read the user
object with the "WinNT"
Provider. The WinNT provider returns a collection of 24
items. I suspect
the field I want is contained within the UserFlags.
How can I access the
Field IsAccountLocked and change it to False, so an
account is no longer
locked.
Thank you.
.
Marc Scheuner [MVP ADSI]
2004-01-08 07:53:19 UTC
Permalink
Post by Antonio Tortora
I am trying to read the status of the IsAccountLocked field in a user object
in the Active Directory. I am able to read the user object with the "WinNT"
Provider. The WinNT provider returns a collection of 24 items. I suspect
the field I want is contained within the UserFlags.
Yes, almost :-) The LDAP property is called "userAccountControl", and
contains a number of flags for the user object.

You get at it like so:

DirectoryEntry deUser = new
DirectoryEntry("LDAP://cn=Tony,cn=Users,dc=yourcompany,dc=com");

int iFlags = (int)deUser.Properties["userAccountControl"].Value;

Check out the ADS_USER_FLAG_ENUM enumeration in MSDN for the
individual values - there's one called ADS_UF_LOCKOUT = 0X0010

I'd highly recommend the "Quick List of C# Code Samples" in the
"System.DirectoryServices Programmer's Guide" on MSDN:

http://msdn.microsoft.com/library/en-us/sds/sds/quick_list_for_c__code_examples.asp

It shows nicely how to do a lot of common things from C#, using S.DS.

As for unlocking - as far as I remember, only resetting the flag in
userAccountControl didn't suffice - you also needed to reset the
"lockoutTime" flag to a value of 0 (if memory serves me correctly).

Marc
================================================================
Marc Scheuner May The Source Be With You!
Bern, Switzerland m.scheuner(at)inova.ch
Max L. Vaughn [MSFT]
2004-01-08 13:46:04 UTC
Permalink
What I do to unlock a user account with the LDAP provider is set the
lockouttime attribute to 0.

THe ADU&C uses this value to determine if the account is locked. If the
value is 0, then the account is not locked. If it has a value, it is
locked and the value represents the when the account is locked.

There has been a lot of discussion on how this mechanism is not always
accurate. The most consistant method of determining if a user account is
locked, is to use the WinNT provider and look a the
IADsUser::IsAccountLocked attribute.

To use the IADsUser::IsAccountLocked attribute, I would com interopt the
IADsUser interface and call it directly from C#, using the
DirectoryEntry.NativeObject to set my reference to IADsUser.


Sincerely,
Max Vaughn [MS]
Microsoft Developer Support


Disclaimer: This posting is provided "AS IS" with no warranties, and
confers no rights. You assume all risk for your use.
Tony Tortora
2004-01-08 17:18:23 UTC
Permalink
Marc:

I found that document last night and was checking it out this morning when I
saw your post. Everything I have found on MSDN states that LDAP is not
reliable in retrieving the IsAccountLocked status.

I created two basic users ADTest1 and ADTest2. I inspected both users and
the "userAccountControl" field is set to a value of 513. I locked the
ADTest2 user and the "userAccountControl" field still returns 513. I
located the ADTest2 object using the WinNT provider
"WinNT//mydomain/ADTest2" and the "UserFlags" field contains a value of 529.
I compared the "UserFlags" with both users and ADTest1 had a value of 513
and ADTest2 had a value 529. Bit 5 is a value of 16 and the math makes
sense. I tried to update the record with the WinNT Provider and I get an
unhandled exception error.

Antonio
Post by Marc Scheuner [MVP ADSI]
Post by Antonio Tortora
I am trying to read the status of the IsAccountLocked field in a user object
in the Active Directory. I am able to read the user object with the "WinNT"
Provider. The WinNT provider returns a collection of 24 items. I suspect
the field I want is contained within the UserFlags.
Yes, almost :-) The LDAP property is called "userAccountControl", and
contains a number of flags for the user object.
DirectoryEntry deUser = new
DirectoryEntry("LDAP://cn=Tony,cn=Users,dc=yourcompany,dc=com");
int iFlags = (int)deUser.Properties["userAccountControl"].Value;
Check out the ADS_USER_FLAG_ENUM enumeration in MSDN for the
individual values - there's one called ADS_UF_LOCKOUT = 0X0010
I'd highly recommend the "Quick List of C# Code Samples" in the
http://msdn.microsoft.com/library/en-us/sds/sds/quick_list_for_c__code_examples.asp
Post by Marc Scheuner [MVP ADSI]
It shows nicely how to do a lot of common things from C#, using S.DS.
As for unlocking - as far as I remember, only resetting the flag in
userAccountControl didn't suffice - you also needed to reset the
"lockoutTime" flag to a value of 0 (if memory serves me correctly).
Marc
================================================================
Marc Scheuner May The Source Be With You!
Bern, Switzerland m.scheuner(at)inova.ch
Richard Mueller [MVP]
2004-01-08 18:45:17 UTC
Permalink
Hi,

I am not familiar with C#, so I can't help there. However, it might help to
clarify some things.

The userAccountControl attribute exposed by LDAP cannot be used to determine
if an account is locked out. This is a known bug. It also cannot be used to
lock or unlock an account. The IsAccountLocked property method exposed by
LDAP can be used to lock or unlock an account, but fails to reveal whether
an account is locked or not.

The userFlags attribute exposed by the WinNT provider is reliable. Also, the
IsAccountLocked property method exposed by the WinNT provider works. This is
one of the few cases where it might be best to use WinNT.

The lockoutTime attribute exposed by the LDAP provider represents the time
when the account was locked out. It is Integer8 (a 64-bit number), so it
must be converted to a date. If the value is zero, then the account is not
locked out. However, if it has a value, this does not mean the account is
locked out. The lockoutTime attribute is not reset to zero until the user
logs on. If the domain lockoutTime policy has not expired, the account is
still locked out, otherwise, the account is not locked but the user has not
yet logged in. You must retrieve the domain lockoutDuration attribute, add
this to the user lockoutTime, and check if the result is before or after the
current date/time.

I have VBScript program that does all of this for a specified user linked on
the page below:

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

I assume the property methods are not available in C#, so you will be
dealing directly with the attributes. If so, the VBScript code may give you
a guide, as the underlying principals are the same. Also, Joe Richards has a
utility on his web site to find and handle locked accounts:

http://www.joeware.net

The real mystery is why the WinNT provider userFlags attribute and
IsAccountLocked property method seem to work.
--
Richard
Microsoft MVP Scripting and ADSI
HilltopLab web site - http://www.rlmueller.net
--
Post by Tony Tortora
I found that document last night and was checking it out this morning when I
saw your post. Everything I have found on MSDN states that LDAP is not
reliable in retrieving the IsAccountLocked status.
I created two basic users ADTest1 and ADTest2. I inspected both users and
the "userAccountControl" field is set to a value of 513. I locked the
ADTest2 user and the "userAccountControl" field still returns 513. I
located the ADTest2 object using the WinNT provider
"WinNT//mydomain/ADTest2" and the "UserFlags" field contains a value of 529.
I compared the "UserFlags" with both users and ADTest1 had a value of 513
and ADTest2 had a value 529. Bit 5 is a value of 16 and the math makes
sense. I tried to update the record with the WinNT Provider and I get an
unhandled exception error.
Antonio
Post by Marc Scheuner [MVP ADSI]
Post by Antonio Tortora
I am trying to read the status of the IsAccountLocked field in a user
object
Post by Marc Scheuner [MVP ADSI]
Post by Antonio Tortora
in the Active Directory. I am able to read the user object with the
"WinNT"
Post by Marc Scheuner [MVP ADSI]
Post by Antonio Tortora
Provider. The WinNT provider returns a collection of 24 items. I
suspect
Post by Marc Scheuner [MVP ADSI]
Post by Antonio Tortora
the field I want is contained within the UserFlags.
Yes, almost :-) The LDAP property is called "userAccountControl", and
contains a number of flags for the user object.
DirectoryEntry deUser = new
DirectoryEntry("LDAP://cn=Tony,cn=Users,dc=yourcompany,dc=com");
int iFlags = (int)deUser.Properties["userAccountControl"].Value;
Check out the ADS_USER_FLAG_ENUM enumeration in MSDN for the
individual values - there's one called ADS_UF_LOCKOUT = 0X0010
I'd highly recommend the "Quick List of C# Code Samples" in the
http://msdn.microsoft.com/library/en-us/sds/sds/quick_list_for_c__code_examples.asp
Post by Tony Tortora
Post by Marc Scheuner [MVP ADSI]
It shows nicely how to do a lot of common things from C#, using S.DS.
As for unlocking - as far as I remember, only resetting the flag in
userAccountControl didn't suffice - you also needed to reset the
"lockoutTime" flag to a value of 0 (if memory serves me correctly).
Marc
================================================================
Marc Scheuner May The Source Be With You!
Bern, Switzerland m.scheuner(at)inova.ch
Joe Kaplan (MVP - ADSI)
2004-01-08 19:12:55 UTC
Permalink
I can probably help translate Richard's sample to C# if you have trouble.

The only part that is tricky is pulling the INTEGER8 data from AD. It is
easy if you use the DirectorySearcher, but kind of a PITA if you use the
DirectoryEntry. DirectorySearcher marshals the data as an Int64, but
DirectoryEntry marshals the data as an IADsLargeInteger which you need to
pull the high and low integer parts from and reassemble into an Int64.

.NET has a very convenient method on the DateTime class that allows you to
take the Int64 value and convert it directly to a DateTime with the
FromFileTime method. Essentially, you just need to compare the lockout time
with the lockout duration for the domain and the current time on the domain.

Joe K.
Post by Richard Mueller [MVP]
Hi,
I am not familiar with C#, so I can't help there. However, it might help to
clarify some things.
The userAccountControl attribute exposed by LDAP cannot be used to determine
if an account is locked out. This is a known bug. It also cannot be used to
lock or unlock an account. The IsAccountLocked property method exposed by
LDAP can be used to lock or unlock an account, but fails to reveal whether
an account is locked or not.
The userFlags attribute exposed by the WinNT provider is reliable. Also, the
IsAccountLocked property method exposed by the WinNT provider works. This is
one of the few cases where it might be best to use WinNT.
The lockoutTime attribute exposed by the LDAP provider represents the time
when the account was locked out. It is Integer8 (a 64-bit number), so it
must be converted to a date. If the value is zero, then the account is not
locked out. However, if it has a value, this does not mean the account is
locked out. The lockoutTime attribute is not reset to zero until the user
logs on. If the domain lockoutTime policy has not expired, the account is
still locked out, otherwise, the account is not locked but the user has not
yet logged in. You must retrieve the domain lockoutDuration attribute, add
this to the user lockoutTime, and check if the result is before or after the
current date/time.
I have VBScript program that does all of this for a specified user linked on
http://www.rlmueller.net/IsUserLocked.htm
I assume the property methods are not available in C#, so you will be
dealing directly with the attributes. If so, the VBScript code may give you
a guide, as the underlying principals are the same. Also, Joe Richards has a
http://www.joeware.net
The real mystery is why the WinNT provider userFlags attribute and
IsAccountLocked property method seem to work.
--
Richard
Microsoft MVP Scripting and ADSI
HilltopLab web site - http://www.rlmueller.net
--
Post by Tony Tortora
I found that document last night and was checking it out this morning
when
Post by Richard Mueller [MVP]
I
Post by Tony Tortora
saw your post. Everything I have found on MSDN states that LDAP is not
reliable in retrieving the IsAccountLocked status.
I created two basic users ADTest1 and ADTest2. I inspected both users and
the "userAccountControl" field is set to a value of 513. I locked the
ADTest2 user and the "userAccountControl" field still returns 513. I
located the ADTest2 object using the WinNT provider
"WinNT//mydomain/ADTest2" and the "UserFlags" field contains a value of
529.
Post by Tony Tortora
I compared the "UserFlags" with both users and ADTest1 had a value of 513
and ADTest2 had a value 529. Bit 5 is a value of 16 and the math makes
sense. I tried to update the record with the WinNT Provider and I get an
unhandled exception error.
Antonio
Post by Marc Scheuner [MVP ADSI]
Post by Antonio Tortora
I am trying to read the status of the IsAccountLocked field in a user
object
Post by Marc Scheuner [MVP ADSI]
Post by Antonio Tortora
in the Active Directory. I am able to read the user object with the
"WinNT"
Post by Marc Scheuner [MVP ADSI]
Post by Antonio Tortora
Provider. The WinNT provider returns a collection of 24 items. I
suspect
Post by Marc Scheuner [MVP ADSI]
Post by Antonio Tortora
the field I want is contained within the UserFlags.
Yes, almost :-) The LDAP property is called "userAccountControl", and
contains a number of flags for the user object.
DirectoryEntry deUser = new
DirectoryEntry("LDAP://cn=Tony,cn=Users,dc=yourcompany,dc=com");
int iFlags = (int)deUser.Properties["userAccountControl"].Value;
Check out the ADS_USER_FLAG_ENUM enumeration in MSDN for the
individual values - there's one called ADS_UF_LOCKOUT = 0X0010
I'd highly recommend the "Quick List of C# Code Samples" in the
http://msdn.microsoft.com/library/en-us/sds/sds/quick_list_for_c__code_examples.asp
Post by Richard Mueller [MVP]
Post by Tony Tortora
Post by Marc Scheuner [MVP ADSI]
It shows nicely how to do a lot of common things from C#, using S.DS.
As for unlocking - as far as I remember, only resetting the flag in
userAccountControl didn't suffice - you also needed to reset the
"lockoutTime" flag to a value of 0 (if memory serves me correctly).
Marc
================================================================
Marc Scheuner May The Source Be With You!
Bern, Switzerland m.scheuner(at)inova.ch
Marc Scheuner [MVP ADSI]
2004-01-09 07:15:21 UTC
Permalink
Post by Joe Kaplan (MVP - ADSI)
The only part that is tricky is pulling the INTEGER8 data from AD. It is
easy if you use the DirectorySearcher, but kind of a PITA if you use the
DirectoryEntry. DirectorySearcher marshals the data as an Int64, but
DirectoryEntry marshals the data as an IADsLargeInteger which you need to
pull the high and low integer parts from and reassemble into an Int64.
Well, it's really not THAT bad - see this MSDN article on how to do it
in C#:

http://msdn.microsoft.com/library/default.asp?url=/library/en-us/sds/sds/large_integer_property_type.asp

Reading it is three lines of code - hardly "tricky" ;-)

Marc
================================================================
Marc Scheuner May The Source Be With You!
Bern, Switzerland m.scheuner(at)inova.ch
Joe Kaplan (MVP - ADSI)
2004-01-09 15:54:17 UTC
Permalink
Yeah, but you need the interop assembly and I can't even get the VB.NET
sample to compile. What is Machine.Shift.Right?I can't find that in the
framework anywhere! I'm pretty sure the samples are buggy. I think the
read sample is incorrect as well as it uses addition which will produce the
wrong value if the low part is negative.

Compared to how the results work with the searcher, it is more difficult and
much easier to get wrong. For the C# folks it isn't quite as bad, but still
annoyingly difficult and silly for a language that already supports 64 bit
integers! It is one of my biggest pet peaves.

Joe K.
Post by Marc Scheuner [MVP ADSI]
Post by Joe Kaplan (MVP - ADSI)
The only part that is tricky is pulling the INTEGER8 data from AD. It is
easy if you use the DirectorySearcher, but kind of a PITA if you use the
DirectoryEntry. DirectorySearcher marshals the data as an Int64, but
DirectoryEntry marshals the data as an IADsLargeInteger which you need to
pull the high and low integer parts from and reassemble into an Int64.
Well, it's really not THAT bad - see this MSDN article on how to do it
http://msdn.microsoft.com/library/default.asp?url=/library/en-us/sds/sds/large_integer_property_type.asp
Post by Marc Scheuner [MVP ADSI]
Reading it is three lines of code - hardly "tricky" ;-)
Marc
================================================================
Marc Scheuner May The Source Be With You!
Bern, Switzerland m.scheuner(at)inova.ch
Marc Scheuner [MVP ADSI]
2004-01-12 06:19:31 UTC
Permalink
Post by Joe Kaplan (MVP - ADSI)
Compared to how the results work with the searcher, it is more difficult and
much easier to get wrong. For the C# folks it isn't quite as bad, but still
annoyingly difficult and silly for a language that already supports 64 bit
integers! It is one of my biggest pet peaves.
Agreed !

Marc
================================================================
Marc Scheuner May The Source Be With You!
Bern, Switzerland m.scheuner(at)inova.ch

Loading...