Thursday, April 23, 2009

Another Other Way to Reset Local Admin Passwords

I realized that, as usual, I was too focused on demonstrating a methodology that I overlooked the simplest of solutions to the problem being "solved". I am referring to my earlier post on "Another Way to Reset Local Passwords on Remote Computers"

Another way would be to meet the fully-baked process (pspasswd.exe) half-way with another semi-fully-baked process (a script to fetch the computer names and write them into a file). This was because of the amazing RTFM syndrome. I use RTFM all the time on others, so it's only fitting that I was bitten by it myself. In my case, it should be RTFMC, where "C" stands for "Carefully". Because I tend to rush when I'm stressed about something and that day I was stressed from idiot humans pretending to drive cars in rush hour. I'll say it again: Humans are incapable of driving machinery. It's a job for computers.

So, here goes. First we fetch the computer names from an AD query, then write them into an ASCII text file, one name per row. Then we call the pspasswd utility and provide the file input and let it do its thing. Rather than do this with the same old boring VBScript mindset, I wanted to spice this baby up a bit and toss in a Red Bull, a box of Viagra and some KiXtart coding, and "Bam!" let 'er rip.

First, the boring VBScript version...


Option Explicit
Const cmdStr = "pspasswd.exe"
Const strUser = "Administrator"
Const strPwd = "P@ssW0rd$123"
Const ADSI_DN = "mydomain.com"
Const inputFile = "computerlist.txt"
Const exclude = "SERVER1 SERVER2 COMPUTER3"

'----------------------------------------------------------------
' comment: do not change any code below this point!
'----------------------------------------------------------------

Wscript.Echo "info: starting processing: " & Now

Dim objShell, objX, objFSO, objFile, runCmd, objDom, strComputer
Set objFSO = CreateObject("Scripting.FileSystemObject")

Wscript.Echo "info: verifying pspasswd.exe exists..."
If objFSO.FileExists(cmdstr) Then
runCmd = cmdStr & " @" & inputFile & " " & strUser & _
" " & strPwd & " >pspasswd.log"
Set objShell = CreateObject("Wscript.Shell")
Set objDom = GetObject("WinNT://" & ADSI_DN)
Set objFile = objFSO.CreateTextFile(inputFile, True)

Wscript.Echo "info: querying computer names from active directory..."

For each objX in objDom
If Lcase(objX.Class) = "computer" Then
strComputer = Ucase(objX.Name)
If InStr(1, exclude, strComputer) <> 0 Then
Wscript.Echo "info: exluding = " & strComputer
Else
Wscript.Echo "info: computername = " & strComputer
objFile.WriteLine(strComputer)
End If
End If
Next
objFile.Close
Set objFile = Nothing
Wscript.Echo "info: finished building input file"
Wscript.Echo "info: runCmd = " & runCmd
objShell.Run "%COMSPEC% /c " & runCmd, 1, True
Set objShell = Nothing
Else
Wscript.Echo "error: pspasswd.exe not found"
End If
Set objFSO = Nothing
Wscript.Echo "info: completed processing: " & Now



Now, as long as you put the script in the same folder as pspasswd.exe, and you run the script using an account that has admin rights on all the remote computers, and they're all online and accessible, it should work fine. You may notice I spruced it up a little with a few lines of code and a spritz of air freshener.

Now for the more interesting KiXtart version...


break on

$cmdStr = "s:\utils\sysinternals\pspasswd.exe"
$strUser = "Administrator"
$strPwd = "P@@ssW0rd$$123"
$ADSI_DN = "mydomain.com"
$inputFile = "computerlist.txt"
$exclude = "SERVER1 SERVER2 COMPUTER3"

;----------------------------------------------------------------
; comment: do not change any code below this point!
;----------------------------------------------------------------

? "info: starting processing: "+@date+" "+@time

Dim $objX, $runCmd, $objDom, $strComputer

? "info: verifying pspasswd.exe exists..."
If Exist($cmdstr)
$runCmd = "$cmdStr @@$inputFile $strUser $strPwd >pspasswd.log"
If Open(1, $inputFile, 5) = 0
? "info: querying computer names from active directory..."
$objDom = GetObject("WinNT://$ADSI_DN")
For each $objX in $objDom
If Lcase($objX.Class) = "computer"
$strComputer = Ucase($objX.Name)
If InStr($exclude, $strComputer) > 0
? "info: exluding = "+$strComputer
Else
? "info: computername = "+$strComputer
$=WriteLine(1, $strComputer+@CRLF)
EndIf
EndIf
Next
Close(1)
? "info: finished building input file"
? "info: runCmd = "+$runCmd
;Shell "%COMSPEC% /c "+$runCmd
EndIf
Else
? "error: pspasswd.exe not found"
EndIf
? "info: completed processing: "+@date+" "+@time


Not radically different really. However, you may notice some easier handling of checking for files, opening and writing to files, and executing shell processes. It also shows how you can leverage in-line variable expansion within strings to eliminate explicit concatenation; not always, but more often than not. An interesting (and important) aspect of this feature is to be careful of escaping special characters within strings to avoid confusion during processing. This is why you see doubled up "@" and "$" entries in some of the strings.
Post a Comment