In-Depth

5 Essential Scripts

Time is money and money is tight, but these five scripts can help any admin get more done every day.

The old cliché "time is money" is probably more true for systems administrators than anyone else. In today's post-boom, "do more with less" economy, you've got no choice but to focus on efficiency in doing your job. With organizations keeping IT headcount to a minimum, it's crucial to practice proactive, efficient systems administration.

Smart systems administrators use VBScript to fill in the gaps between native Windows tools. With a strong handle on VBScript and its connections to your server's WMI store, you'll be amazed at how efficient you can become.

What follows are five of my most essential scripts, the ones at the top of my toolbox. I think you'll find them as useful for you as they are for me.

Don't Play the Waiting Game
If you've ever had to sit and watch a batch file copy a huge amount of data from one share to another, you've probably said to yourself, "There has to be a way this can just notify me when it's done!" Well, there is.

This first example is one of the simplest e-mail scripts you can write. If you're familiar with writing batch files, simply create this file with a .VBS extension in the same folder as your batch file. Then, call this script as the very last line in your batch file using "CALL E-MAIL.VBS." Replace the entries for From, To, Subject and Textbody with values appropriate for your environment:

Set objE-mail = CreateObject("CDO.Message")
objE-mail.From = "[email protected]"
objE-mail.To = "[email protected]"
objE-mail.Subject = "Script complete! "
objE-mail.Textbody = "The script is complete. "
objE-mail.Send

If your mail server prevents unauthorized mail relaying, you'll want to reconfigure it to allow for mail relaying from the IP address of the system running the script.

To make this script even more valuable, replace your e-mail address in the To field with the e-mail address of your text pager. Now, you're free to leave work early today.

For options that make this script even more powerful, showing how to e-mail yourself a results text file, and make the script run on a system without SMTP or Outlook Express, which this version requires, click here.

Evict DHCP
One of the biggest bottlenecks when modifying your site's DHCP configuration is the long wait for DHCP clients to pick up new information. A DNS or WINS change can take days or weeks to complete while you wait for half your DHCP lease time to expire.

In the past, the only way to accelerate this process was to log in and run "ipconfig –release" and "ipconfig –renew" on each machine—a big chore for a large network.

Instead, use VBScript to force the DHCP lease renewal. The Win32_NetworkAdapterConfiguration class is accessed through WMI, and provides more than 60 different data points and 40 methods to update your system's network configuration.

This script uses the RenewDHCPLeaseAll method to instruct the remote system to ignore its lease duration and run an "ipconfig –release" and "ipconfig –renew" equivalent.

RebootFile = "computers.txt"
LogFile = "results.txt"

Set fso = CreateObject("Scripting.FileSystemObject")
Set f = fso.OpenTextFile(RebootFile, 1, True)
Set objTextFile = fso.OpenTextFile(LogFile, 2, True)

On Error resume next
Do While f.AtEndOfLine <> True
strComputer = f.ReadLine
Set objWMIService = GetObject("winmgmts:" & "{impersonationLevel=impersonate}!\\" & strComputer & "\root\cimv2")
If Err.Number <> 0 Then
objTextFile.WriteLine(intCount & ". " & strComputer & " is not responding.")
Err.Clear
Else
Set objNetworkSettings = objWMIService.Get("Win32_NetworkAdapterConfiguration")
objNetworkSettings.RenewDHCPLeaseAll()
objTextFile.WriteLine(strComputer & " has been renewed.")
End If
Loop

To use this script, create a file named "computers.txt" which lists computers that need DHCP leases renewed—one per line. This file should reside in the same folder as the script itself.

For a little error checking, the script attempts to connect to the WMI store on each machine. If an error occurs, it logs the error and continues to the next machine. If no errors happen, it goes on to renew the lease and log the result.

Because the client attempts to keep the same IP as it renews, this can be done with little impact to users.

As an aside, this format can be used as a boilerplate for lots of different scripts that view or modify settings on large numbers of remote machines. As you grow in experience, you'll find plenty that require nothing more than replacing some syntax with other WMI information. An example of this is next.

Give 'Em the Boot
If you've ever worked on a help desk, called into a help desk, or even heard of a help desk, you're familiar with the oft-provided Help Desk Solution: "Have you tried rebooting?" Poorly written applications, memory leaks and many Microsoft patches require reboots to ensure that the machine functions correctly.

Here's a way to reboot a list of systems with a single keystroke. Replace the contents of the code between "Else" and "End if" statements in the previous script with the following:

Set colOperatingSystems = objWMIService.ExecQuery("Select * from Win32_OperatingSystem")
objTextFile.WriteLine(strComputer & " is rebooting.")
For Each objOperatingSystem in colOperatingSystems
ObjOperatingSystem.Reboot()
Next

Unlike the Resource Kit tool SHUTDOWN.EXE, this script doesn't prompt a dialog box when it gets to a computer that doesn't accept the shutdown. Like the previous script, if an error occurs when it attempts to connect to the machine, it will log the error and continue to the next machine.

A useful implementation of this script is to run it via a Scheduled Task to enable weekly reboots of your network's computers.

You can even integrate this script with the SQL back-end of Microsoft Systems Management Server (SMS). SMS can provide lists of machines in the form of SMS Collections which give you granular control over what gets rebooted. Later on, we'll discuss how to create ODBC connections to an SMS server to enable this.

Cure Terminal Problems
Our next script is an excellent example of how to integrate other command-line tools into your homemade scripts to create something more usable.

This script uses a combination of VBScript and Sysinternals' freeware PSExec tool (available for download at www.sysinternals.com) to query remote Windows Terminal Servers for their user information and report the results into a text file. PSExec allows you to start processes on remote systems and return the command-line results back to the local screen.

Using PSExec within a VBScript script gives you an application that can be scheduled to run hourly via Scheduled Tasks. You can use the historical user count and username data on each Terminal Server as a troubleshooting aid when problems arise.

On Error Resume Next
Set objFSO = CreateObject("Scripting.FileSystemObject")
Set objShell = CreateObject("WScript.Shell")
objTermSrv = WScript.Arguments.Item(0)
Set objResultsFile = objFSO.OpenTextFile(objTermSrv & " TermServ_User_Audit.txt", 8, True)

objTempFile = objFSO.GetTempName
ObjShell.Run("%comspec% /C psexec.exe \\" & objTermSrv & " query user > " & ObjTempFile), 1, True

Set objTextFile = objFSO.OpenTextFile(objTempFile, 1, True)

objResultsFile.WriteLine(Date & " " & Time)
Do While objTextFile.AtEndOfStream <> TRUE
objLineCheck = objTextFile.ReadLine
If mid(objLineCheck, 24, 3) = "rdp" Then
objResultsFile.WriteLine(objLineCheck)
End If
Loop

objTextFile.Close
objFSO.DeleteFile(objTempFile)

In this script, the WScript.Arguments.Item allows you to specify a server to check at the command prompt. To run this script against a system called TermServer1, enter TermServ_ User_Audit.vbs TermServer1 at the command prompt.

The results file created when running this script includes, among other things, a date and time stamp for when the script was run, usernames of those currently logged in, their logon time and idle time.

The integration with PSExec.exe can be seen in the ObjShell.Run line. Immediately prior to this, notice the use of GetTempName to generate a randomly named file. We pipe our results to this file from the PSExec command using ObjShell.Run. In order for ObjShell.Run to work properly, we actually launch the Windows Command Interpreter "cmd" with the /c switch, which tells it to "run the next command, and then exit."

The online version uses the text manipulation capabilities of VBScript to modify the results from our Query User command into a more-readable .CSV file.

Leverage the Power of SMS
Microsoft's SMS is a convenient repository to find last logged-on user information and other current data about each computer on your network.

What you may not know is that you can query SMS's SQL database information directly through ODBC using VBScript.

The script allows you to enter a username at the command prompt when calling the script, then queries SMS for the machines where that username is the last logged-on user. By returning this information, you can get a helpful view of the machines a user typically logs into and the other users that may have touched those machines in the past.

This information is especially useful for your help desk, which will no longer need to ask each user for their computer name—and in many cases, teach them how to locate it.

On Error Resume Next
strUserName = WScript.Arguments.Item(0)

Set Connection = CreateObject("ADODB.Connection")
Set RecordSet = CreateObject("ADODB.Recordset")
SQLConnection = "Driver={SQL Server};Server=SMSServer;Database=SMS_ABC;UID=UserName;PWD=Password"
Connection.open SQLConnection
strSQLQuery = "SELECT Name0 from v_R_System WHERE User_Name0 LIKE '" & strUserName & "'"
RecordSet.Open strSQLQuery, Connection, 3, 3

While Not RecordSet.EOF
OutputResults = OutputResults & RecordSet("Name0") & vbCrLf
RecordSet.MoveNext
Wend

WScript.Echo(OutputResults)
RecordSet.Close
Connection.Close

In order for this script to run, you'll need to create a SQL user in your database with db_datareader rights. Modify the database connection information (the line that starts "SQLconnection" and ends "WD=password") to include your SMS server and database, and the username and password the script will use to log in.

In the online version of this script, we add a few more useful capabilities, including reconfiguring the results from a pop-up window to a command-line result. Also added is a "-v" switch to provide more information about logons on that user's machine.

Use these scripts as a starting point. Once you get used to using scripts in your environment, you'll want to use more, and start to develop your own. In no time, you'll become a scripting expert and find many new ways to make your time much more productive.

More Information

Expanded Versions of These Scripts

One of the best parts about using scripting instead of relying on the Windows GUI is the ability to format your results in any way you like. Tired of flipping through pages and pages of Network Settings inside of My Network Places? Build a script to give you the results in a text file. Hate the six-clicks-and-scroll you do to check entries in DNS? Write a script to help you do it from the command prompt.
Even better, by building scripts to view and modify remote machines in addition to your own, you can now update settings all over your network without leaving your desk. Changing the URL of your Web server? Don’t email your users to have them update their Internet Explorer Favorites—do it for them! There’s not a lot you can’t do.

Once you’ve started building your quiver of scripts, you’ll find yourself retooling and expanding them to include additional functionality as the need arrives. In the next few paragraphs, let’s take a look at how we can expand a few of the scripts shown in this month’s Redmond magazine (full story at top of page). Note: You can download all three modified scripts at one time here (.txt format), or use the links below to download the expanded scripts individually. To view the original scripts, see the story above.

E-mail Script Results…and Stop Staring at your Screen

Click here to download this modified script (.txt download).

This expanded version of our e-mail script adds two very useful features over the one originally shown. First, by adding in the lines:

objEmail.Configuration.Fields.Item("http://schemas.microsoft.com/cdo/configuration/sendusing") = 2
objEmail.Configuration.Fields.Item("http://schemas.microsoft.com/cdo/configuration/smtpserver") = strSMTPServer
objEmail.Configuration.Fields.Item("http://schemas.microsoft.com/cdo/configuration/smtpserverport") = 25
objEmail.Configuration.Fields.Update

we’ve added in the ability to use this script on a computer that doesn’t have SMTP installed. These four lines reference the http://schema.microsoft.com/cdo/configuration namespace and identify the local network’s SMTP server and port. Second, by creating a File System Object and pointing it to a text file, we’ve now got the ability to e-mail a text file. Note also that we’ve cleaned up the script and moved to the top all the variables we’ll eventually modify.

When this script runs, it leverages the local system’s File System Object to read in your results file. Here, we read in the file assigned to the variable strResultsFile using the ReadAll method, then use that variable as the text of the message. Note that this results file must reside in the same folder as the script.

Combine .EXE’s and VBScript To Get Terminal Services User Audits

Click here to download this modified script (.txt download).

To expand our Terminal Services User Audit script, we use the text modification capabilities of VBScript to convert the standard result from “query user” into something that’s more useable to us. Since the data that arrives would be useful in tabular format, it’s most convenient to drop it into a .CSV file. By doing this, we need only double-click the file to open it in Microsoft Excel.

We only need to make a few edits to the script to get it into that format. Note the following addition:

objName = rtrim(mid(objLineCheck, 2, 12))
objConcatLine = objConcatLine & objName & ","
objUserCount = objUserCount + 1

Rather than simply passing the results from the “query user” command directly into the results file, we do three things:

  1. For every line with a reference to “rdp”, we use the text operators rtrim and mid to grab the username.
  2. We concatenate every username into a single line with the objConcatLine variable.
  3. We increment a counter for each user to give us a total user count.

In the line:

objResultsFile.WriteLine(Date & "," & Time & "," & objUserCount & "," & objConcatLine)

we write to our .CSV file the line concatenating the date and time of the audit, the total user count, and every username currently logged in. Now, when we open our .CSV file, Excel automatically separates each comma-separated entry into columns.

Since we’re appending to our results file every time we run this script, we can now use Task Scheduler to run it hourly. Over time, we’ll get a good idea of not only how many users are using our Terminal Servers, but the names of those users as well.

SMS Gives You LLU

Click here to download this modified script (.txt download).

For the expansion of our Last Logged On User script, you’ll notice the first new section starting wtih the line: If strVerbose = "-v" Then. This section is only called when a “-v” switch is passed into the script after the username.

With the “-v” switch, our script runs in “verbose mode,” giving us not only the Last Logged On User information from SMS, but also information about other users who have logged on to the user’s machine—useful for when we want to know who else has been on a user’s machine.

With the “-v” switch enabled, the script does the same call to our SMS database as in the basic script. It also does a little more with the recordset, using it in a Win32_Directory.Name WMI query. Although it looks complicated, the syntax of our Set colSubFolders query grabs the subfolders of C:\Documents and Settings on the target machine. It then reports on the names and last modified datestamp of each. Notice here, like before, we’re using VBScript’s native text manipulation tools—mid and left— to give us just the results text we need.

You’ll also note in the next section with the line Wscript.StdOut.Write(RecordSet("Name0")) & vbCrLf our use of WScript.Echo has changed to use Wscript.StdOut.Write. This method, which uses CScript rather than WScript, allows us to send the results to the same command-line window where the script was run. No more annoying message boxes!

To run this easily with CScript, you’ll want to create the following little batch file—LLU.BAT— and drop it and your LLU.VBS file in the System32 folder.

@echo off
cscript //Nologo %systemroot%\llu.vbs %1 %2

Now you can run it from the command line by typing llu [-v].

Be Fruitful and Manipulate
With just these few examples and a little research, you’ll undoubtedly find yourself noticing lots of tasks in your daily administration you can automate. Microsoft has made plenty of resources available to help you learn. Check out their book, the Microsoft Windows 2000 Scripting Guide and definitely spend some time with the Scripting Guys at Microsoft (links to both resources below). Good luck and happy scripting! —Greg Sheilds


More Scripting Answers

  • If you still haven’t discovered the wonders of digging into WMI and modifying Active Directory information using VBScript, go immediately to your nearest bookstore and buy the Microsoft Windows 2000 Scripting Guide. Not quite a book on programming, this well-written tome on VBScript uses common English and plenty of examples to get you quickly into down-and-dirty scripting.
  • You can get lots of information, sample scripts, and even a “Script-o-matic” tool that teaches as it builds helpful scripts from Microsoft's TechNet Script Center. Look for a downloadable HTML Help Format file that compiles everything you need to know into a single searchable file.
  • Extremely detailed information about the VBScript language syntax can be obtained from MSDN here.
  • Noted scripting guru (and Redmond contributing editor) Don Jones has his own site dedicated to scripting at ScriptingAnswers.com.

Featured