how to query AD to find locked out user accounts?

rated by 0 users
This post has 11 Replies | 2 Followers

Top 500 Contributor
Posts 6
blmuzzy Posted: 11-18-2008 2:50 PM

i found this code scrap on MS to list disabled accounts :

$strFilter = "(&(objectCategory=User)(userAccountControl:1.2.840.113556.1.4.803:=2))"

$objDomain = New-Object System.DirectoryServices.DirectoryEntry

$objSearcher = New-Object System.DirectoryServices.DirectorySearcher
$objSearcher.SearchRoot = $objDomain
$objSearcher.PageSize = 1000
$objSearcher.Filter = $strFilter

$colProplist = "name"
foreach ($i in $colPropList){$objSearcher.PropertiesToLoad.Add($i)}

$colResults = $objSearcher.FindAll()

foreach ($objResult in $colResults)
    {$objItem = $objResult.Properties; $objItem.name}

According to http://support.microsoft.com/kb/305144  "In a Windows Server 2003-based domain, LOCK_OUT and PASSWORD_EXPIRED have been replaced with a new attribute called ms-DS-User-Account-Control-Computed. For more information about this new attribute, visit the following Web site:

 
I tried unsuccessfully to substitute
msDS-User-Account-Control-Computed:1.2.840.113556.1.4.1460:=16
for userAccountControl:1.2.840.113556.1.4.803:=2
inthe code above.
according to http://msdn.microsoft.com/en-us/library/ms680832(VS.85).aspx the Attribute-ID of userAccountControl is 1.2.840.113556.1.4.8 and not 1.2.840.113556.1.4.803.  so I don't know what to use for msDS-User-Account-Control-Computed.
Anybody have any experience with this?
Thanks,
Bob
Top 10 Contributor
Posts 489
Microsoft MVP
Top Contributor

Change your filter to:

$objSearcher.Filter = "(&(objectClass=User)(lockoutTime>=1))"

 

The userAccountControl attribute is not of a much help when you want to find locked out users.

After a change your script should look like this (I've added | out-null when you load properties to omit output of "0"):

 

$objDomain = New-Object System.DirectoryServices.DirectoryEntry

$objSearcher = New-Object System.DirectoryServices.DirectorySearcher
$objSearcher.SearchRoot = $objDomain
$objSearcher.PageSize = 1000

$objSearcher.Filter = "(&(objectClass=User)(lockoutTime>=1))"

$colProplist = "name"
foreach ($i in $colPropList){$objSearcher.PropertiesToLoad.Add($i) | out-null}

$colResults = $objSearcher.FindAll()

foreach ($objResult in $colResults)
    {$objItem = $objResult.Properties; $objItem.name}

 

If you use Quest AD cmdlets, you can get the same result with this one-liner:

Get-QADUser -Locked -SizeLimit 0

 

-aleksandar

http://powershellers.blogspot.com

http://powershell.com/cs/blogs/aleksandar/default.aspx

Top 500 Contributor
Posts 6

Thanks for your reply.  I tried it and it returned 10 accounts, only 1 of which is actually locked out according to ADUC.   I tested one of the allegedly lockedout accounts and was able to logon successfully. 

according to MSDN, "2.372 Attribute lockoutTime  This attribute specifies the date and time (UTC) that this account was locked out. This value is stored as a large integer that represents the number of 100 nanosecond intervals since January 1, 1601 (UTC). A value of zero means that the account is not currently locked out."

So either those accounts were once lockedout and the value wasn't reset in AD when they were unlocked, or there's some other problem with my PC, AD in my domain, powershell, PowerShellPlus console, etc.

Bob

Top 10 Contributor
Posts 489
Microsoft MVP
Top Contributor

Have you set the lockoutDuration attribute of the domain object in your AD? This attribute specifies the amount of time an account is locked due to the Lockout-Threshold (a number of failed log on attempts) being exceeded. When the lockoutDuration "expires", the account is no longer locked out.

If the value of lockoutTime is 0, the account is not locked out. That's the logic behind that query filter. However, when the lockoutDuration expires, the value is not reset to 0 until the user successfully logs into the domain. That means that the above filter will also retrieve the accounts that are no longer locked out, but the user has not yet successfully logged in.

-aleksandar

http://powershellers.blogspot.com

http://powershell.com/cs/blogs/aleksandar/default.aspx

Top 500 Contributor
Posts 6

Yes, the lockout threshold is 5, the lockout duration is 30 minutes, and the "reset account lockout counter after" is 30 minutes. 

I re-ran the script about 2 hrs later, and my test user account showed as still locked out.  I logged on as the test user and re-ran the script.  This time the user was not on the lockedout list.  I would think that "reset account lockout counter after" would reset it to 0, but apparently not.

Top 500 Contributor
Posts 6

If you download the ActiveRoles Management Shell from Quest, all you need to do is:

get-qaduser -locked | format-table

This will provide you a listing of all user accounts that are locked out.

The add-in  is free and can be downloaded at:  http://www.quest.com/powershell/activeroles-server.aspx

Top 500 Contributor
Posts 6

Unfortunately, it returns the same, seemingly invalid, data that $objSearcher.Filter = "(&(objectClass=User)(lockoutTime>=1))" does, in this case users who may have been locked previously, but are not now, according to ADUC.   I'll see if I can try it on another domain.

Top 500 Contributor
Posts 6

Interesting.  I just tried some test accounts on one of our child domains (locked 'em out, ran the script / unlocked a few, ran the script) and it provided accurate results.

How is your Account Lockout Policy set up?

Account lockout duration...

Account lockout threshold...

Reset account lockout counter after...

 

Top 25 Contributor
Posts 209
Microsoft MVP
Top Contributor

did you consider replication/replication issues? Try and connect to different DCs in your environment to see if you get different results.

Top 500 Contributor
Posts 6

from above in the thread:

Yes, the lockout threshold is 5, the lockout duration is 30 minutes, and the "reset account lockout counter after" is 30 minutes.

 

 

Top 10 Contributor
Posts 489
Microsoft MVP
Top Contributor

LDAP filter "(&(objectClass=User)(lockoutTime>=1))" is not good enough, and if we don't want to bother with time math, ADS_UF_LOCKOUT flag is our only hope. :-) It seems that ADS_UF_LOCKOUT flag is not retrieved correctly through LDAP ADSI provider. Fortunately, WinNT provider could help to filter (really) locked out users.

 

$objDomain = New-Object System.DirectoryServices.DirectoryEntry

$objSearcher = New-Object System.DirectoryServices.DirectorySearcher
$objSearcher.SearchRoot = $objDomain
$objSearcher.PageSize = 1000

$objSearcher.Filter = "(&(objectClass=User)(lockoutTime>=1))"

$colProplist = "name","samaccountname"
foreach ($i in $colPropList){$objSearcher.PropertiesToLoad.Add($i) | out-null}

$colResults = $objSearcher.FindAll()

foreach ($objResult in $colResults) {

    $domainname = $objDomain.name
    $samaccountname = $objResult.Properties.samaccountname
 
    $user = [ADSI]"WinNT://$domainname/$samaccountname"
 
    $ADS_UF_LOCKOUT = 0x00000010
 
    if(($user.UserFlags.Value -band $ADS_UF_LOCKOUT) -eq $ADS_UF_LOCKOUT) {
        $objResult.Properties.name
    }
}

If you prefer Quest AD cmdlets, here is a function/filter that corrects buggy -locked parameter:

function IsLocked ([string]$samaccountname) {
     Process{
            $samaccountname = $_.samaccountname
            $ADS_UF_LOCKOUT = 0x00000010
            $user = [ADSI]"WinNT://$env:userdomain/$samaccountname"

            if(($user.userflags.value -band $ADS_UF_LOCKOUT) -eq $ADS_UF_LOCKOUT) {
                $_
            }
      }
}

Usage: Get-QADUser -locked -sizelimit 0 | IsLocked

 

-aleksandar

http://powershellers.blogspot.com

http://powershell.com/cs/blogs/aleksandar/default.aspx

Top 500 Contributor
Posts 6

Thanks, very impressive detective work!  I assume the LDAP ADSI provider written Microsoft, no?  Is it convenient to send this to their debug team?

In my tests, both of your suggested scripts worked correctly.

thanks again,

-Bob

 

Page 1 of 1 (12 items) | RSS
Copyright 2012 PowerShell.com. All rights reserved.