How to list locked accounts in Active Directory (using powershell)

Envoyer Imprimer PDF




What’s an account lockout policy?

I’m not here to explain you what’s an account lockout policy but, for a better understanding, I think is not a bad idea to give you a short reminder.

An account lockout policy is a way to lock an account after a number of failed logon attempts and how it is managed by the system.

By default, to define an account lockout policy, you have to manipulate two specific attributes at your domain level:

  • LockoutThreshold: the account lockout threshold is the attribute which determine the number of failed logon attempts you have before the account is locked. If the value is defined to 0, there is not account lockout policy…
  • LockoutDuration: the account lockout duration determine the time that the account remains locked. If the value is defined to 0, the account is not unlocked automatically.

Notes: There are some others attributes but we won’t talk about them in this article.

However, since Windows Server 2008, you can have also multiple account lockout policies with the Fine-Grained Password Policy feature. So we have to count on them.

Last important information is how the information of the lockout of an account is replicated within your domain. It is based on Active Directory urgent replication on a Windows Server 2003 Native domain ( The information is updated directly on the PDC Emulator and replicated urgently on all the domain controllers.



The process to identify a locked account

Before I start to explain in detail how to proceed, I would clarify something. To identify the locked accounts, I tried in first to use the userAccountControl attribute has the flag ADS_UF_LOCKOUT ( With this flag I thought I was able to list all locked out accounts. Unfortunately, it is totally useless with the ADSI LDAP Provider (

Now let start. To give a better approach and to explain how to proceed, I have made the process flow diagram below:


No clear enough? Ok… let’s explain each step:

  • Step 1 - Connect to the PDC emulator: The PDC Emulator is the most relevant domain controller for retrieving locked accounts.
  • Step 2 - Identify the domain functional level: In first, the functional level will determine if Password Settings objects are eventually used in the current domain (greater or equal to Windows Server 2008). The second need is concerning the method used to identify locked accounts (Step 5). The constructed attribute “MS-DS-User-Account-Control-Computed” ( has been introduced in with Windows Server 2003.
  • Step 3 - Collect account lockout policies: the domain account lockout policy and the PSOs.
  • Step 4 - Validate the existence of one account lockout policy at least: if there is not account lockout policy, there is no needs to identify if an account is locked.
  • Step 5 – Determine the method used to identify locked accounts: we have two methods to identify the locked accounts. The choice between these methods will be based on the configuration of your domain. If you are not using PSO objects, we will simply use the user attribute lockoutTime and the domain attribute lockoutDuration. If you have PSOs objects, we will use the constructed attribute “MS-DS-User-Account-Control-Computed”.



Method one: computing the lockoutTime attribute

The lockoutTime attribute specifies the date and time (in UTC) when an account was locked. If the value of this attribute for one specific account is set to 0, the account is not locked. So this attribute is particularly helpful to collect all accounts which were locked! However, the attribute is not reset every time to 0 when an account is unlocked. It is especially the case when an account is unlocked automatically. The lockoutTime attribute will be reset only when the account is logged successfully at next logon.

The screenshots below show you an account unlocked automatically and its lockoutTime value different of 0.


In conclusion, to be sure that an account with a lockoutTime greater that 0 is locked or not, we have to compare the addition of the lockoutTime value and the lockoutDuration value with the current time. If the result is greater than the current time, the account is locked… However, the compute is only needed if the lockoutDuration is defined because if it is not the case, there is no automatically unlock process.

I’m enjoining you to consult the article “Find Locked Out Users” ( if you are looking for this type of script.

However, this method is particularly useful until you don’t use PSOs. If you are using Fine-Grained Password Policy, we have to identify what is the exact value of the lockoutDuration used for each account.


Method two: use the attribute MS-DS-User-Account-Control-Computed

This method is based on the attribute “MS-DS-User-Account-Control-Computed”. This attribute is replacing the userAccountControl for the flag ADS_UF_LOCKOUT.

This attribute is constructed and it cannot be returned in a query unless specified. We have to use the RefreshCache method to retrieve it. See the example below:

# sAMAccountName of the user
$sAMAccountName = "User-0"
$Attribute = "msds-user-account-control-computed"
$ADSearcher = New-Object System.DirectoryServices.DirectorySearcher
$ADSearcher.PageSize = 1000
$ADSearcher.Filter = "samaccountname=$sAMAccountName"
$User = $ADSearcher.FindOne()
# Use DirectoryEntry and RefreshCache method
$MyUser = $User.GetDirectoryEntry()
# Return the value of msds-user-account-control-computed
$UserAccountFlag = $MyUser.Properties[$Attribute].Value
if ( $UserAccountFlag -band $ADS_UF_LOCKOUT )
Write-host "Account $sAMAccountName is locked"

The biggest caveat of this method is the call of the RefreshCache method which is not really good in term of performance. Especially when you have to check thousands of accounts. But it is probably better than evaluate the Fine-Grained Password policy applied to your users…



The script

Now that I gave you a quick overview… Let see the script based on the process shown before.

You can download it from Microsoft Scripts center:

Mise à jour le Jeudi, 03 Octobre 2013 09:54