Search This Blog

Monday, November 3, 2008

Use PowerShell to change Local Admin Passwords on Multiple Machines

Ran into an issue with the need to change the local administrator password on several servers.
Decided to try my hand with PowerShell to do the job.

After some research I found a few scripts that got me close, so I have done some tweaking and created a script that will:
Thanks to http://poshcode.org/567 and http://myitforum.com/cs2/blogs/yli628/archive/2007/08/23/powershell-script-to-change-administrator-password-on-a-list-of-machines.aspx for getting me on my way with this.
  • Use a text file list of machine names as input to the script
  • Create a randomly generated complex password for each machine
  • Ping the machine to verify it is online
  • Change the local admin password to the new complex password
  • Write all changes and passwords to an Excel file

I decided to have it write the passwords to an Excel File so I can easily import them into our Secret Server password management system.

Your milage may vary but this is what I needed:

Copy the below code into PowerGUI Script Editor (or your favorite editor) and it should format all the line breaks correctly.

---------------------------


#
# Script Name: Change Local Admin Passwords
# Version: 1.5
# Author: Andrew H. Bradley II
# Date: 11/3/08
#
# Description:
# Requires Microsoft Excel to be available on the machine running this script!
#
# This script will accept a list of machine names from c:\MachineList.txt
# Using that list it will ping each machine to verify it is active.
# Once verified it will use the credentials of the script to change the local Administrator account password.
# It will then open an Excel Spreadsheet and write the status of each MachineName and what it's password now is.
# All passwords are randomly generated - the random nature of the passwords can be controlled via the script in line 122
#
# Special Thanks to Ying Li at myITforum.com and to the PowerShell Code Repository for the Complex Password Function
# http://myitforum.com/cs2/blogs/yli628
# http://poshcode.org/567
#
# Functions
Function New-ComplexPassword ([int]$Length=8, $digits=$null, $alphaUpper=$null, $alphaLower=$null, $special=$null)
{
# ASCII data taken from http://msdn2.microsoft.com/en-us/library/60ecse8t(VS.80).aspx
# Make sure the password is long enough to meet complexity requirements
if($digits+$alphaUpper+$alphaLower+$special -gt $Length) { throw "Password too short for specified complexity" }
# Define character groups and the number of each required by passwords
# In case this is used in a DCPromo answer files, theres a few chars to
# avoid: Ampersand, Less than, double quote and back slash
# (34,38,60,92)
$groups = @()
$group = New-Object System.Object
Add-Member -In $group -Type NoteProperty -Name "Group" -Value "0123456789" # 48..57
Add-Member -In $group -Type NoteProperty -Name "Count" -Value $Digits
$groups += $group
$group = New-Object System.Object
Add-Member -In $group -Type NoteProperty -Name "Group" -Value "ABCDEFGHIJKLMNOPQRSTUVWXYZ" # 65..90
Add-Member -In $group -Type NoteProperty -Name "Count" -Value $alphaUpper
$groups += $group
$group = New-Object System.Object
Add-Member -In $group -Type NoteProperty -Name "Group" -Value "abcdefghijklmnopqrstuvwxyk" # 97..122
Add-Member -In $group -Type NoteProperty -Name "Count" -Value $alphaLower
$groups += $group
$group = New-Object System.Object
Add-Member -In $group -Type NoteProperty -Name "Group" -Value '~`!@#$%^&*()-_={}[]\;:"<>?,./'' ' # 32..47, 58..64, 91..96, 123..126
Add-Member -In $group -Type NoteProperty -Name "Count" -Value $special
$groups += $group
# initilize random number generator
$ran = New-Object Random
# make sure password meets complexity requirements
foreach ($req in $groups)
{
if ($req.count)
{
$charsAllowed += $req.group
for ($i=0; $i -lt $req.count; $i++)
{
$r = $ran.Next(0,$req.group.length)
$password += $req.group[$r]
}
} elseif ($req.count -eq 0) {
$charsAllowed += $req.group
}
}
# make sure password meets length requirement
if(!$charsAllowed)
{
$groups % { $charsAllowed += $_.group }
}
for($i=$password.length; $i -lt $length; $i++)
{
$r = $ran.Next(0,$charsAllowed.length)
$password += $charsAllowed[$r]
}
# randomize the password
return [string]::join('',($password.ToCharArray()sort {$ran.next()}))
}
# Main Program
# Open Excel Object
$a = New-Object -comobject Excel.Application
$a.visible = $True
# Create a new WorkBook/WorkSheet
$b = $a.Workbooks.Add()
$c = $b.Worksheets.Item(1)
# Create the Column Headers
$c.Cells.Item(1,1) = "Machine Name"
$c.Cells.Item(1,2) = "Password Changed"
$c.Cells.Item(1,3) = "Report Time Stamp"
$c.Cells.Item(1,4) = "Password"
# Format the Column Headers
$d = $c.UsedRange
$d.Interior.ColorIndex = 19
$d.Font.ColorIndex = 11
$d.Font.Bold = $True
# Setup first data row following headers
$intRow = 2
# Run this loop for every machine listed in the MachineList.txt file
foreach ($strComputer in get-content C:\MachineList.Txt)
{
$c.Cells.Item($intRow,1) = $strComputer.ToUpper()
#This is using WMI to ping the computers and return a status
$Reply = Gwmi Win32_PingStatus -Filter "Address = '$strComputer'" Select-Object StatusCode
if ($Reply.StatusCode -eq 0)
{
# Use ADSI to change the local administrator account's password
$admin=[adsi]("WinNT://" + $strComputer + "/administrator, user")
# Call the New-ComplexPassword Function to create a new random password
$adminpass=New-ComplexPassword 8 3 2 2 1
# Set the password to the local machine
$admin.SetPassword($adminpass)
# Write the results to the Excel Sheet
$c.Cells.Item($intRow,2).Interior.ColorIndex = 4
$c.Cells.Item($intRow,2) = "Yes"
$c.Cells.Item($intRow,3) = Get-Date
$c.Cells.Item($introw,4) = $adminpass
}
#If the ping reqest fails
Else
{
$c.Cells.Item($intRow,2).Interior.ColorIndex = 3
$c.Cells.Item($intRow,2) = "Not Pingable"
$c.Cells.Item($intRow,3) = Get-Date
}

# Clear the variables for the next loop and increment the row number
$Reply = ""
$adminpass = ""
$intRow = $intRow + 1
}
# Autofit the entire WorkSheet
$d.EntireColumn.AutoFit()
cls

10 comments:

Unknown said...

Dead simple. All I need. Thanks for that.

Unknown said...

I have problem with starting this script. I’m beginner with power shell.

Error is:

Unexpected token 'sort' in expression or statement.
At C:\scripts\test2.ps1:75 char:54
+ return [string]::join('',($password.ToCharArray()sort <<<< {$ran.next()}))
+ CategoryInfo : ParserError: (sort:String) [], ParseException
+ FullyQualifiedErrorId : UnexpectedToken



Can you help me pls?

Andrew Bradley II said...

That error "Unexpected token" is telling you that the word sort is not valid.

Please check to make sure that there are no extra spaces after the word sort.

Unknown said...

Line should read:

return [string]::join('',($password.ToCharArray()|sort {$ran.next()}))

Note the pipe symbol |

Unknown said...

Also for me the ping routine did not work so I changed it to .net:

Replace:
#This is using WMI to ping the computers and return a status
$Reply = Gwmi Win32_PingStatus -Filter "Address = '$strComputer'" Select-Object StatusCode
if ($Reply.StatusCode -eq 0)

With:
# Using .NET method to ping test the servers
$ping = new-object System.Net.NetworkInformation.Ping
$Reply = $ping.send($strComputer)
if($Reply.status -eq "success")

Dan Ra said...

Odd result for me. The spreadsheet generates a positive password change, and the password itself. Yet, the password doesn't work on the machine that the script was run on.

Any thoughts?

Andrew Bradley II said...

I can't say I have ever seen it fail where the return value was positive but the password did not take on the machine.

What is the Operating System of the target machine?
I have not tested this script against new 2008R2 edition machines yet.

Dan Ra said...

Hey Andrew, sorry for the extended, delayed response. The target (test) machine is Windows XP SP3. Any thoughts?

Ian the Atheist said...

Just a warning to other users coming in here - we have the same results as Dan Ra.

script says success, details saves in Excel, but alas, the password has been set to something else and we can't log into the local admin accounts...

Unknown said...

I too got the apparent success, but seemingly incorrect password. I noticed there was a permissions error so I ran it again with admin access and this time it went through OK, no errors, correct passwords.