Environment variables can easily be added, removed, or retrieved using the script in this hack.
Using VBScript to work with the Windows system environment can be pretty simple. This hack shows how to use a script to read variables, add new variables, remove variables, and recurse through all of them. Just take a look through the script and read the comments to see how to perform each task. Note that there are four types of values in the Windows Script Host (WSH) environment—System, User, Volatile, and Process—and the script uses all of them.
By the way, this script is provided by Dudeworks (http://www.dudeworks.net). For additional resources on Windows scripting and working with the environment, see http://msdn.microsoft.com/library/default.asp?url=/library/en-us/script56/html/wsProEnvironment.asp.
The Code
Type the following script into Notepad (with Word Wrap disabled) and save it with a .vbs extension as GetEnvVars.vbs:
'~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
'Created by: Rob Olson - Dudeworks
'Created on: 10/17/2001
'Purpose: Get Environment Variables.
'~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
wscript.echo "Working with the Environment: Provided by www.dudeworks.net"&vbcrlf&vbcrlf&strval
'// Create an instance of the wshShell object
set WshShell = CreateObject("WScript.Shell")
'Use the methods of the object
wscript.echo "Environment.item: "& WshShell.Environment.item("WINDIR")
wscript.echo "ExpandEnvironmentStrings: "& WshShell.ExpandEnvironmentStrings("%windir%")
'// add and remove environment variables
'// Specify the environment type ( System, User, Volatile, or Process )
set oEnv=WshShell.Environment("System")
wscript.echo "Adding ( TestVar=Windows Script Host ) to the System " _
& "type environment"
' add a var
oEnv("TestVar") = "Windows Script Host"
wscript.echo "removing ( TestVar=Windows Script Host ) from the System " _
& "type environment"
' remove a var
oEnv.Remove "TestVar"
'// List all vars in all environment types
'//System Type
set oEnv=WshShell.Environment("System")
for each sitem in oEnv
strval=strval & sItem &vbcrlf
next
wscript.echo "System Environment:"&vbcrlf&vbcrlf&strval
strval=""
'//Process Type
set oEnv=WshShell.Environment("Process")
for each sitem in oEnv
strval=strval & sItem &vbcrlf
next
wscript.echo "Process Environment:"&vbcrlf&vbcrlf&strval
strval=""
'//User Type
set oEnv=WshShell.Environment("User")
for each sitem in oEnv
strval=strval & sItem &vbcrlf
next
wscript.echo "User Environment:"&vbcrlf&vbcrlf&strval
strval=""
'//Volatile Type
set oEnv=WshShell.Environment("Volatile")
for each sitem in oEnv
strval=strval & sItem &vbcrlf
next
wscript.echo "Volatile Environment:"&vbcrlf&vbcrlf&strval
strval=""
Running the Hack
To run the script, open a command prompt, change to the directory where the script is saved, and type cscript.exe GetEnvVars.vbs. Here is an example of typical output from the script on a Windows 2000 machine:
Microsoft (R) Windows Script Host Version 5.6
Copyright (C) Microsoft Corporation 1996-2001. All rights reserved.
Working with the Environment: Provided by www.dudeworks.net
Environment.item: %SystemRoot%
ExpandEnvironmentStrings: C:\WINNT
Adding ( TestVar=Windows Script Host ) to the System type environment
removing ( TestVar=Windows Script Host ) from the System type environment
System Environment:
ComSpec=%SystemRoot%\system32\cmd.exe
Os2LibPath=%SystemRoot%\system32\os2\dll;
Path=%SystemRoot%\system32;%SystemRoot%;%SystemRoot%\System32\Wbem
windir=%SystemRoot%
OS=Windows_NT
PROCESSOR_ARCHITECTURE=x86
PROCESSOR_LEVEL=6
PROCESSOR_IDENTIFIER=x86 Family 6 Model 5 Stepping 2, GenuineIntel
PROCESSOR_REVISION=0502
NUMBER_OF_PROCESSORS=1
PATHEXT=.COM;.EXE;.BAT;.CMD;.VBS;.VBE;.JS;.JSE;.WSF;.WSH
TEMP=%SystemRoot%\TEMP
TMP=%SystemRoot%\TEMP
Process Environment:
=C:=C:\
=ExitCode=00000000
ALLUSERSPROFILE=C:\Documents and Settings\All Users
APPDATA=C:\Documents and Settings\Administrator\Application Data
CommonProgramFiles=C:\Program Files\Common Files
COMPUTERNAME=SNOOPY
ComSpec=C:\WINNT\system32\cmd.exe
HOMEDRIVE=C:
HOMEPATH=\Documents and Settings\Administrator
LOGONSERVER=\\SNOOPY
NUMBER_OF_PROCESSORS=1
OS=Windows_NT
Os2LibPath=C:\WINNT\system32\os2\dll;
Path=C:\WINNT\system32;C:\WINNT;C:\WINNT\System32\Wbem
PATHEXT=.COM;.EXE;.BAT;.CMD;.VBS;.VBE;.JS;.JSE;.WSF;.WSH
PROCESSOR_ARCHITECTURE=x86
PROCESSOR_IDENTIFIER=x86 Family 6 Model 5 Stepping 2, GenuineIntel
PROCESSOR_LEVEL=6
PROCESSOR_REVISION=0502
ProgramFiles=C:\Program Files
PROMPT=$P$G
SystemDrive=C:
SystemRoot=C:\WINNT
TEMP=C:\DOCUME~1\ADMINI~1\LOCALS~1\Temp
TMP=C:\DOCUME~1\ADMINI~1\LOCALS~1\Temp
USERDOMAIN=SNOOPY
USERNAME=Administrator
USERPROFILE=C:\Documents and Settings\Administrator
windir=C:\WINNT
User Environment:
TEMP=%USERPROFILE%\Local Settings\Temp
TMP=%USERPROFILE%\Local Settings\Temp
Volatile Environment:
LOGONSERVER=\\SNOOPY
APPDATA=C:\Documents and Settings\Administrator\Application Data
By the way, if you add a new variable via the command prompt, you will not see it when you try to read it via the script. You can read only the new values created via the same scripting type you used to create them. Although I've tested this only to a limited extent, it seems to be true. Try it for yourself; just open a command prompt, type Set DUDE=Dudeworks, and press Enter to set the new environment variable. Now, when you execute GetEnvVars.vbs, and you'll notice that it does not list that new variable. However, if you type SET at the command prompt, you will see it.
—Rob Olson
Wednesday, March 26, 2008
Hack 8 Execute a Command on Each Computer in a Domain
This handy script lets you easily run any command on a specified subset of computers in your domain.
Running the same command on multiple computers in your domain can be tedious indeed, but such a scenario is common in an administrator's life. I've written this hack to make this chore easier. The script traverses member systems of a domain, executing a command against each system that has a name that matches a particular specification you specify in the command line. Note that regular expressions are legal in this script, which makes it a powerful and flexible addition to the administrator's toolkit.
The Code
To use this script, type it into a text editor such as Notepad (make sure Word Wrap is disabled) and save it with a .vbs extension as ExecuteAll.vbs. Alternatively, if you don't want to wear your fingers out, you can download the script from the O'Reilly web site.
'Script Name: ExecuteAll.vbs
Option Explicit
Dim oDomain, oService, oItem, oShell
Dim strDomain, strSpec, strCommand, intButton
Dim oArgs, strFinalCommand, oRegEx, boolConfirm
' Prepare to execute commands & do popups
Set oShell = CreateObject("WScript.Shell")
GetArguments
' Access the domain so we can traverse objects
WScript.Echo "Accessing NT Domain " & strDomain
Set oDomain = GetObject("WinNT://" & strDomain)
' Initiate our regular expression support
Set oRegEx = New RegExp
oRegEx.Pattern = strSpec
oRegEx.IgnoreCase = True
' Traverse each computer (WinNT) object in the domain
WScript.Echo "Searching for " & strSpec
oDomain.Filter = Array("Computer") ' only look at computers
For Each oItem In oDomain
If oRegEx.Test(oItem.Name) Then
WScript.Echo " Matched " & oItem.Name
strFinalCommand = Replace(strCommand, "$n", oItem.Name)
intButton = vbNo
If boolConfirm Then
intButton = oShell.Popup("Execute " & strFinalCommand & "?",,_
"System " & oItem.Name, vbYesno + vbQuestion)
End If
If (boolConfirm = False) Or (intButton = vbYes) Then
WScript.Echo " Executing: " & strFinalCommand
execute strFinalCommand
End If
End If
Next
' All done; clean up
Set oItem = Nothing
Set oRegEx = Nothing
Set oDomain = Nothing
Set oShell = Nothing
Set oArgs = Nothing
'
' Glean the arguments for our run from the command line, if provided.
' If any are missing, prompt for input. A blank input signals an abort.
'
' /Y is an optional last argument
Sub GetArguments
Dim i, strConfirm, intButton
Set oArgs = WScript.Arguments
boolConfirm = True ' assume always confirm
strDomain = "" ' domain to be traversed
strSpec = "" ' name specification to be matched
strCommand = "" ' command to be executed on each match
strConfirm = "" ' track prompting for confirmation setting
' Look for our optional 4th argument
If oArgs.Length = 4 Then
If UCase(oArgs.Item(3)) = "/Y" Then
boolConfirm = False
strConfirm = "/Y" ' don't prompt below
End If
End If
' Look for any specified arguments, in order
If oArgs.Length >= 1 Then strDomain = oArgs(0)
If oArgs.Length >= 2 Then strSpec = oArgs(1)
If oArgs.Length >= 3 Then strCommand = oArgs(2)
' Prompt for any arguments not specified on the command line
If strDomain = "" Then
strDomain = InputBox _
("Enter the name of the NT Domain to be traversed", _
"NT Domain")
End If
If strDomain = "" Then WScript.Quit
strDomain = UCase(strDomain)
If strSpec = "" Then
strSpec = InputBox _
("Enter your name specification for the computer(s) " & _
"that will be matched within the " & strDomain & " Domain." & _
vbCrlf & "Regular Expressions are acceptable.", _
"Name Specification")
End If
If strSpec = "" Then WScript.Quit
If strCommand = "" Then
strCommand = InputBox _
("Enter the command to be executed on each computer matching " & _
strSpec & " within the " & strDomain & " Domain." & _
vbCrlf & "$n will be substituted for the computer name.", _
"Command to Execute")
End If
If strCommand = "" Then WScript.Quit
If strConfirm = "" Then
intButton = oShell.Popup("Confirm each command prior to execution?",,_
"Confirm?", vbYesNo + vbQuestion)
If intButton = vbNo Then
boolConfirm = False
End If
End If
End Sub
' Execute a command. Each is always run under a new instance of the command
' processor. This allows the use of built-in commands and I/O redirection.
'
' We won't wait for command completion.
Sub Execute(strCommand)
Dim RetVal
strCommand = "%COMSPEC% /c " & strCommand
RetVal = oShell.Run(strCommand, 1, False)
End Sub
Running the Hack
Here is the syntax for running the script:
ExexcuteAll.vbs [/Y]
When the script runs, the matched system's name will be substituted for the occurrence of $n in the command to be performed. By default, each command instance is confirmed before it is executed, but you can specify /Y to always answer Yes instead.
Here's an example of how to run the script:
ExexcuteAll.vbs MYDOMAIN WKSATL* "del \\$n\admin$\activitylog.txt"
This example traverses the MYDOMAIN domain, looking for computer names that start with WKSATL* (note the wildcard) and deletes the activitylog.txt file from the C:\Winnt folder.
—Hans Schefske
Running the same command on multiple computers in your domain can be tedious indeed, but such a scenario is common in an administrator's life. I've written this hack to make this chore easier. The script traverses member systems of a domain, executing a command against each system that has a name that matches a particular specification you specify in the command line. Note that regular expressions are legal in this script, which makes it a powerful and flexible addition to the administrator's toolkit.
The Code
To use this script, type it into a text editor such as Notepad (make sure Word Wrap is disabled) and save it with a .vbs extension as ExecuteAll.vbs. Alternatively, if you don't want to wear your fingers out, you can download the script from the O'Reilly web site.
'Script Name: ExecuteAll.vbs
Option Explicit
Dim oDomain, oService, oItem, oShell
Dim strDomain, strSpec, strCommand, intButton
Dim oArgs, strFinalCommand, oRegEx, boolConfirm
' Prepare to execute commands & do popups
Set oShell = CreateObject("WScript.Shell")
GetArguments
' Access the domain so we can traverse objects
WScript.Echo "Accessing NT Domain " & strDomain
Set oDomain = GetObject("WinNT://" & strDomain)
' Initiate our regular expression support
Set oRegEx = New RegExp
oRegEx.Pattern = strSpec
oRegEx.IgnoreCase = True
' Traverse each computer (WinNT) object in the domain
WScript.Echo "Searching for " & strSpec
oDomain.Filter = Array("Computer") ' only look at computers
For Each oItem In oDomain
If oRegEx.Test(oItem.Name) Then
WScript.Echo " Matched " & oItem.Name
strFinalCommand = Replace(strCommand, "$n", oItem.Name)
intButton = vbNo
If boolConfirm Then
intButton = oShell.Popup("Execute " & strFinalCommand & "?",,_
"System " & oItem.Name, vbYesno + vbQuestion)
End If
If (boolConfirm = False) Or (intButton = vbYes) Then
WScript.Echo " Executing: " & strFinalCommand
execute strFinalCommand
End If
End If
Next
' All done; clean up
Set oItem = Nothing
Set oRegEx = Nothing
Set oDomain = Nothing
Set oShell = Nothing
Set oArgs = Nothing
'
' Glean the arguments for our run from the command line, if provided.
' If any are missing, prompt for input. A blank input signals an abort.
'
' /Y is an optional last argument
Sub GetArguments
Dim i, strConfirm, intButton
Set oArgs = WScript.Arguments
boolConfirm = True ' assume always confirm
strDomain = "" ' domain to be traversed
strSpec = "" ' name specification to be matched
strCommand = "" ' command to be executed on each match
strConfirm = "" ' track prompting for confirmation setting
' Look for our optional 4th argument
If oArgs.Length = 4 Then
If UCase(oArgs.Item(3)) = "/Y" Then
boolConfirm = False
strConfirm = "/Y" ' don't prompt below
End If
End If
' Look for any specified arguments, in order
If oArgs.Length >= 1 Then strDomain = oArgs(0)
If oArgs.Length >= 2 Then strSpec = oArgs(1)
If oArgs.Length >= 3 Then strCommand = oArgs(2)
' Prompt for any arguments not specified on the command line
If strDomain = "" Then
strDomain = InputBox _
("Enter the name of the NT Domain to be traversed", _
"NT Domain")
End If
If strDomain = "" Then WScript.Quit
strDomain = UCase(strDomain)
If strSpec = "" Then
strSpec = InputBox _
("Enter your name specification for the computer(s) " & _
"that will be matched within the " & strDomain & " Domain." & _
vbCrlf & "Regular Expressions are acceptable.", _
"Name Specification")
End If
If strSpec = "" Then WScript.Quit
If strCommand = "" Then
strCommand = InputBox _
("Enter the command to be executed on each computer matching " & _
strSpec & " within the " & strDomain & " Domain." & _
vbCrlf & "$n will be substituted for the computer name.", _
"Command to Execute")
End If
If strCommand = "" Then WScript.Quit
If strConfirm = "" Then
intButton = oShell.Popup("Confirm each command prior to execution?",,_
"Confirm?", vbYesNo + vbQuestion)
If intButton = vbNo Then
boolConfirm = False
End If
End If
End Sub
' Execute a command. Each is always run under a new instance of the command
' processor. This allows the use of built-in commands and I/O redirection.
'
' We won't wait for command completion.
Sub Execute(strCommand)
Dim RetVal
strCommand = "%COMSPEC% /c " & strCommand
RetVal = oShell.Run(strCommand, 1, False)
End Sub
Running the Hack
Here is the syntax for running the script:
ExexcuteAll.vbs
When the script runs, the matched system's name will be substituted for the occurrence of $n in the command to be performed. By default, each command instance is confirmed before it is executed, but you can specify /Y to always answer Yes instead.
Here's an example of how to run the script:
ExexcuteAll.vbs MYDOMAIN WKSATL* "del \\$n\admin$\activitylog.txt"
This example traverses the MYDOMAIN domain, looking for computer names that start with WKSATL* (note the wildcard) and deletes the activitylog.txt file from the C:\Winnt folder.
—Hans Schefske
Hack 7 Rename Mapped Drives
Renaming drive mappings can be done in several ways, but automating the process is most efficient using a script.
Occasionally, an administrator might need to change drive-mapping names to hide share paths or to make the drive name user-friendly. This is an easy operation when done manually through a console, but when you try to automate this task, it becomes a little more difficult. Because mapped drives are not partitions on the local hard disk, common DOS commands, such as label, can't be used. Most drive-mapping commands, such as net use, don't have a way to customize the name of the mapped drive either.
One common way to perform this task is to hack the following Registry key and add the _LabelFromReg string value:
HKCU\Software\Microsoft\Windows\CurrentVersion\Explorer\MountPoints2\%key%
Here, the %key% variable is the drive letter to be changed.
There is a whole host of ways to make this method work, either by editing the Registry directly, via script, or by importing a .reg file using regedit /c. All of these methods require many steps and some require external files, so they might not fit into every administrative scheme. But there's an easier approach.
The Code
As it turns out, our old friend VBScript can be used to make this task a little more seamless. This simple script can be used on mapped drives as well as local partitions:
mDrive = "drive letter"
Set oShell = CreateObject("Shell.Application")
oShell.NameSpace(mDrive).Self.Name = "AnyName"
Running the Hack
To use this hack, simply edit the script to change the drive letter and drive name as desired. For example, if E: is a mapped drive that has the label Budgets on 172.16.33.14, and you want to change the label on the mapped drive to simply Budgets, change this line:
mDrive = "drive letter"
to this:
mDrive = "e:\"
Then, change this line:
oShell.NameSpace(mDrive).Self.Name = "AnyName"
to this:
oShell.NameSpace(mDrive).Self.Name = "Budgets"
Finally, run the script by creating a shortcut to it and double-clicking on the shortcut, by calling it from a logon script, or by any other method suitable for your environment.
—Michael Brainard
Occasionally, an administrator might need to change drive-mapping names to hide share paths or to make the drive name user-friendly. This is an easy operation when done manually through a console, but when you try to automate this task, it becomes a little more difficult. Because mapped drives are not partitions on the local hard disk, common DOS commands, such as label, can't be used. Most drive-mapping commands, such as net use, don't have a way to customize the name of the mapped drive either.
One common way to perform this task is to hack the following Registry key and add the _LabelFromReg string value:
HKCU\Software\Microsoft\Windows\CurrentVersion\Explorer\MountPoints2\%key%
Here, the %key% variable is the drive letter to be changed.
There is a whole host of ways to make this method work, either by editing the Registry directly, via script, or by importing a .reg file using regedit /c. All of these methods require many steps and some require external files, so they might not fit into every administrative scheme. But there's an easier approach.
The Code
As it turns out, our old friend VBScript can be used to make this task a little more seamless. This simple script can be used on mapped drives as well as local partitions:
mDrive = "drive letter"
Set oShell = CreateObject("Shell.Application")
oShell.NameSpace(mDrive).Self.Name = "AnyName"
Running the Hack
To use this hack, simply edit the script to change the drive letter and drive name as desired. For example, if E: is a mapped drive that has the label Budgets on 172.16.33.14, and you want to change the label on the mapped drive to simply Budgets, change this line:
mDrive = "drive letter"
to this:
mDrive = "e:\"
Then, change this line:
oShell.NameSpace(mDrive).Self.Name = "AnyName"
to this:
oShell.NameSpace(mDrive).Self.Name = "Budgets"
Finally, run the script by creating a shortcut to it and double-clicking on the shortcut, by calling it from a logon script, or by any other method suitable for your environment.
—Michael Brainard
Hack 6 Shut Down a Remote Computer
Here's a nifty way to use a script to shut down remote machines.
Sometimes, you need to be able to shut down a server remotely. This script pings the computer in question prior to sending the Win32Shutdown method. It operates on remote PCs and has been tested on systems running Windows 2000. It will probably work on NT4 systems with the proper WHS/WMI/VB scripting, though it has not been tested on such systems.
Using the Win32Shutdown method, the script provides you with the option of logging off the current user of the machine, powering the machine down, or rebooting it. In addition, each of these options can be forced so that the action occurs even if applications are running. Use this option carefully, though, because it might cause the logged-on user to lose his work if he has open files. Note that forced log off/power down/reboot will not work if the screen saver is password-protected and is currently active.
The Code
Make sure you have the latest scripting engines on the workstation you run this script from. You can download the latest scripting engines at the Microsoft Scripting home page (http://msdn.microsoft.com/library/default.asp?url=/nhp/default.asp?contentid=28001169). Note that, when working with the Active Directory Services Interface (ADSI), you must have the same applicable rights as you need to use the built-in administrative tools. Also, for VB scripts that interact with Windows Management Instrumentation (WMI), apply the most current version of the WMI agents.
Type the following code into a text editor such as Notepad (making sure to have Word Wrap disabled) and save it with a .vbs extension. Alternatively, you can download the RemoteShutdown.vbs script from the O'Reilly web site at http://www.oreilly.com/catalog/winsvrhks/.
'/'|| RemoteShutdown.vbs
'||
'|| Created by Harvey Hendricks, MCP, MCSE, A+
'|| March 2001
'|| email: Harvey.Hendricks@aramcoservices.com
'||
'||
'|| Based on techniques and ideas from:
'|| SMS admin, SMS Installer, & WMI forums ->
'|| http://www.myITforum.com/forums
'|| Win32 Scripting -> http://cwashington.netreach.net/
'|| Microsoft Windows Script Technologies ->
'|| http://msdn.microsoft.com/scripting
'|| Microsoft Online Library ->
'|| http://msdn.microsoft.com/library/default.asp
'|| Microsoft VBScript 5.5 documentation and Microsoft WMI SDK
'||
'||~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
'|| SCRIPT LOGIC FLOW:
'|| Collects computername from user, calls function to ping the computername
'|| to determine if it is accessible, if not then display message and exit
'|| otherwise continue.
'|| Collects desired action to perform from the user, does error checking on
'|| the input to determine if it is acceptable, if not then display message
'|| and exit otherwise continue.
'|| Set variables and output messages based on the action chosen. Calls
'|| Win32Shutdown with the appropriate variable. Displays success message
'|| and exits
'||
'|| Uses WMI Win32Shutdown method from the Win32_OperatingSystem class
'|| to perform different logoff / powerdown / reboot functions
'||
'|| Testing found the following values to be effective on Win32Shutdown:
'|| Action decimal binary
'|| Logoff 0 0000
'|| Force Logoff 4 0100
'|| Reboot 2 0010
'|| Force Reboot 6 0110
'|| Powerdown 8 1000
'|| Force Powerdown 12 1100
'||
'|| Notice that the third bit from the right appears to be the "FORCE" bit.
'||
'|| A value of 1 will do a shutdown, ending at the "It is safe to turn
'|| off your computer" screen. I have no use for this and did not test it.
'||
'||
'||NOTES: - tested under Windows 2000 Pro. with ACPI compliant systems -
'|| SHOULD work under Windows NT4 without modification IF the
'|| system has compatible versions of WSH / WMI / VBscripting
'||
'||Logoff / Powerdown / Reboot:
'|| Does not work if a password protected screen saver is active or
'|| there is data to save. Either way the system waits for user input.
'||
'||Force Logoff / Force Powerdown / Force Reboot:
'|| Does not work if a password protected screen saver is active, will wait
'|| for user input. Otherwise will close open applications without saving
'|| data.
'||
'\/~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
'/\/\/\/\/\/\/\/\/\/\/\/\/\/\ start function
function Ping(byval strName)
dim objFSO, objShell, objTempFile, objTS
dim sCommand, sReadLine
dim bReturn
set objShell = WScript.CreateObject("Wscript.Shell")
set objFSO = CreateObject("Scripting.FileSystemObject")
'Set default return value
bReturn = false
'Create command line to ping and save results to a temp file
sCommand = "cmd /c ping.exe -n 3 -w 1000 " & strName & " > C:\temp.txt"
'Execute the command
objShell.run sCommand, 0, true
'Get the temp file
set objTempFile = objFSO.GetFile("C:\temp.txt")
set objTS = objTempFile.OpenAsTextStream(1)
'Loop through the temp file to see if "reply from" is found,
'if it is then the ping was successful
do while objTs.AtEndOfStream <> true
sReadLine = objTs.ReadLine
if instr(lcase(sReadLine), "reply from") > 0 then
bReturn = true
exit do
end if
loop
'Close temp file and release objects
objTS.close
objTempFile.delete
set objTS = nothing
set objTempFile = nothing
set objShell = nothing
set objFSO = nothing
'Return value
Ping = bReturn
end function
'/\/\/\/\/\/\/\/\/\/\/\/\/\/\ end function
'/\/\/\/\/\/\/\/\/\/\/\ Start Main body of script
'Get computer name to operate on
ComputerName=InputBox("Enter the Machine name of the computer" & vbCRLF _
& "you wish to Shutdown / Reboot / Logoff", _
"Remote Shutdown / Reboot / Logoff", _
"ComputerName")
'if Cancel selected - exit
If (ComputerName = "") Then Wscript.Quit
'change the name to uppercase
ComputerName=UCase(ComputerName)
'ping the computername to see if it is accessible
bPingtest = ping(Computername)
If bPingtest = FALSE Then
y = msgbox ("'" & ComputerName & "' is not accessible!" & vbCRLF _
& "It may be offline or turned off." & vbCRLF _
& "Check the name for a typo." & vbCRLF, _
vbCritical, ComputerName & " NOT RESPONDING")
Wscript.Quit
end IF
'Get the action desired
Action=InputBox( _
"Select Action to perform on " & ComputerName & vbCRLF & vbCRLF _
& " 1 - Logoff" & vbCRLF _
& " 2 - Force Logoff ( NO SAVE )" & vbCRLF _
& " 3 - Powerdown" & vbCRLF _
& " 4 - Force Powerdown ( NO SAVE )" & vbCRLF _
& " 5 - Reboot" & vbCRLF _
& " 6 - Force Reboot ( NO SAVE )" & vbCRLF & vbCRLF _
& "NOTE:" & vbCRLF _
& " Using Force will close windows" & vbCRLF _
& " without saving changes!", _
"Select action to perform on " & ComputerName, "")
'if Cancel selected - exit
If (Action = "") Then Wscript.Quit
'error check input
If (INSTR("1234567",Action)=0) OR (Len(Action)>1) then
y = msgbox("Unacceptable input passed -- '" & Action & "'", _
vbOKOnly + vbCritical, "That was SOME bad input!")
Wscript.Quit
end if
'set flag to disallow action unless proper input achieved, 1 => go 0 => nogo
flag = 0
'set variables according to computername and action
Select Case Action
Case 1 'Logoff
x = 0
strAction = "Logoff sent to " & ComputerName
flag = 1
Case 2 'Force Logoff
x = 4
strAction = "Force Logoff sent to " & ComputerName
flag = 1
Case 3 'Powerdown
x = 8
strAction = "Powerdown sent to " & ComputerName
flag = 1
Case 4 'Force Powerdown
x = 12
strAction = "Force Powerdown sent to " & ComputerName
flag = 1
Case 5 'Reboot
x = 2
strAction = "Reboot sent to " & ComputerName
flag = 1
Case 6 'Force Reboot
x = 6
strAction = "Force Reboot sent to " & ComputerName
flag = 1
Case 7 'Test dialog boxes
y = msgbox("Test complete", vbOKOnly + vbInformation, "Dialog Box Test Complete")
flag = 0
Case Else 'Default -- should never happen
y = msgbox("Error occurred in passing parameters." _
& vbCRLF & " Passed '" & Action & "'", _
vbOKOnly + vbCritical, "PARAMETER ERROR")
flag = 0
End Select
'check flag
' if equal 1 (TRUE) then perform Win32Shutdown action on remote PC
' and display a confirmation message
' if not equal 1 (FALSE) then skip the action and script ends
if flag then
Set OpSysSet=GetObject("winmgmts:{(Debug,RemoteShutdown)}//" _
& ComputerName & "/root/cimv2").ExecQuery( _
"Select * from Win32_OperatingSystem where Primary=true")
for each OpSys in OpSysSet
OpSys.Win32Shutdown(x)
y = msgbox(strAction,vbOKOnly + vbInformation,"Mission Accomplished")
next
end If
'Release objects
set OpSys = nothing
set OpSysSet = nothing
Running the Hack
To run the hack, simply double-click on the RemoteShutdown.vbs file in Windows Explorer (or a shortcut to this file on your desktop) and type the name of the remote computer you want to log off from, power down, or reboot. This name can be the NetBIOS name, DNS name, or IP address of the remote machine. You will then be presented with an input box that displays a menu of options:
1 - Logoff
2 - Force Logoff
3 - Powerdown
4 - Force Powerdown
5 - Reboot
6 - Force Reboot
Simply type the number for the action you want to perform and press Enter.
—Harvey Hendricks
Sometimes, you need to be able to shut down a server remotely. This script pings the computer in question prior to sending the Win32Shutdown method. It operates on remote PCs and has been tested on systems running Windows 2000. It will probably work on NT4 systems with the proper WHS/WMI/VB scripting, though it has not been tested on such systems.
Using the Win32Shutdown method, the script provides you with the option of logging off the current user of the machine, powering the machine down, or rebooting it. In addition, each of these options can be forced so that the action occurs even if applications are running. Use this option carefully, though, because it might cause the logged-on user to lose his work if he has open files. Note that forced log off/power down/reboot will not work if the screen saver is password-protected and is currently active.
The Code
Make sure you have the latest scripting engines on the workstation you run this script from. You can download the latest scripting engines at the Microsoft Scripting home page (http://msdn.microsoft.com/library/default.asp?url=/nhp/default.asp?contentid=28001169). Note that, when working with the Active Directory Services Interface (ADSI), you must have the same applicable rights as you need to use the built-in administrative tools. Also, for VB scripts that interact with Windows Management Instrumentation (WMI), apply the most current version of the WMI agents.
Type the following code into a text editor such as Notepad (making sure to have Word Wrap disabled) and save it with a .vbs extension. Alternatively, you can download the RemoteShutdown.vbs script from the O'Reilly web site at http://www.oreilly.com/catalog/winsvrhks/.
'/'|| RemoteShutdown.vbs
'||
'|| Created by Harvey Hendricks, MCP, MCSE, A+
'|| March 2001
'|| email: Harvey.Hendricks@aramcoservices.com
'||
'||
'|| Based on techniques and ideas from:
'|| SMS admin, SMS Installer, & WMI forums ->
'|| http://www.myITforum.com/forums
'|| Win32 Scripting -> http://cwashington.netreach.net/
'|| Microsoft Windows Script Technologies ->
'|| http://msdn.microsoft.com/scripting
'|| Microsoft Online Library ->
'|| http://msdn.microsoft.com/library/default.asp
'|| Microsoft VBScript 5.5 documentation and Microsoft WMI SDK
'||
'||~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
'|| SCRIPT LOGIC FLOW:
'|| Collects computername from user, calls function to ping the computername
'|| to determine if it is accessible, if not then display message and exit
'|| otherwise continue.
'|| Collects desired action to perform from the user, does error checking on
'|| the input to determine if it is acceptable, if not then display message
'|| and exit otherwise continue.
'|| Set variables and output messages based on the action chosen. Calls
'|| Win32Shutdown with the appropriate variable. Displays success message
'|| and exits
'||
'|| Uses WMI Win32Shutdown method from the Win32_OperatingSystem class
'|| to perform different logoff / powerdown / reboot functions
'||
'|| Testing found the following values to be effective on Win32Shutdown:
'|| Action decimal binary
'|| Logoff 0 0000
'|| Force Logoff 4 0100
'|| Reboot 2 0010
'|| Force Reboot 6 0110
'|| Powerdown 8 1000
'|| Force Powerdown 12 1100
'||
'|| Notice that the third bit from the right appears to be the "FORCE" bit.
'||
'|| A value of 1 will do a shutdown, ending at the "It is safe to turn
'|| off your computer" screen. I have no use for this and did not test it.
'||
'||
'||NOTES: - tested under Windows 2000 Pro. with ACPI compliant systems -
'|| SHOULD work under Windows NT4 without modification IF the
'|| system has compatible versions of WSH / WMI / VBscripting
'||
'||Logoff / Powerdown / Reboot:
'|| Does not work if a password protected screen saver is active or
'|| there is data to save. Either way the system waits for user input.
'||
'||Force Logoff / Force Powerdown / Force Reboot:
'|| Does not work if a password protected screen saver is active, will wait
'|| for user input. Otherwise will close open applications without saving
'|| data.
'||
'\/~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
'/\/\/\/\/\/\/\/\/\/\/\/\/\/\ start function
function Ping(byval strName)
dim objFSO, objShell, objTempFile, objTS
dim sCommand, sReadLine
dim bReturn
set objShell = WScript.CreateObject("Wscript.Shell")
set objFSO = CreateObject("Scripting.FileSystemObject")
'Set default return value
bReturn = false
'Create command line to ping and save results to a temp file
sCommand = "cmd /c ping.exe -n 3 -w 1000 " & strName & " > C:\temp.txt"
'Execute the command
objShell.run sCommand, 0, true
'Get the temp file
set objTempFile = objFSO.GetFile("C:\temp.txt")
set objTS = objTempFile.OpenAsTextStream(1)
'Loop through the temp file to see if "reply from" is found,
'if it is then the ping was successful
do while objTs.AtEndOfStream <> true
sReadLine = objTs.ReadLine
if instr(lcase(sReadLine), "reply from") > 0 then
bReturn = true
exit do
end if
loop
'Close temp file and release objects
objTS.close
objTempFile.delete
set objTS = nothing
set objTempFile = nothing
set objShell = nothing
set objFSO = nothing
'Return value
Ping = bReturn
end function
'/\/\/\/\/\/\/\/\/\/\/\/\/\/\ end function
'/\/\/\/\/\/\/\/\/\/\/\ Start Main body of script
'Get computer name to operate on
ComputerName=InputBox("Enter the Machine name of the computer" & vbCRLF _
& "you wish to Shutdown / Reboot / Logoff", _
"Remote Shutdown / Reboot / Logoff", _
"ComputerName")
'if Cancel selected - exit
If (ComputerName = "") Then Wscript.Quit
'change the name to uppercase
ComputerName=UCase(ComputerName)
'ping the computername to see if it is accessible
bPingtest = ping(Computername)
If bPingtest = FALSE Then
y = msgbox ("'" & ComputerName & "' is not accessible!" & vbCRLF _
& "It may be offline or turned off." & vbCRLF _
& "Check the name for a typo." & vbCRLF, _
vbCritical, ComputerName & " NOT RESPONDING")
Wscript.Quit
end IF
'Get the action desired
Action=InputBox( _
"Select Action to perform on " & ComputerName & vbCRLF & vbCRLF _
& " 1 - Logoff" & vbCRLF _
& " 2 - Force Logoff ( NO SAVE )" & vbCRLF _
& " 3 - Powerdown" & vbCRLF _
& " 4 - Force Powerdown ( NO SAVE )" & vbCRLF _
& " 5 - Reboot" & vbCRLF _
& " 6 - Force Reboot ( NO SAVE )" & vbCRLF & vbCRLF _
& "NOTE:" & vbCRLF _
& " Using Force will close windows" & vbCRLF _
& " without saving changes!", _
"Select action to perform on " & ComputerName, "")
'if Cancel selected - exit
If (Action = "") Then Wscript.Quit
'error check input
If (INSTR("1234567",Action)=0) OR (Len(Action)>1) then
y = msgbox("Unacceptable input passed -- '" & Action & "'", _
vbOKOnly + vbCritical, "That was SOME bad input!")
Wscript.Quit
end if
'set flag to disallow action unless proper input achieved, 1 => go 0 => nogo
flag = 0
'set variables according to computername and action
Select Case Action
Case 1 'Logoff
x = 0
strAction = "Logoff sent to " & ComputerName
flag = 1
Case 2 'Force Logoff
x = 4
strAction = "Force Logoff sent to " & ComputerName
flag = 1
Case 3 'Powerdown
x = 8
strAction = "Powerdown sent to " & ComputerName
flag = 1
Case 4 'Force Powerdown
x = 12
strAction = "Force Powerdown sent to " & ComputerName
flag = 1
Case 5 'Reboot
x = 2
strAction = "Reboot sent to " & ComputerName
flag = 1
Case 6 'Force Reboot
x = 6
strAction = "Force Reboot sent to " & ComputerName
flag = 1
Case 7 'Test dialog boxes
y = msgbox("Test complete", vbOKOnly + vbInformation, "Dialog Box Test Complete")
flag = 0
Case Else 'Default -- should never happen
y = msgbox("Error occurred in passing parameters." _
& vbCRLF & " Passed '" & Action & "'", _
vbOKOnly + vbCritical, "PARAMETER ERROR")
flag = 0
End Select
'check flag
' if equal 1 (TRUE) then perform Win32Shutdown action on remote PC
' and display a confirmation message
' if not equal 1 (FALSE) then skip the action and script ends
if flag then
Set OpSysSet=GetObject("winmgmts:{(Debug,RemoteShutdown)}//" _
& ComputerName & "/root/cimv2").ExecQuery( _
"Select * from Win32_OperatingSystem where Primary=true")
for each OpSys in OpSysSet
OpSys.Win32Shutdown(x)
y = msgbox(strAction,vbOKOnly + vbInformation,"Mission Accomplished")
next
end If
'Release objects
set OpSys = nothing
set OpSysSet = nothing
Running the Hack
To run the hack, simply double-click on the RemoteShutdown.vbs file in Windows Explorer (or a shortcut to this file on your desktop) and type the name of the remote computer you want to log off from, power down, or reboot. This name can be the NetBIOS name, DNS name, or IP address of the remote machine. You will then be presented with an input box that displays a menu of options:
1 - Logoff
2 - Force Logoff
3 - Powerdown
4 - Force Powerdown
5 - Reboot
6 - Force Reboot
Simply type the number for the action you want to perform and press Enter.
—Harvey Hendricks
Hack 5 Wait for and Optionally Terminate a Process
If you've wondered how to write code that waits for a process to finish before terminating it, here's the answer.
I have seen a number of discussions regarding the need for a VB script that waits for a process to finish. The script in this hack does this and more: it waits for a process to finish and optionally terminates the process if it has not finished within a specified amount of time.
This code is a modified form of what I use to control my software deployments, and it has two purposes. First, the code is designed to be certain that the deployment script waits until the initiated software setup executable is fully finished before proceeding. Even though the majority of recent software releases do not require this functionality when being deployed, it is still required for some legacy installations. Second, the code can perform a forceful termination of an application if this functionality is required.
This script accepts three arguments: the name of the executable to wait for or terminate, the amount of time to wait before terminating the specified executable, and (optionally) a switch specifying that the script should run silently. Note that the script uses Windows Management Instrumentation (WMI) for the process-management tasks, so make sure you're running the latest WMI version on your machine.
The Code
The script consists of several sections, which are described inline in the following sections.
Main routine
First, command-line switches are read in the main body area:
Option Explicit
'''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
'
' File: vbsWaitForProcess.vbs
' Updated: Nov 2002
' Version: 1.0
' Author: Dan Thomson, myITforum.com columnist
' I can be contacted at dethomson@hotmail.com
'
' Usage: The command processor version must be run using cscript
' cscript vbsWaitForProcess.vbs notepad.exe 60 S
' or
' The IE and Popup versions can be run with cscript or wscript
' wscript vbsWaitForProcess.vbs notepad.exe -1
'
' Input: Name of executable (ex: notepad.exe)
' Time to wait in seconds before terminating the executable
' -1 waits indefinitely for the process to finish
' 0 terminates the process imediately
' Any value > 0 will cause the script to wait the specified
' amount of time in seconds before terminating the process
' Silent mode (S)
'
' Notes:
'
''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
On Error Resume Next
'Define some variables
Dim strProcess
Dim intWaitTime
Dim strSilent
'Get the command line arguments
strProcess = Wscript.Arguments.Item(0)
intWaitTime = CInt(Wscript.Arguments.Item(1))
strSilent = Wscript.Arguments.Item(2)
Call WaitForProcess (strProcess, intWaitTime, strSilent)
Check if process is running
Next, the ProcessIsRunning function determines if a process is running:
'''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
'
' Function: ProcessIsRunning
'
' Purpose: Determine if a process is running
'
' Input: Name of process
'
' Output: True or False depending on if the process is running
'
''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
Private Function ProcessIsRunning( strProcess )
Dim colProcessList
Set colProcessList = Getobject("Winmgmts:").Execquery _
("Select * from Win32_Process Where Name ='" & strProcess & "'")
If colProcessList.Count > 0 Then
ProcessIsRunning = True
Else
ProcessIsRunning = False
End If
Set colProcessList = Nothing
End Function
Terminate the process
In the next section, the ProcessTerminate function terminates a process:
'''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
'
' Function: TerminateProcess
'
' Purpose: Terminates a process
'
' Input: Name of process
'
''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
Private Function ProcessTerminate( strProcess )
Dim colProcessList, objProcess
Set colProcessList = GetObject("Winmgmts:").ExecQuery _
("Select * from Win32_Process Where Name ='" & strProcess & "'")
For Each objProcess in colProcessList
objProcess.Terminate( )
Next
Set colProcessList = Nothing
End Function
Wait for process to terminate
Finally, in the WaitForProcess subroutine, the user interface is set up, the script waits while the process is active, and the process termination is initiated. I created three versions of the subroutine in an effort to demonstrate a few methods for displaying status messages. For example, here's how to display these messages using the command console:
'''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
'
' Sub: WaitForProcess
'
' Purpose: Waits for a process
'
' Input: Name of process
' Wait time in seconds before termination.
' -1 will cause the script to wait indefinitely
' 0 terminates the process imediately
' Any value > 0 will cause the script to wait the specified
' amount of time in seconds before terminating the process
' Display mode.
' Passing S will run the script silent and not show any prompts
'
' Output: On screen status
'
' Notes: The version echos user messages in the command window via StdOut
'
''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
Private Sub WaitForProcess( strProcess, intWaitTime, strMode )
If ProcessIsRunning(strProcess) Then
Dim StdOut
Dim w : w = 0
Dim strPrompt
Dim intPause : intPause = 1
If UCase(strMode) <> "S" Then
strPrompt = "Waiting for " & strProcess & " to finish."
Set StdOut = WScript.StdOut
StdOut.WriteLine ""
StdOut.Write strPrompt
End If
'Loop while the process is running
Do While ProcessIsRunning(strProcess)
'Check to see if specified # of seconds have passed before terminating
'the process. If yes, then terminate the process
If w >= intWaitTime AND intWaitTime >= 0 Then
Call ProcessTerminate(strProcess)
Exit Do
End If
'If not running silent, post user messages
If UCase(strMode) <> "S" Then _
StdOut.Write "."
'Increment the seconds counter
w = w + intPause
'Pause
Wscript.Sleep(intPause * 1000)
Loop
If UCase(strMode) <> "S" Then
StdOut.WriteLine ""
Set StdOut = Nothing
End If
End If
End Sub
The result is shown in Figure 1-8.
Figure 1-8. Status message displayed in command console
Alternatively, here's some code for displaying status messages in Internet Explorer:
'''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
'
' Sub: WaitForProcess
'
' Purpose: Waits for a process
'
' Input: Name of process
' Wait time in seconds before termination.
' -1 will cause the script to wait indefinitely
' 0 terminates the process imediately
' Any value > 0 will cause the script to wait the specified
' amount of time in seconds before terminating the process
' Display mode.
' Passing S will run the script silent and not show any prompts
'
' Output: On screen status
'
' Notes: This version uses Internet Explorer for user messages
'
''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
Private Sub WaitForProcess( strProcess, intWaitTime, strMode )
If ProcessIsRunning(strProcess) Then
Dim objIntExplorer
Dim c : c = 0
Dim w : w = 0
Dim strPrompt
Dim intPause : intPause = 1
strPrompt = "Waiting for " & strProcess & " to finish."
'If not running silent, create reference to objIntExplorer
'This will be used for the user messages. Also set IE display attributes
If UCase(strMode) <> "S" Then
Set objIntExplorer = Wscript._
CreateObject("InternetExplorer.Application")
With objIntExplorer
.Navigate "about:blank"
.ToolBar = 0
.Menubar = 0 ' no menu
.StatusBar = 0
.Width=400
.Height = 80
.Left = 100
.Top = 100
.Document.Title = "WaitForProcess"
End With
'Wait for IE to finish
Do While (objIntExplorer.Busy)
Wscript.Sleep 200
Loop
'Show IE
objIntExplorer.Visible = 1
End If
Do While ProcessIsRunning(strProcess)
'Check to see if specified # of seconds have passed before terminating
'the process. If yes, then terminate the process
If w >= intWaitTime AND intWaitTime >= 0 Then
Call ProcessTerminate(strProcess)
Exit Do
End If
If UCase(strMode) <> "S" Then
objIntExplorer.Document.Body.InnerHTML = strPrompt & String(c, ".")
'Increment the counter.
'Reset the counter indicator if it's > 25 because
'we don't want it taking up a lot of screen space.
If c > 25 Then c = 1 Else c = c + 1
'Increment the seconds counter
w = w + intPause
End If
'Pause
Wscript.Sleep(intPause * 1000)
Loop
objIntExplorer.Quit( ) ' close Internet Explorer
Set objIntExplorer = Nothing ' release object reference
End If
End Sub
The resulting status message is shown in Figure 1-9.
Figure 1-9. Displaying status messages in Internet Explorer
Finally, here's code that uses the Popup method of Windows Scripting Host for displaying status messages:
''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
'
' Sub: WaitForProcess
'
' Purpose: Waits for a process
'
' Input: Name of process
' Wait time in seconds before termination.
' -1 will cause the script to wait indefinitely
' 0 terminates the process imediately
' Any value > 0 will cause the script to wait the specified '
' amount of time in seconds before terminating the process
' Display mode.
' Passing S will run the script silent and not show any prompts
'
' Output: On screen status
'
' Notes: This version uses WshShell.Popup for user messages
'
''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
Private Sub WaitForProcess( strProcess, intWaitTime, strMode )
If ProcessIsRunning(strProcess) Then
Dim objWshShell
Dim c : c = 0
Dim w : w = 0
Dim strPrompt
Dim intPopupTimer : intPopupTimer = 2
Dim intPause : intPause = 1
strPrompt = "Waiting for " & strProcess & " to finish."
'If not running silent, create reference to objWshShell
'This will be used for the user messages
If UCase(strMode) <> "S" Then _
Set objWshShell = CreateObject("WScript.Shell")
'Loop while the process is running
Do While ProcessIsRunning(strProcess)
'Check to see if specified # of seconds have passed before terminating
'the process. If yes, then terminate the process
If w >= intWaitTime AND intWaitTime >= 0 Then
Call ProcessTerminate(strProcess)
Exit Do
End If
'If not running silent, post user prompt
If UCase(strMode) <> "S" Then
objWshShell.Popup strPrompt & String(c, "."), intPopupTimer, _
"WaitForProcess", 64
'Increment the counter.
'Reset the counter indicator if it's > 25 because
'we don't want it taking up a lot of screen space.
If c > 25 Then c = 1 Else c = c + 1
End If
'Increment the seconds counter
w = w + intPause + intPopupTimer
'Pause
Wscript.Sleep(intPause * 1000)
Loop
Set objWshShell = Nothing
End If
End Sub
The resulting dialog box is shown in Figure 1-10.
Figure 1-10. Displaying status messages in a dialog box
Note that if you are assembling a standalone script, it should contain sections 1, 2, 3, and one option from section 4. If you would rather incorporate this code into your existing script, you need only sections 2, 3, and one option from section 4. You'll also need to add the call statement that is at the end of the main routine section. All the code sections are self-contained, which makes them easy to import into existing scripts.
Running the Hack
To use this hack, type the code into Notepad (with Word Wrap disabled) and save it with a .vbs extension as WaitForProcess.vbs. Or, if you don't want to tire your fingers out, download it from the O'Reilly web site instead.
Here are a few sample command-line examples. This will wait indefinitely until Notepad is closed:
cscript WaitForProcess.vbs notepad.exe -1
This will wait silently and indefinitely until Notepad is closed:
cscript WaitForProcess.vbs notepad.exe -1 S
And this will wait 10 seconds before Notepad is forcefully closed:
cscript WaitForProcess.vbs notepad.exe 10
—Dan Thomson
I have seen a number of discussions regarding the need for a VB script that waits for a process to finish. The script in this hack does this and more: it waits for a process to finish and optionally terminates the process if it has not finished within a specified amount of time.
This code is a modified form of what I use to control my software deployments, and it has two purposes. First, the code is designed to be certain that the deployment script waits until the initiated software setup executable is fully finished before proceeding. Even though the majority of recent software releases do not require this functionality when being deployed, it is still required for some legacy installations. Second, the code can perform a forceful termination of an application if this functionality is required.
This script accepts three arguments: the name of the executable to wait for or terminate, the amount of time to wait before terminating the specified executable, and (optionally) a switch specifying that the script should run silently. Note that the script uses Windows Management Instrumentation (WMI) for the process-management tasks, so make sure you're running the latest WMI version on your machine.
The Code
The script consists of several sections, which are described inline in the following sections.
Main routine
First, command-line switches are read in the main body area:
Option Explicit
'''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
'
' File: vbsWaitForProcess.vbs
' Updated: Nov 2002
' Version: 1.0
' Author: Dan Thomson, myITforum.com columnist
' I can be contacted at dethomson@hotmail.com
'
' Usage: The command processor version must be run using cscript
' cscript vbsWaitForProcess.vbs notepad.exe 60 S
' or
' The IE and Popup versions can be run with cscript or wscript
' wscript vbsWaitForProcess.vbs notepad.exe -1
'
' Input: Name of executable (ex: notepad.exe)
' Time to wait in seconds before terminating the executable
' -1 waits indefinitely for the process to finish
' 0 terminates the process imediately
' Any value > 0 will cause the script to wait the specified
' amount of time in seconds before terminating the process
' Silent mode (S)
'
' Notes:
'
''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
On Error Resume Next
'Define some variables
Dim strProcess
Dim intWaitTime
Dim strSilent
'Get the command line arguments
strProcess = Wscript.Arguments.Item(0)
intWaitTime = CInt(Wscript.Arguments.Item(1))
strSilent = Wscript.Arguments.Item(2)
Call WaitForProcess (strProcess, intWaitTime, strSilent)
Check if process is running
Next, the ProcessIsRunning function determines if a process is running:
'''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
'
' Function: ProcessIsRunning
'
' Purpose: Determine if a process is running
'
' Input: Name of process
'
' Output: True or False depending on if the process is running
'
''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
Private Function ProcessIsRunning( strProcess )
Dim colProcessList
Set colProcessList = Getobject("Winmgmts:").Execquery _
("Select * from Win32_Process Where Name ='" & strProcess & "'")
If colProcessList.Count > 0 Then
ProcessIsRunning = True
Else
ProcessIsRunning = False
End If
Set colProcessList = Nothing
End Function
Terminate the process
In the next section, the ProcessTerminate function terminates a process:
'''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
'
' Function: TerminateProcess
'
' Purpose: Terminates a process
'
' Input: Name of process
'
''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
Private Function ProcessTerminate( strProcess )
Dim colProcessList, objProcess
Set colProcessList = GetObject("Winmgmts:").ExecQuery _
("Select * from Win32_Process Where Name ='" & strProcess & "'")
For Each objProcess in colProcessList
objProcess.Terminate( )
Next
Set colProcessList = Nothing
End Function
Wait for process to terminate
Finally, in the WaitForProcess subroutine, the user interface is set up, the script waits while the process is active, and the process termination is initiated. I created three versions of the subroutine in an effort to demonstrate a few methods for displaying status messages. For example, here's how to display these messages using the command console:
'''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
'
' Sub: WaitForProcess
'
' Purpose: Waits for a process
'
' Input: Name of process
' Wait time in seconds before termination.
' -1 will cause the script to wait indefinitely
' 0 terminates the process imediately
' Any value > 0 will cause the script to wait the specified
' amount of time in seconds before terminating the process
' Display mode.
' Passing S will run the script silent and not show any prompts
'
' Output: On screen status
'
' Notes: The version echos user messages in the command window via StdOut
'
''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
Private Sub WaitForProcess( strProcess, intWaitTime, strMode )
If ProcessIsRunning(strProcess) Then
Dim StdOut
Dim w : w = 0
Dim strPrompt
Dim intPause : intPause = 1
If UCase(strMode) <> "S" Then
strPrompt = "Waiting for " & strProcess & " to finish."
Set StdOut = WScript.StdOut
StdOut.WriteLine ""
StdOut.Write strPrompt
End If
'Loop while the process is running
Do While ProcessIsRunning(strProcess)
'Check to see if specified # of seconds have passed before terminating
'the process. If yes, then terminate the process
If w >= intWaitTime AND intWaitTime >= 0 Then
Call ProcessTerminate(strProcess)
Exit Do
End If
'If not running silent, post user messages
If UCase(strMode) <> "S" Then _
StdOut.Write "."
'Increment the seconds counter
w = w + intPause
'Pause
Wscript.Sleep(intPause * 1000)
Loop
If UCase(strMode) <> "S" Then
StdOut.WriteLine ""
Set StdOut = Nothing
End If
End If
End Sub
The result is shown in Figure 1-8.
Figure 1-8. Status message displayed in command console
Alternatively, here's some code for displaying status messages in Internet Explorer:
'''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
'
' Sub: WaitForProcess
'
' Purpose: Waits for a process
'
' Input: Name of process
' Wait time in seconds before termination.
' -1 will cause the script to wait indefinitely
' 0 terminates the process imediately
' Any value > 0 will cause the script to wait the specified
' amount of time in seconds before terminating the process
' Display mode.
' Passing S will run the script silent and not show any prompts
'
' Output: On screen status
'
' Notes: This version uses Internet Explorer for user messages
'
''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
Private Sub WaitForProcess( strProcess, intWaitTime, strMode )
If ProcessIsRunning(strProcess) Then
Dim objIntExplorer
Dim c : c = 0
Dim w : w = 0
Dim strPrompt
Dim intPause : intPause = 1
strPrompt = "Waiting for " & strProcess & " to finish."
'If not running silent, create reference to objIntExplorer
'This will be used for the user messages. Also set IE display attributes
If UCase(strMode) <> "S" Then
Set objIntExplorer = Wscript._
CreateObject("InternetExplorer.Application")
With objIntExplorer
.Navigate "about:blank"
.ToolBar = 0
.Menubar = 0 ' no menu
.StatusBar = 0
.Width=400
.Height = 80
.Left = 100
.Top = 100
.Document.Title = "WaitForProcess"
End With
'Wait for IE to finish
Do While (objIntExplorer.Busy)
Wscript.Sleep 200
Loop
'Show IE
objIntExplorer.Visible = 1
End If
Do While ProcessIsRunning(strProcess)
'Check to see if specified # of seconds have passed before terminating
'the process. If yes, then terminate the process
If w >= intWaitTime AND intWaitTime >= 0 Then
Call ProcessTerminate(strProcess)
Exit Do
End If
If UCase(strMode) <> "S" Then
objIntExplorer.Document.Body.InnerHTML = strPrompt & String(c, ".")
'Increment the counter.
'Reset the counter indicator if it's > 25 because
'we don't want it taking up a lot of screen space.
If c > 25 Then c = 1 Else c = c + 1
'Increment the seconds counter
w = w + intPause
End If
'Pause
Wscript.Sleep(intPause * 1000)
Loop
objIntExplorer.Quit( ) ' close Internet Explorer
Set objIntExplorer = Nothing ' release object reference
End If
End Sub
The resulting status message is shown in Figure 1-9.
Figure 1-9. Displaying status messages in Internet Explorer
Finally, here's code that uses the Popup method of Windows Scripting Host for displaying status messages:
''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
'
' Sub: WaitForProcess
'
' Purpose: Waits for a process
'
' Input: Name of process
' Wait time in seconds before termination.
' -1 will cause the script to wait indefinitely
' 0 terminates the process imediately
' Any value > 0 will cause the script to wait the specified '
' amount of time in seconds before terminating the process
' Display mode.
' Passing S will run the script silent and not show any prompts
'
' Output: On screen status
'
' Notes: This version uses WshShell.Popup for user messages
'
''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
Private Sub WaitForProcess( strProcess, intWaitTime, strMode )
If ProcessIsRunning(strProcess) Then
Dim objWshShell
Dim c : c = 0
Dim w : w = 0
Dim strPrompt
Dim intPopupTimer : intPopupTimer = 2
Dim intPause : intPause = 1
strPrompt = "Waiting for " & strProcess & " to finish."
'If not running silent, create reference to objWshShell
'This will be used for the user messages
If UCase(strMode) <> "S" Then _
Set objWshShell = CreateObject("WScript.Shell")
'Loop while the process is running
Do While ProcessIsRunning(strProcess)
'Check to see if specified # of seconds have passed before terminating
'the process. If yes, then terminate the process
If w >= intWaitTime AND intWaitTime >= 0 Then
Call ProcessTerminate(strProcess)
Exit Do
End If
'If not running silent, post user prompt
If UCase(strMode) <> "S" Then
objWshShell.Popup strPrompt & String(c, "."), intPopupTimer, _
"WaitForProcess", 64
'Increment the counter.
'Reset the counter indicator if it's > 25 because
'we don't want it taking up a lot of screen space.
If c > 25 Then c = 1 Else c = c + 1
End If
'Increment the seconds counter
w = w + intPause + intPopupTimer
'Pause
Wscript.Sleep(intPause * 1000)
Loop
Set objWshShell = Nothing
End If
End Sub
The resulting dialog box is shown in Figure 1-10.
Figure 1-10. Displaying status messages in a dialog box
Note that if you are assembling a standalone script, it should contain sections 1, 2, 3, and one option from section 4. If you would rather incorporate this code into your existing script, you need only sections 2, 3, and one option from section 4. You'll also need to add the call statement that is at the end of the main routine section. All the code sections are self-contained, which makes them easy to import into existing scripts.
Running the Hack
To use this hack, type the code into Notepad (with Word Wrap disabled) and save it with a .vbs extension as WaitForProcess.vbs. Or, if you don't want to tire your fingers out, download it from the O'Reilly web site instead.
Here are a few sample command-line examples. This will wait indefinitely until Notepad is closed:
cscript WaitForProcess.vbs notepad.exe -1
This will wait silently and indefinitely until Notepad is closed:
cscript WaitForProcess.vbs notepad.exe -1 S
And this will wait 10 seconds before Notepad is forcefully closed:
cscript WaitForProcess.vbs notepad.exe 10
—Dan Thomson
Hack 4 Automatically Log On After Booting
It's sometimes convenient to configure machines to log on automatically when booted. Here are three ways to do this.
In all versions of Windows that are based on Windows NT (including Windows 2000, Windows XP, and Windows Server 2003), a user is required to log on before he can use the system interactively. This is usually done by pressing Ctrl-Alt-Del and typing the user's credentials. Automatic logon is an option you can set to enable Windows to log on automatically using credentials that are stored in the Registry. To invoke automatic logon, you set Registry entries that define the user ID, the password, and the domain to be used to log on. Why use this feature? There are a number of reasons. As an IT professional, I have several of my home systems set up to do this, and it makes life simpler. Test systems in a lab might be another place to use this feature. I also use it all the time on virtual machine images I have running on my laptop.
Automatic login makes things simpler, but it creates a security hole. First, the credentials are stored in clear text in the Registry. Thus, anyone with remote Registry privileges can see the clear text user ID and password. Also, if you have automatic logon set on a laptop, anyone who turns on the laptop is automatically logged in as you. So use this feature carefully!
Manual Configuration
You can configure automatic logon manually by adding the following four key Registry entries: AutoAdminLogon, DefaultDomainName, DefaultUserName, and DefaultPassword. These entries inform Windows whether to attempt automatic logon and provide the credentials (username, password, and domain).
Start Registry Editor (StartRunregedit) and find the Registry key HKLM\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Winlogon, which is where the Registry values you set to control automatic logon are located. Two of these values, DefaultDomainName and DefaultUserName, already exist. DefaultDomainName is a string that holds the domain (or workstation) name where the user ID exists, and DefaultUserName is the user ID that Winlogon will attempt to use to log on. This username is authenticated against the domain (or workstation) name set in the DefaultDomainName setting.
Now, create two new values by right-clicking on Winlogon and selecting NewString Value, which will create new values of type REG_SZ. Name the first value AutoAdminLogon, and specify a value data of 1 to instruct Winlogon to attempt to use automatic logon. Name the second value DefaultPassword; this value specifies the password for the user set in the DefaultUserName setting.
The result will looking like Figure 1-7.
Figure 1-7. Enabling automatic logon by editing the Registry
Script Method
An easier way to configure automatic logon on your machines is to use two VBScript scripts, one to enable automatic logon and the other to disable it. Here's the script for enabling it:
' Script to turn on automatic logon
' (c) Thomas Lee 2002
' Freely distributed!
Dim Prompt, oWSH,UserName, UserPass, UserDomain
set oWSH = WScript.CreateObject("WScript.Shell")
' get user name
Prompt = "Enter the autologon user name"
UserName = InputBox(Prompt, Title, "")
' get password
Prompt = "Enter the autologon user password for " & UserName
UserPass = InputBox(Prompt, Title, "")
' get domain
Prompt = "Enter the autologon user domain for " & UserName
Userdomain = InputBox(Prompt, Title, "")
' now set these in the Registry
oWSH.RegWrite "HKLM\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Winlogon\AutoAdminLogon",
"1","REG_SZ"
oWSH.RegWrite "HKLM\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Winlogon\
DefaultDomainName", UserDomain, "REG_SZ"
oWSH.RegWrite "HKLM\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Winlogon\
DefaultUserName", UserName, "REG_SZ"
oWSH.RegWrite "HKLM\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Winlogon\
DefaultPassword", UserPass, "REG_SZ"
' ensure the change is persistent!
oWSH.RegWrite "HKLM\SOFTWARE\Microsoft\WindowsNT\CurrentVersion\Winlogon\ForceAutoLogon",
"1", "REG_SZ"
' All done
And here's the script for disabling automatic logon:
' Script to remove autoadmin logon
' (c) Thomas Lee 2002
' Freely distributed!
Option Explicit
On Error Resume Next
'Declare variables
Dim Prompt, oWSH
'Set the Windows Script Host Shell
set oWSH = WScript.CreateObject("WScript.Shell")
' delete the relevant keys
oWSH.RegDelete "HKLM\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Winlogon\
AutoAdminLogon"
oWSH.RegDelete "HKLM\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Winlogon\
DefaultDomainName"
oWSH.RegDelete "HKLM\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Winlogon\
DefaultUserName"
oWSH.RegDelete "HKLM\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Winlogon\
DefaultPassword"
' All done - say goodbye!
Legend = "Autoadmin removed - have a nice day!"
MyBox = MsgBox (legend, 4096, "We're Done")
You can use Notepad to type these scripts and save them with a .vbs file extension, or download autoadminlogon.vbs and noautoadminlogon.vbs from http://www.oreilly.com/catalog/winsvrhks/.
Sysinternals Tool
Finally, here's one more way to configure automatic logon on machines. Mark Russinovich, of Sysinternals fame, also wrote a simple program to do this. You can download the program and the source from http://www.sysinternals.com/ntw2k/source/misc.shtml#AutoLogon, where you can find lots of other great tools.
—Thomas Lee
In all versions of Windows that are based on Windows NT (including Windows 2000, Windows XP, and Windows Server 2003), a user is required to log on before he can use the system interactively. This is usually done by pressing Ctrl-Alt-Del and typing the user's credentials. Automatic logon is an option you can set to enable Windows to log on automatically using credentials that are stored in the Registry. To invoke automatic logon, you set Registry entries that define the user ID, the password, and the domain to be used to log on. Why use this feature? There are a number of reasons. As an IT professional, I have several of my home systems set up to do this, and it makes life simpler. Test systems in a lab might be another place to use this feature. I also use it all the time on virtual machine images I have running on my laptop.
Automatic login makes things simpler, but it creates a security hole. First, the credentials are stored in clear text in the Registry. Thus, anyone with remote Registry privileges can see the clear text user ID and password. Also, if you have automatic logon set on a laptop, anyone who turns on the laptop is automatically logged in as you. So use this feature carefully!
Manual Configuration
You can configure automatic logon manually by adding the following four key Registry entries: AutoAdminLogon, DefaultDomainName, DefaultUserName, and DefaultPassword. These entries inform Windows whether to attempt automatic logon and provide the credentials (username, password, and domain).
Start Registry Editor (StartRunregedit) and find the Registry key HKLM\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Winlogon, which is where the Registry values you set to control automatic logon are located. Two of these values, DefaultDomainName and DefaultUserName, already exist. DefaultDomainName is a string that holds the domain (or workstation) name where the user ID exists, and DefaultUserName is the user ID that Winlogon will attempt to use to log on. This username is authenticated against the domain (or workstation) name set in the DefaultDomainName setting.
Now, create two new values by right-clicking on Winlogon and selecting NewString Value, which will create new values of type REG_SZ. Name the first value AutoAdminLogon, and specify a value data of 1 to instruct Winlogon to attempt to use automatic logon. Name the second value DefaultPassword; this value specifies the password for the user set in the DefaultUserName setting.
The result will looking like Figure 1-7.
Figure 1-7. Enabling automatic logon by editing the Registry
Script Method
An easier way to configure automatic logon on your machines is to use two VBScript scripts, one to enable automatic logon and the other to disable it. Here's the script for enabling it:
' Script to turn on automatic logon
' (c) Thomas Lee 2002
' Freely distributed!
Dim Prompt, oWSH,UserName, UserPass, UserDomain
set oWSH = WScript.CreateObject("WScript.Shell")
' get user name
Prompt = "Enter the autologon user name"
UserName = InputBox(Prompt, Title, "")
' get password
Prompt = "Enter the autologon user password for " & UserName
UserPass = InputBox(Prompt, Title, "")
' get domain
Prompt = "Enter the autologon user domain for " & UserName
Userdomain = InputBox(Prompt, Title, "")
' now set these in the Registry
oWSH.RegWrite "HKLM\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Winlogon\AutoAdminLogon",
"1","REG_SZ"
oWSH.RegWrite "HKLM\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Winlogon\
DefaultDomainName", UserDomain, "REG_SZ"
oWSH.RegWrite "HKLM\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Winlogon\
DefaultUserName", UserName, "REG_SZ"
oWSH.RegWrite "HKLM\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Winlogon\
DefaultPassword", UserPass, "REG_SZ"
' ensure the change is persistent!
oWSH.RegWrite "HKLM\SOFTWARE\Microsoft\WindowsNT\CurrentVersion\Winlogon\ForceAutoLogon",
"1", "REG_SZ"
' All done
And here's the script for disabling automatic logon:
' Script to remove autoadmin logon
' (c) Thomas Lee 2002
' Freely distributed!
Option Explicit
On Error Resume Next
'Declare variables
Dim Prompt, oWSH
'Set the Windows Script Host Shell
set oWSH = WScript.CreateObject("WScript.Shell")
' delete the relevant keys
oWSH.RegDelete "HKLM\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Winlogon\
AutoAdminLogon"
oWSH.RegDelete "HKLM\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Winlogon\
DefaultDomainName"
oWSH.RegDelete "HKLM\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Winlogon\
DefaultUserName"
oWSH.RegDelete "HKLM\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Winlogon\
DefaultPassword"
' All done - say goodbye!
Legend = "Autoadmin removed - have a nice day!"
MyBox = MsgBox (legend, 4096, "We're Done")
You can use Notepad to type these scripts and save them with a .vbs file extension, or download autoadminlogon.vbs and noautoadminlogon.vbs from http://www.oreilly.com/catalog/winsvrhks/.
Sysinternals Tool
Finally, here's one more way to configure automatic logon on machines. Mark Russinovich, of Sysinternals fame, also wrote a simple program to do this. You can download the program and the source from http://www.sysinternals.com/ntw2k/source/misc.shtml#AutoLogon, where you can find lots of other great tools.
—Thomas Lee
Hack 3 Find and Replace Registry Keys from a Command Line
Using the Regfind utility, you can easily search the Registry for a value, regardless of the key, and replace it.
Regfind (from the Windows 2000 Server Resource Kit) can be an invaluable tool when you need change a Registry key that you know the value for but when do not necessarily know the full path. Recently tasked with changing the hardcoded DNS server IP on all the servers in our organization, I was pleasantly surprised when I located this gem. The problem with trying to change the DNS server entry in the Registry is that all the IP parameters are broken up by a hashed ID. The ID references several things, but most of them have to do with the network card. Regfind allows you to search a set of subkeys in the Registry for a specific value and, when found, replace it. Another real beauty of this program is that it will work remotely; all you need to do is supply it with a list of machines and let it go. Using a list of computer names (generated from SMS, Server Manager, or AD Users and Computers), combined with two batch files, you can make sweeping changes in a dynamic environment.
The Code
Here's an example of how to change the DNS server entry on all servers in your organization. First, create a batch file called Regchange2.bat with the following syntax:
regfind -m \\%1 -p HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\Tcpip\parameters "OLDIP" -r "NEWIP"
You will obviously want to replace OLDIP with the old DNS server IP and replace NEWIP with the new DNS server IP.
Now, create a second batch file called regchange1.bat with the following syntax:
for /F %%A in (servers.txt) do (call regchange2.bat %%A)
This searches the servers.txt file for computer names and passes them to the regchange2.bat file as a command-line argument.
Now you need to create a list file for your batch files to use. Create a listing of servers that need to have their DNS IP's changed and save that list as servers.txt. An SMS report or a copy/paste from the server manager will suffice, or you can create the file manually if you like.
Running the Hack
Now, simply run the regchange1.bat batch file by calling it from a logon script and watch all your servers have their IP settings changed!
This is just one simple example of how to use Regfind. There are many command-line arguments, so please examine those to meet your needs.
—Donnie Taylor
Regfind (from the Windows 2000 Server Resource Kit) can be an invaluable tool when you need change a Registry key that you know the value for but when do not necessarily know the full path. Recently tasked with changing the hardcoded DNS server IP on all the servers in our organization, I was pleasantly surprised when I located this gem. The problem with trying to change the DNS server entry in the Registry is that all the IP parameters are broken up by a hashed ID. The ID references several things, but most of them have to do with the network card. Regfind allows you to search a set of subkeys in the Registry for a specific value and, when found, replace it. Another real beauty of this program is that it will work remotely; all you need to do is supply it with a list of machines and let it go. Using a list of computer names (generated from SMS, Server Manager, or AD Users and Computers), combined with two batch files, you can make sweeping changes in a dynamic environment.
The Code
Here's an example of how to change the DNS server entry on all servers in your organization. First, create a batch file called Regchange2.bat with the following syntax:
regfind -m \\%1 -p HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\Tcpip\parameters "OLDIP" -r "NEWIP"
You will obviously want to replace OLDIP with the old DNS server IP and replace NEWIP with the new DNS server IP.
Now, create a second batch file called regchange1.bat with the following syntax:
for /F %%A in (servers.txt) do (call regchange2.bat %%A)
This searches the servers.txt file for computer names and passes them to the regchange2.bat file as a command-line argument.
Now you need to create a list file for your batch files to use. Create a listing of servers that need to have their DNS IP's changed and save that list as servers.txt. An SMS report or a copy/paste from the server manager will suffice, or you can create the file manually if you like.
Running the Hack
Now, simply run the regchange1.bat batch file by calling it from a logon script and watch all your servers have their IP settings changed!
This is just one simple example of how to use Regfind. There are many command-line arguments, so please examine those to meet your needs.
—Donnie Taylor
Subscribe to:
Posts (Atom)