Find locked out accounts in Active Directory (a way that actually works!)

I have googled how to list locked out accounts and found two methods so far, both of which don't work...

Saved query - (&(&(&(objectCategory=Person)(objectClass=User)(lockoutTime>=1))))

Lists a number of accounts, many of which are not locked out. If I unlock one that I happen to know is locked out, it still gets returned by the query.

Powershell command - Search-ADAccount -LockedOut

Does nothing.

So either - Am I doing something wrong? Or - Is there a method that actually works?


Solution 1:

I would not necessarily trust Get-ADUser -LDAPFilter "(&(objectCategory=Person)(objectClass=User)(lockoutTime>=1))" -Properties LockedOut, as it is not returning reliable results for me either, but then, I'm also unable to directly contact my PDCe at this time. For best results, you would want to directly target your PDC-emulator, as it always has the most up-to-date information on account lockouts throughout the domain.

That's what I am wagering that you're witnessing here is a delay in replication:

... account lockout is urgently replicated to the primary domain controller (PDC) emulator role owner and is then urgently replicated to the following:

• Domain controllers in the same domain that are located in the same site as the PDC emulator.

• Domain controllers in the same domain that are located in the same site as the domain controller that handled the account lockout.

• Domain controllers in the same domain that are located in sites that have been configured to allow change notification between sites (and, therefore, urgent replication) with the site that contains the PDC emulator or with the site where the account lockout was handled. These sites include any site that is included in the same site link as the site that contains the PDC emulator or in the same site link as the site that contains the domain controller that handled the account lockout.

In addition, when authentication fails at a domain controller other than the PDC emulator, the authentication is retried at the PDC emulator. For this reason, the PDC emulator locks the account before the domain controller that handled the failed-password attempt if the bad-password-attempt threshold is reached. For more information about how the PDC emulator role owner manages password changes and account lockouts, see "Managing Flexible Single-Master Operations" in this book.

So try Search-ADAccount -LockedOut -Server DC-PDCE and see if your results are any better.

Also, here's something else to consider when building queries around the lockoutTime attribute:

This attribute value is only reset when the account is logged onto successfully. This means that this value may be non zero, yet the account is not locked out. To accurately determine if the account is locked out, you must add the Lockout-Duration to this time and compare the result to the current time, accounting for local time zones and daylight savings time.

Edit: By way of reverse engineering Microsoft.ActiveDirectory.Management.dll, I can tell you that Search-ADAccount -LockedOut, which seems to me to produce pretty reliable results, runs the following code:

else if ((bool) this._paramSet.LockedOut)
      {
        list.Add(ADAccountFactory<ADAccount>.AttributeTable[cmdletSessionInfo.ConnectedADServerType]["AccountLockoutTime"].InvokeToSearcherConverter(ADOPathUtil.CreateFilterClause(ADOperator.Ge, "AccountLockoutTime", (object) 1), cmdletSessionInfo));
        this.OutputFilterFunction = new ADGetCmdletBase<SearchADAccountParameterSet, ADAccountFactory<ADAccount>, ADAccount>.OutputFilterDelegate(this.FilterIsLockedOut);
      }
      if (list.Count > 0)
        this.OutputSearchResults(list.Count != 1 ? ADOPathUtil.CreateAndClause(list.ToArray()) : list[0]);
      else
        this.OutputSearchResults((IADOPathNode) null);

So it appears that Search-ADAccount -LockedOut is looking at the AccountLockoutTime attribute too!

Edit some more for great justice: Richard Mueller, Dir. Services MVP, says this:

You cannot use the userAccountControl attribute to identify users that are locked out. There is a bit of userAccountControl documented for this, but it is not used.

I can verify this thusly:

PS C:\Users\ryan> $(Search-ADAccount -LockedOut).Count
11
PS C:\Users\ryan> $(Get-ADUser -LDAPFilter "(&(objectCategory=User)(userAccountControl:1.2.840.113556.1.4.803:=16))").Count
0

Finally, I'd like to end on this blog post on the topic, which explains why the lockoutTime>=1 is approaching the best solution, but that's only part of the story. You need to further filter down the list to include only the users where their lockoutTime is greater than $(your domain lockout duration) minutes in the past.