Prof. Powershell
Ye Olde Local Admin
Use PowerShell to find the password age of a local admin account.
- By Jeffery Hicks
- 06/11/2008
PowerShell supports many technologies you are probably familiar with, especially if you have used other scripting languages like VBScript. Let me show you how to use PowerShell and ADSI to find out the age of a local administrator's password and some other information you may find useful.
PowerShell's support of ADSI is based on the underlying .NET System.DirectoryServices namespace. Don't worry; I'm not going to force you to learn .NET. We'll use the [ADSI] type accelerator, which gives PowerShell a hint about what we're trying to do. It will handle the rest. Try an expression like this in PowerShell (the WinNT provider is case-sensitive):
PS C:\> [ADSI]$admin="WinNT://MYCOMPUTER/administrator"
The $admin variable now contains and ADSI object for the administrator account on MYCOMPUTER. Take a look at it:
PS C:\> $admin | select *
UserFlags : {66049}
MaxStorage : {-1}
PasswordAge : {3384031}
PasswordExpired : {0}
LoginHours : {255 255 255 255 255 255 255 255
FullName : {}
Description : {Built-in administration account
BadPasswordAttempts : {0}
LastLogin : {4/2/2008 1:51:22 PM}
HomeDirectory : {}
LoginScript : {}
Profile : {}
HomeDirDrive : {}
Parameters : {}
PrimaryGroupID : {513}
Name : {Administrator}
MinPasswordLength : {0}
MaxPasswordAge : {3628800}
MinPasswordAge : {0}
PasswordHistoryLength : {0}
AutoUnlockInterval : {1800}
LockoutObservationInterval : {1800}
MaxBadPasswordsAllowed : {0}
objectSid : {1 5 0 0 0 0 0 5 21 0 0 0 32 71 2
Even looking at this raw list you can make sense of it, except maybe Password age:
PS C:\> $admin.passwordage
3384031
That value is the number of seconds since the password was last set. To get the age in days, I can divide it by 86400:
PS C:\> [int]($admin.passwordage[0]/86400)
39
Because of the way PowerShell adapts the underlying class, the password age property is returned as a collection, so [0] indicates the first (and only) value. I'm also casting the result as an integer using [int] to round the result.
You're probably wondering about all the servers or desktops you want to check. I'll cut to the chase. Put the names of all the computers you want to check into a file like servers.txt and then use an expression like this:
Get-content servers.txt | foreach {
[ADSI]"WinNT://$_/Administrator" | select `
@{Name="Account";Expression={($_.PSBase).Path}},`
@{Name="PasswordSet";Expression={(Get-Date).AddSeconds(-($_.PasswordAge)[0])}},`
@{Name="PasswordAge (Days)";Expression={[int](($_.PasswordAge)[0]/86400) }},`
@{Name="Last Logon";Expression={$_.LastLogin}},`
@{Name="Days since last login";Expression={`
(New-TimeSpan -start ($_.LastLogin[0]) -end (Get-Date)).days}}}
Each server will be piped to ForEach, which will get the Administrator account on the computer. This object is then piped to Select-Object, which creates some custom properties. You should get a result like this for each server:
Account : WinNT://FILE03/Administrator
PasswordSet : 3/18/2008 2:04:31 PM
PasswordAge (Days) : 39
Last Logon : 4/2/2008 1:51:22 PM
Days since last login : 24
If you'd like, pipe the entire output to Export-CSV and open it in Microsoft Excel for further analysis:
Get-content servers.txt | foreach {
[ADSI]"WinNT://$_/Administrator" | select `
@{Name="Account";Expression={($_.PSBase).Path}},`
@{Name="PasswordSet";Expression={(Get-Date).AddSeconds(-($_.PasswordAge)[0])}},`
@{Name="PasswordAge (Days)";Expression={[int](($_.PasswordAge)[0]/86400) }},`
@{Name="Last Logon";Expression={$_.LastLogin}},`
@{Name="Days since last login";Expression={`
(New-TimeSpan -start ($_.LastLogin[0]) -end (Get-Date)).days}}} `
| export-csv "c:\adminage.csv" -notypeinformation
A few last notes: You'll need to have admin rights on all the servers. There is no support for alternate credentials. If you have a lot of servers, I'd break them up into smaller groups of, say, 10 or so to keep performance from tanking.
About the Author
Jeffery Hicks is an IT veteran with over 25 years of experience, much of it spent as an IT infrastructure consultant specializing in Microsoft server technologies with an emphasis in automation and efficiency. He is a multi-year recipient of the Microsoft MVP Award in Windows PowerShell. He works today as an independent author, trainer and consultant. Jeff has written for numerous online sites and print publications, is a contributing editor at Petri.com, and a frequent speaker at technology conferences and user groups.