Summary: Guest blogger and Microsoft PFE Jason Walker talks about using Windows PowerShell to find a locked-out user’s location.
Microsoft Scripting Guy, Ed Wilson, is here. Today, we have a guest blog post written by Microsoft Premier Field Engineer (PFE) Jason Walker. Jason has written a number of extremely popular Hey, Scripting Guy! blog posts and today’s article is no exception.
Finding a locked-out user’s location
Have you ever been asked to unlock a user account, and then five minutes later, asked again to unlock the same account? Or, maybe you have changed the password for a service account, and you’re not sure what server needs the new credentials. Even better, have you ever had a virus outbreak where thousands of accounts were locked out, and you had to find out what machines were producing all the failed logon attempts? I have …
There are basically two ways of troubleshooting locked-out accounts. You can chase the events that are logged when a failed logon occurs. The events that are logged vary depending on the how auditing is configured in your environment. However, an easier way is to wait until the account is locked out.
All failed logon attempts get forwarded to the PDC Emulator (PDC) in the domain. Like I said earlier, the events that get logged depend on how auditing is configured. What is consistent is the event number that gets logged when the account is locked out. In an environment with domain controllers running Windows Server 2008 or later, when an account is locked out, a 4740 event is logged in the Security log on the PDC of your domain. With the 4740 event, the source of the failed logon attempt is documented. Here is an example of this taken from my lab:
In the above example, you can see the user BrWilliams was locked out and the last failed logon attempt came from computer WIN7. So, really all we need to do is write a script that will:
- Find the domain controller that holds the PDC role.
- Query the Security logs for 4740 events.
- Filter those events for the user in question.
Doesn’t sound too bad.
Here is the script in action.
I wrote the script to contact all the domain controllers in the domain to display the LastBadPasswordAttempt timestamp, if present. If there are recent bad password attempts across all domain controllers, it could be a sign of a virus or something on a larger scale. This data isn’t truly needed to find the locked-out location. Additionally, it adds time to the script’s completion because this attribute isn’t replicated. This requires contact with every domain controller. However, I thought it could be helpful in troubleshooting. The second set of information displayed is the 4740s from the PDC for the user in question sorted by the time the event was created in descending order.
Here is an example of how we get all the domain controllers in a domain, and then query the individual domain controllers for a user’s attributes:
$DomainControllers = Get-ADDomainController -Filter *
Foreach($DC in $DomainControllers)
Get-ADUser -Identity brwilliams -Server $DC.Hostname `
Notice I used the Properties parameter and specified only the properties I care about. I see admins use –Properties * and it makes me cringe. When you use the wildcard, all the user’s 140+ attributes are sent across the wire. This adds unnecessary time to the script. In a small environment with 3 domain controllers this might not matter that much, but in a larger domain with 15 domain controllers I guarantee you will see a performance degradation.
Now let’s see how to get the 4740s off the PDC Emulator.
By using the Get-WinEvent cmdlet, I easily create a filter that will quickly bring back all the 4740 events.
Now, let’s look closely at one event by piping it to a Format-List.
The Message note property has everything we need to script finding the lock-out location, but the property is a string and will take some coding to get what we need. The hidden gem here is the property name Properties. Let’s take a look.
Here we have the user name, computer name, and SID of the user. Each value being a separate entry in an array. Very cool, and very easy to work with.
Once we have all the 4740s, we filter for the user being locked out, and then display the second entry in the properties array. This ends up being the computer where the failed user logon attempt came from.
A few things to take note of:
- After you have the locked-out location, there is still some troubleshooting to do. You still have to figure out what what machine is creating the failed logon attempts. Is it a service account whose password was changed and needs to be updated on a service or scheduled task? I think the most common scenario is a user has logged on to a machine, never logged out, and has since changed their password.
- In a production environment, the security logs on the PDC Emulator get rolled every 24-48 hours. The sooner you can start troubleshooting the better.
- This script is dependent on the PDC running Windows Server 2008 or later. Get-WinEvent is not compatible with Windows Server 2003 and a domain controller running this operating system version logs a 644 event, not a 4740 when a user account is locked out.
- The ActiveDirectory module is used in the script, which requires the Active Directory Web Services to be running on a domain controller.
I hope this blog post helps you better troubleshoot locked-out accounts and that you picked up some other tips I mentioned.
You can download the script from the script repository.
Thank you, Jason, for a very useful article.
Join me tomorrow when we will have a guest blog written by Steffan Stranger.
I invite you to follow me on Twitter and Facebook. If you have any questions, send email to me at firstname.lastname@example.org, or post your questions on the Official Scripting Guys Forum. See you tomorrow. Until then, peace.
Ed Wilson, Microsoft Scripting Guy