Prof. Powershell
The Old Local Admin
Short of learning .NET, here's a way to script something against the ADSI to find out some interesting data about the servers you're working with.
- By Jeffery Hicks
- 07/16/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 then 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 an 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 86,400:
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.