In the last few articles in this series we've learned about some of the concepts and issues surrounding remote scripting on Windows platforms. In this article we'll describe two tricks relating to remote scripting using WMI scripts written in VBScript.
First, how about a tip from the Windows Vista Resource Kit? This Resource Kit is the book for IT pros who plan on deploying Windows Vista in mid- and large-sized enterprise networking environments, and I was privileged to be lead author on this project and have permission from Microsoft Press to share a few excerpts with you from this terrific book.
Here's the first tip: It's simple but smart, but we need some background info first, so here goes. I'm sure you know by now that there are a few ways you can launch scripts on Windows machines. For example, if you have the script ChangeIPAddress.vbs on a machine, you could launch it by performing the following:
- Double-click on the .vbs file or on a shortcut to that file.
- Click Start, then Run. Type ChangeIPAddress.vbs and click OK.
- Open a command prompt and navigate to the directory where the script is located, and type ChangeIPAddress.vbs, and press ENTER.
Now what happens when you do these things depends on what your default settings are for the Windows Script Host (WSH) on your machine. WSH is a language-independent scripting host for scripting engines i.e. WSH uses the VBScript scripting engine to run VBScript scripts you try to run, so WSH acts as the "environment" within which your script runs. But WSH actually has two default script hosts:
- Wscript.exe, which provides a Windows-based dialog box for setting script properties and displays script output as windowed output
- Cscript.exe, which lets you configure script properties and display script output from a command prompt
Let's see the difference between them in case you're not aware or have forgotten. I'll use the ChangeIPAddress.vbs script from Part 2 of this managing Windows networks series to illustrate. Let's open a command prompt on a Windows Vista machine and use this script to change the machine's IP address to 172.16.11.173. Now the first thing to note is that changing network configuration settings requires local admin credentials on the machine, so to do this I need to right-click on the command prompt shortcut under Accessories and select Run As Administrator. When I do this a User Account Control (UAC) prompt appears, so I have to either click Continue (if my user account is a member of the local Administrators group on the machine) or enter the credentials of a local admin account (if my user account is only a member of the local Users group on the machine).
Anyway, one way or another I get an admin-level command prompt window open, and I type the command to change the machine's address (Figure 1):
Figure 1: Trying to change IP address using script
Now what happens when I press ENTER is that a few seconds later the following dialog box appears (Figure 2):
Figure 2: Output of script appears as a dialog box
Where did this message come from? Well, remember that our script Change IPAddress.vbs included the following lines at the end of the script:
'Display result or error code
If errEnableStatic=0 Then
Wscript.Echo "Adapter's IP address has been successfully changed to " & strAddress
Wscript.Echo "Changing the adapter's address was not successful. Error code " & errEnableStatic
So what's happening is that the Wscript.Echo statement is displaying windowed output (i.e. popping up a dialog box) instead of displaying the output within the command prompt window itself. The reason for that is that by default, Wscript.exe is the default script host and that's what this host does i.e. it displays all output using pop-up windows like this.
How can we stop this behavior and get the script output to display within the command prompt window instead? Well, one way would be to explicitly invoke the command-line script host Cscript.exe when you run the script. You can do this as follows (Figure 3):
Figure 3: Using cscript.exe to make script output appear within the command prompt window
But it's a pain to always have to type Cscript before you type the script name like this, so instead we can set Cscript.exe as the default script host for all WSH invocations by doing this (Figure 4):
Figure 4: Making cscript.exe the default script host
Now we can run the script and display its output from within the command prompt window without having to explicitly type Cscript first (Figure 5):
Figure 5: Since Cscript.exe is the default script host, the script's output is displayed within the command prompt window
Now you probably knew all this already, but here's the issue. Say we have a bunch of scripts like ChangeIPAddress.vbs that we want to run remotely by deploying them to target machines as login scripts or startup scripts using Group Policy. And say some of these scripts have Wscript.Echo statements in them to generate script output. What will happen when one of these scripts is deployed to a remote machine and runs on the machine? A series of pop-up windows will appear on the user's desktop as the script runs on the user's machine, and the user will have to click OK, OK, OK, etc. until all the pop-ups are gone and the script has finished its work. What a drag! Is there any way around this?
Well, you could get around it two ways. First, you could edit all your scripts to remove or comment out all the Wscript.Echo statements so that the script doesn't generate any output. That's a bit of a drag though, especially if you have a ton of scripts to mess around with.
So what's the second method? Aha, here's the tip I wanted to share with you, excerpted with permission from the Windows Vista Resource Kit:
In an Active Directory environment in which Group Policy is being used to manage desktop computers, you can change the default script host from Wscript.exe to Cscript.exe on all computers in an OU by following these steps:
- Use Notepad to create a text file named ChangeToCscript.bat with the following two lines of text in it:
cscript //h:cscript //s
- Open the GPO that is linked to the OU and navigate to Computer Configuration\Windows Settings\Scripts\Startup.
- Double-click the Startup policy setting to open its properties sheet.
- Click the Show Files button and copy and paste ChangeToCscript.bat from Windows Explorer to the subfolder of SYSVOL where Startup scripts must be located.
- Click the Add button on the properties sheet for the Startup policy setting.
- Click the Browse button and select ChangeToCscript.bat.
- Close all properties sheets.
- Adding this startup script will cause the default script host on the targeted computers to be changed from Wscript.exe to Cscript.exe on the next reboot of these computers, and this will work regardless of whether the targeted users are standard users or local admins on their computers.
NOTE: ChangeToCscript.bat must be run as a Startup script and not a Logon script. If you run it as a Logon script, it will only work when the targeted users are local admins on their computers.
Pretty cool what you can do with only a two-line batch file, isn't it? Now you can deploy any scripts you want to your targeted computers and not have to worry about users getting tons of pop-ups appearing on their screens.
Tip 2: Performing "runAs" without having to specify credentials
The second tip was submitted to me by one of our readers after he read one of my previous articles in this series. I thought it was pretty cool so I asked him if I could share it with other readers of WindowsNetworking.com and he said I could do this, so I'll just quote from his emails directly and you can hear him explain his trick:
The way I perform 'runAs' without having to enter credentials is to use the local administrator account for WMI, and then store the local admin password in a text file on a network share that is protected by NTFS permissions. For example, if 'tech1' and 'tech4' and 'tech5' are normal domain accounts (not domain admins), but these users are authorized to run WMI scripts, then I give those accounts NTFS permission access to the text file containing the local administrator password. I then have the script import that password and connect using Set objWMIService = GetObject("winmgmts:\\" & strComputer & "\root\cimv2", strComputer & "\Administrator", strImportedPassword)
Well, the above is not 100% true. I actually use:
Set objSWbemLocator = CreateObject("WbemScripting.SWbemLocator")
Set objWMIService = objSWbemLocator.ConnectServer(strComputer, "root\cimv2", strComputer & "\administrator", strPWD, "", "", &H80)
Set objReg = objSWbemLocator.ConnectServer(strComputer, "root\default", strComputer & "\administrator", strPWD, "", "", &H80)
Set oReg = objReg.Get("StdRegProv")
…which accomplishes the same thing.
Connecting with the local administrator account has another interesting side effect; it does not leave a copy of your domain admin account profile on the PC under Documents and Settings. When using my domain account, I had a few users ask "Why were you connected to my PC?" and wondering what snooping was taking place. By using the local admin account, they don't realize anyone had connected (they are blocked from seeing the security log).
For the record, in practice we have a couple of different local administrator passwords in use here; so the script imports a list and tries them one by one until it is successful or runs out of options.
Pretty cool, eh? Do you have any scripting tips or tricks you'd like to share? Email me at firstname.lastname@example.org and I'll share some more submissions in a future article in my column here.