November 20th, 2008

Hey, Scripting Guy! How Can I Find Locked-Out Accounts?

Hey, Scripting Guy! Question

Hey, Scripting Guy! I know we probably should not do this, but we have account lockout set at work. If a user types in too many bad passwords, they are locked out forever. It requires a call to the help desk to have their account unlocked. The problem is that some users who are shall we say “less motivated” simply refuse to work. They say it is a network problem, and they do not call the help desk. If the boss says anything to them, they say the network is not working, and then he calls. We need a script that will list all the locked-out user accounts in our domain. Can this be done?

– TB

SpacerHey, Scripting Guy! Answer

Hi TB,

You know the danger of account lockout don’t you? It makes for a very easy Denial of Service (DOS) attack. Earlier this year we released the Windows 2008 Security Guide (available for download or online browsing). In it we recommend increasing the lockout threshold and setting moderate lockout duration. Then you monitor for suspicious activity. The idea is the lockout duration should be long enough to frustrate script kitties, but not network administrators. You should also read this series of articles about passwords and pass phrases. In the first two articles, Jesper Johansson talks about password strategies. In the last article, he talks about password policies which include, of course, account lockout policies. The articles make for interesting reading, and should frame an informed review of one’s security policies.

By the way, here is a picture of a script kitty I took while visiting theWoodland Park Zoo in Seattle, Washington, in the United States. We’ll call him Get-Aslan:

Image of script kitty

 

To search for locked-out user accounts, you need to first query Active Directory Directory Services (AD DS) for user accounts. Then go through the user accounts querying the IsAccountLocked property, and print out the distinguishedName attribute of the user. Here is a VBScript script that accomplishes a similar task . Here is the script written in Windows PowerShell (if you are unfamiliar with Windows PowerShell, you may want to check out our Windows PowerShell Owner’s Manual):

$adsiSearcher = New-Object DirectoryServices.DirectorySearcher("LDAP://rootdse")
$adsiSearcher.filter = "ObjectCategory=User"
$adsiSearcher.findAll() | 
ForEach-Object `
 -Begin `
  { 
   "Locating locked out User accounts ..." 
   $UserCount = 0
  } `
 -Process `
  {
   If( ([adsi]$_.path).psbase.invokeGet("IsAccountLocked") )
     {
      ([adsi]$_.path).DistinguishedName + " is locked out"
       $UserCount ++
     }
  } `
 -End `
  {
   "There were $userCount locked out User Accounts."
  }

The script begins by creating an instance of the DirectoryServices.DirectorySearcher .NET Framework class. We use the New-Object cmdlet to create the DirectorySearcher. This allows us to search AD DS. Our constructor tells the DirectorySearcher we wish to search rootdse using the LDAP protocol.

Keep in mind that LDAP must be in all caps. It is one of the few things that is case sensitive:

$adsiSearcher = New-Object DirectoryServices.DirectorySearcher("LDAP://rootdse")

Next we specify the filter to use with the DirectorySearcher. We use ObjectCategory, which is the name of an attribute in AD DS, and we filter out if the ObjectCategory has a value of user. This is seen here:

$adsiSearcher.filter = "ObjectCategory=User"

We use the findall method to return all the user objects, and then we pipeline the user objects to the Foreach-Object cmdlet. This is seen here:

$adsiSearcher.findAll() |

The ForEach-Object allows us to work through all the user objects as they come across the pipeline. We use the backtick to continue the command to the next line:

ForEach-Object `

We begin by specifying an action for the -begin parameter. This code will be executed once within the entire ForEach-Object cmdlet. We print out a message that says “Locating locked out User accounts,” and we initialize the $userCount variable to 0. This is seen here:

-Begin `
{ 
   "Locating locked out User accounts ..." 
   $UserCount = 0
  } `

The process parameter is used to perform an action on each object that comes across the pipeline. We use the [adsi] type accelerator and give it the path of the SearchResult object. This gives us a DirectoryEntry object. We use the psbase property to gain access to the invokeGet method, which retrieves the IsAccountLocked property. If this value is true, we :

-Process `
  {
   If( ([adsi]$_.path).psbase.invokeGet("IsAccountLocked") )
     {
      ([adsi]$_.path).DistinguishedName + " is locked out"
       $UserCount ++
     }
  } `

The ending of our script prints out the count of the number of locked-out accounts. This is seen here:

-End `
  {
   "There were $userCount locked out User Accounts."
  }

That’s it. See you tomorrow for Quick-Hits Friday. Peace! Oh, by the way, if you are in Seattle, Washington, stop by and say hi to the script kitty. Here’s all the information you need.

Ed Wilson and Craig Liebendorfer, Scripting Guys

Author

0 comments

Discussion are closed.