Hi all,
I have a script I've put together that will ping all of the servers in our domain, and change the local administrators password on each of the servers that are pingable. There are two parts, part 1 is the ping section. Part 2 is the section that changes all of the passwords. I'm using text files to store the results of the pings, then opening them in part 2 to change the passwords. I want to have the sections separated. I ran the script last night, and noticed as the pings started an error message popped up saying server is busy switch application, or something to that effect. I think what's happening is the program is not waiting for ping to finish before changing the passwords. It works great if I do each one of the sections separately. My question is how do I make part 2 wait until part 1 is completely finished? Here's the script.
I have a script I've put together that will ping all of the servers in our domain, and change the local administrators password on each of the servers that are pingable. There are two parts, part 1 is the ping section. Part 2 is the section that changes all of the passwords. I'm using text files to store the results of the pings, then opening them in part 2 to change the passwords. I want to have the sections separated. I ran the script last night, and noticed as the pings started an error message popped up saying server is busy switch application, or something to that effect. I think what's happening is the program is not waiting for ping to finish before changing the passwords. It works great if I do each one of the sections separately. My question is how do I make part 2 wait until part 1 is completely finished? Here's the script.
Code:
'==========================================================================
'
' NAME: Reset Local Admin Password.vbs
'
' AUTHOR: Gene Magerr
' EMAIL: genemagerr@hotmail.com
'
' DESCRIPTION: This script has two parts. First, it will query Active
' Directory for all servers in the Domain via ping requests.
' It will create the directory C:\PWChangeLogs
' Four text files will be created in that directory,
' PingSuccess.txt, PingFail.txt, PWSuccess.txt and PWFailed.txt
' Successful pings are written to PingSuccess.txt, failed pings are
' writtent to PingFail.txt.
'
' The second part of the script opens and reads PingSuccess.txt into
' an array. it then connects to each of the servers in the array, and
' get's the local administrators account by SID, in case someone renamed
' the account to something other than administrator.
'
' The script then generates a random 16 character password of UPPER, lower,
' numeric and special characters (you can change the length in the function)
' and sets that as the new administrators password. The Date of the change,
' the administrators account name (as it is on the server), and the new
' password are all written to PWSuccess.txt. Any password failures are
' written to PWFail.txt
'
' VERSION HISTORY:
' 1.0 01/17/2008 Initial release
' 1.1 01/04/2010 Completely rewrote the script. Initially it was just
' changing passwords from an already generated server
' list. Now it does everything.
'
' REQUIREMENTS: Must run as a domain Administrator
'
' You have a royalty-free right to use, modify, reproduce, and
' distribute this script file in any way you find useful, provided that
' you agree that the creator, owner above has no warranty, obligations,
' or liability for such use.
'
'==========================================================================
Option Explicit
On Error Resume Next
'==========================================================================
' VARIABLE DECLARATIONS
'==========================================================================
Dim objShell, objNetwork, objFSO, TestMode
Set objShell = CreateObject("WScript.Shell")
Set objNetwork = WScript.CreateObject("WScript.Network")
Set objFSO = CreateObject("Scripting.FilesystemObject")
'==========================================================================
' STATIC VARIABLE ASSIGNMENTS
'==========================================================================
Const FOR_READING = 1, FOR_WRITING = 2, FOR_APPENDING = 8
'==========================================================================
' MAIN SCRIPT CODE
'==========================================================================
Dim objRootDSE, strDNSDomain, objConnection, objCommand, strQuery
Dim objRecordSet, strComputerDN, strOS, strSuccess, strFail
Dim objFailed, objSuccess, strTextFile, strComputer, arrComputers
Dim objUser, objUsers, AdminName, adminPassword
'==========================================================================
' PART 1 - Ping all of the servers in the domain. Write the successful
' pings to a text file called PingSuccess.txt, and the failed pings
' to a text file called PingFail.txt. We can then determine if the servers
' in the PingFail.txt file are still in service, or just shut down.
'==========================================================================
'Determine DNS domain name from RootDSE object.
'==========================================================================
Set objRootDSE = GetObject("LDAP://RootDSE")
strDNSDomain = objRootDSE.Get("defaultNamingContext")
'==========================================================================
'Use ADO to search Active Directory for all computers.
'==========================================================================
Set objCommand = CreateObject("ADODB.Command")
Set objConnection = CreateObject("ADODB.Connection")
objConnection.Provider = "ADsDSOObject"
objConnection.Open "Active Directory Provider"
objCommand.ActiveConnection = objConnection
'==========================================================================
'Will query all servers that are not domain controllers
'[URL unfurl="true"]http://www.rlmueller.net/ADOSearchTips.htm[/URL]
'==========================================================================
strQuery = "<LDAP://" & strDNSDomain & ">;(&(objectCategory=computer)(!(userAccountControl:1.2.840.113556.1.4.803:=8192)));name,operatingSystem;subtree"
objCommand.CommandText = strQuery
objCommand.Properties("Page Size") = 100
objCommand.Properties("Timeout") = 30
objCommand.Properties("Cache Results") = False
Set objRecordSet = objCommand.Execute
If Not objFSO.FolderExists("C:\PWChangeLogs") Then
objFSO.CreateFolder("C:\PWChangeLogs")
End If
If Not objFSO.FileExists("C:\PWChangeLogs\PingSuccess.txt") Then
objFSO.CreateTextFile("C:\PWChangeLogs\PingSuccess.txt")
End If
If Not objFSO.FileExists("C:\PWChangeLogs\PingFail.txt") Then
objFSO.CreateTextFile("C:\PWChangeLogs\PingFail.txt")
End If
Set strSuccess = objFSO.OpenTextFile("C:\PWChangeLogs\PingSuccess.txt", 2)
Set strFail = objFSO.OpenTextFile("C:\PWChangeLogs\PingFail.txt", 2)
'==========================================================================
'Enumerate computer objects with server operating systems.
'strQuery above, constructs the LDAP query to exclude domain controllers.
'==========================================================================
Do Until objRecordSet.EOF
strOS = objRecordSet.Fields("operatingSystem")
If InStr(UCase(strOS), "SERVER") > 0 Then
strComputerDN = objRecordSet.Fields("name")
If Ping(strComputerDN) Then
strSuccess.WriteLine strComputerDN
Else
strFail.WriteLine strComputerDN
End If
End If
objRecordSet.MoveNext
Loop
'Clean up.
objConnection.Close
strSuccess.Close
strFail.Close
Set objRootDSE = Nothing
Set objCommand = Nothing
Set objConnection = Nothing
Set objRecordSet = Nothing
objShell.Popup "Finished Pinging Computers, box will close in 5 seconds.", 5, "Part 1 Complete."
'==========================================================================
' PART 2 - Change The Local Administrators Password
' Here we will open the PingSuccess.txt file and read in all of the server
' names. Then we will connect to each server and change the Local
' Administrators password. We will ten write the Time, Server Name,
' Administrator account name and the new password to a text file as a
' reference for the new passwords, as each server will get a randomly
' generated uniqie password.
'==========================================================================
If objFSO.FileExists("C:\PWChangeLogs\PWFailed.txt") Then
objFSO.DeleteFile("C:\PWChangeLogs\PWFailed.txt")
End If
If objFSO.FileExists("C:\PWChangeLogs\PWSuccess.csv") Then
objFSO.DeleteFile("C:\PWChangeLogs\PWSuccess.csv")
End If
Set objFailed = objFSO.CreateTextFile("C:\PWChangeLogs\PWFailed.txt")
Set objSuccess = objFSO.CreateTextFile("C:\PWChangeLogs\PWSuccess.csv")
'==========================================================================
'Open the data file
'==========================================================================
Set strTextFile = objFSO.OpenTextFile("C:\PWChangeLogs\PingSuccess.txt", 1)
arrComputers = Split(strTextFile.ReadAll, vbNewLine)
strTextFile.Close
For Each strComputer In arrComputers
'If Ping(strComputer) Then
Set objUsers = GetObject("winmgmts:{impersonationLevel=impersonate}!//" & strComputer & "/root/cimv2").ExecQuery( _
"Select Name, SID from Win32_UserAccount WHERE Domain = '" & strComputer & "'")
For Each objUser In objUsers
If Left(objUser.SID, 9) = "S-1-5-21-" And Right(objUser.SID, 4) = "-500" Then
AdminName = objUser.Name
Exit For
End If
Next
'==========================================================================
'Connect to Administrator acccount on server using WinNT provider
'==========================================================================
Set objUser = GetObject("WinNT://" & strComputer & "/" & AdminName & ",user")
'==========================================================================
'Change the password
'==========================================================================
adminPassword = RandomString()
objUser.SetPassword adminPassword
objUser.SetInfo ' Save Changes
'==========================================================================
'Check if we connected to the user object successfully
'==========================================================================
If Err.Number <> 0 Then
objFailed.WriteLine strComputer & " could not be reset. Check that it is powered on." & Err.Number
Err.Clear
Else
objSuccess.WriteLine Date() & "," & strComputer & "," & AdminName & "," & adminPassword
objShell.LogEvent EVENT_SUCCESS, "Admin password reset successfully from Gene's password script", "\\" & strComputer
End If
' Else
' objFailed.WriteLine Date() & " " & strComputer & " ping failed, not online."
' End If
Next
'==========================================================================
'Clean Up
'==========================================================================
objFailed.close
objSuccess.close
objShell.Popup "Finished Changing Administrator Passwords, box will close in 60 seconds.", 60, "Part 2 Complete."
set objFSO = nothing
set objAdmin = Nothing
set strTextFile = nothing
set objSuccess = nothing
set objFailed = nothing
'==========================================================================
' SUBS AND FUNCTIONS
'==========================================================================
'==========================================================================
' RandomPassword
' Function to generate a random password with Uppercase, lowercase,
' nums and special chars
' [URL unfurl="true"]http://911-need-code-help.blogspot.com/2009/06/generate-random-strings-using.html[/URL]
'==========================================================================
Function RandomString()
Randomize()
Dim CharacterSetArray
CharacterSetArray = Array(_
Array(4, "abcdefghijklmnopqrstuvwxyz"), _
Array(4, "ABCDEFGHIJKLMNOPQRSTUVWXYZ"), _
Array(4, "0123456789"), _
Array(4, "!@$*") _
)
Dim i
Dim j
Dim Count
Dim Chars
Dim Index
Dim Temp
For i = 0 to UBound(CharacterSetArray)
Count = CharacterSetArray(i)(0)
Chars = CharacterSetArray(i)(1)
for j = 1 to Count
Index = Int(Rnd() * Len(Chars)) + 1
Temp = Temp & Mid(Chars, Index, 1)
Next
Next
Dim TempCopy
Do until Len(Temp) = 0
Index = Int(Rnd() * Len(Temp)) + 1
TempCopy = TempCopy & Mid( Temp, Index, 1)
Temp = Mid(Temp, 1, Index - 1) & Mid(Temp, Index + 1)
Loop
RandomString = TempCopy
End function
'==========================================================================
' Ping
' Function to Secretely call up the commnad shell and ping a server
' This is need for compatibility sake. Currently only XP and 2003 server have built
' in WMI versions
' [URL unfurl="true"]http://www.tek-tips.com/viewthread.cfm?qid=1125863&page=1[/URL]
'==========================================================================
Function Ping(hostname)
Set objShell = CreateObject("WScript.Shell")
Ping = Not CBool(objShell.run("ping -n 1 " & hostname,0,True))
End Function