Previous Page
Next Page

Do While...Loop

The Do While...Loop command enables you to run a script as long as a certain condition is in effect. If you were in Kauai, the Do While...Loop might look like this:

Do While sun_is_shining
  Surf
Loop

Do While...Loop means that as long as the specified condition remains true, the listed action continues to performit just loops around and around. In our silly preceding example, as long as the sun is shining, we surf. (Not a bad way to spend an afternoon.)

Just the Steps

To use the Do While...Loop

1.
On a new line in the script, type Do While followed by a condition to be tested.

2.
On the next line, type the command to be performed.

3.
On the next line, type Loop.


In the MonitorForChangedDiskSpace.vbs script, you monitor the disk space on a server. If the free space changes, then a message is echoed to the screen. Read through this script and see which parts you can identify. After you finish reading it, we'll discuss it.

MonitorForChangedDiskSpace.vbs

Option Explicit
'On Error Resume Next
Dim colMonitoredDisks
Dim objWMIService
Dim objDiskChange
Dim strComputer
Dim startTime, 'snapTime used for timer Function

Const LOCAL_HARD_DISK = 3 'the driveType value from SDK
Const RUN_TIME = 10 'time to allow the script to run in seconds
strComputer = "."
startTime = Timer

Set objWMIService = GetObject("winmgmts:\\" & strComputer & "\root\cimv2")
Set colMonitoredDisks = objWMIService.ExecNotificationQuery _
   ("Select * from __instancemodificationevent within 10 where " _
     & "TargetInstance ISA 'Win32_LogicalDisk'")
Do While True
snapTime = Timer
 Set objDiskChange = colMonitoredDisks.NextEvent
  If objDiskChange.TargetInstance.DriveType = LOCAL_HARD_DISK Then
  WScript.echo "diskSpace on " &_
  objDiskChange.TargetInstance.deviceID &_
  " has changed. It now has " &_
  objDiskChange.TargetInstance.freespace &_
  " Bytes free."
  End If
  If (snapTime - startTime) > RUN_TIME Then
  Exit Do
  End If
Loop
WScript.Echo FormatNumber(snapTime-startTime) & " seconds elapsed. Exiting now"
WScript.quit

Header Information

The Header information section, as shown in the next segment of code, begins with the Option Explicit command. You can think of Option Explicit as a cheap spelling checker.

Because it forces you to list all your variables, if you later misspell a variable, VBScript gives you an error, such as the one shown in Figure 2-1.

Figure 2-1. The Option Explicit command acts like a spelling checker for your scripts


After the Option Explicit command, you see On Error Resume Next. This is one command you want to comment out during testing of the script. The reason for this is that the On Error Resume Next command suppresses error messages while you're in testing and development mode, and you won't know what's going on with the script. One of the easiest errors to see is failure to declare a variable while using Option Explicit. The Header information section of our script is shown here:

Option Explicit
'On Error Resume Next
Dim colMonitoredDisks
Dim objWMIService
Dim objDiskChange
Dim strComputer
Dim startTime, snapTime    'used for timer Function

  • colMonitoredDisks Used to hold the collection of disks that is returned by the WMI query.

  • objWMIService Used to hold the connection string and query to WMI.

  • objDiskChange Used to hold the notification event that comes from WMI, which lets you know you have a change in disk status.

  • strComputer Used to hold the target of the WMI query. When set to "." it means to run the WMI query on the local machine.

  • startTime Used to hold the number of seconds since midnight. Will be used with the Timer function.

  • snapTime Used to hold the number of seconds since midnight. It will be subtracted from startTime and tell us how long the operation has been running.

Reference Information

In the Reference information section, shown next, you assign values to variables and define the constants. Two constants are used: LOCAL_HARD_DISK and RUN_TIME. The LOCAL_HARD_DISK constant is set to 3, which is a local fixed disk. This value comes from the Platform SDK article on the WMI class WIN32_LogicalDisk. The second constant is RUN_TIME and it is used to control how long we allow the script to run. It is set in seconds, and 10 is used for testing purposes. To allow the script to run for longer periods of time, you would increase the value of this constant.

StartTime is set equal to Timer. The Timer function is used see how long a script is running. It counts the number of seconds that have elapsed since midnight. Two or three variables are normally employed when using the Timer function. In this script, we use two: startTime and snapTime. We will compute the difference between the two values and echo out the results. We could also have used a third variable to hold the result of the computation, but in this instance there is little value in doing so.

Const LOCAL_HARD_DISK = 3 'the driveType value from SDK
Const RUN_TIME = 10 'time to allow the script to run in seconds
strComputer = "."
startTime = Timer

Worker and Output Information

The Worker and Output information section of the script is where you do some pretty cool stuff. The two Set commands at the beginning of the Worker section are WMI things. The first makes the connection into the default WMI namespace on the local computer. The second Set command executes a notification event query. This sets up a subscription that tells WMI we want to be notified if something changes in relation to our logical disks. We only want to be notified if this occurrs during a 10-second interval. In a production server, do not set the within clause to less than 60 and preferably not less than 120. But for testing purposes, within 10 seconds is fine. Let's take a look at what is going on in this section of the script:

Set objWMIService = GetObject("winmgmts:\\" & strComputer & "\root\cimv2")
Set colMonitoredDisks = objWMIService.ExecNotificationQuery _
   ("Select * from __instancemodificationevent within 10 where " _
     & "TargetInstance ISA 'Win32_LogicalDisk'")
Do While True
snapTime = Timer
 Set objDiskChange = colMonitoredDisks.NextEvent
  If objDiskChange.TargetInstance.DriveType = LOCAL_HARD_DISK Then
  WScript.echo "diskSpace on " &_
  objDiskChange.TargetInstance.deviceID &_
  " has changed. It now has " &_
  objDiskChange.TargetInstance.freespace &_
  " Bytes free."
  End If
  If (snapTime - startTime) > RUN_TIME Then
  Exit Do
  End If
Loop

First let's look at the Do While...Loop construction. Notice that the line beginning this section is Do While True. This tells VBScript that you want to invoke Do While...Loop. Everything between Do While True and Loop will continue to run as long as the Do While statement is true. It will continue to be true forever, because we only say Do While True.

After you set up Do While...Loop, you assign the objDiskChange variable to be equal to the next event that comes out of colMonitoredDisks. Because the Do While True clause will run forever, we want to have a means of exiting the script (so that it does not run forever). We use an If Then construction. We will actually talk about this construction in Chapter 3, "Adding Intelligence," but for now it is sufficient to see that if the script has been running for more than 10 seconds, we use the Exit Do command and end the script.

Note

Normally, I do not like using Exit Do because I prefer to allow the logic of the script to determine when things are finished. In general, you should be able to handle conditions and allow the script to run through the structure and not have to "bail out" early by calling Exit Do. There are much better ways of creating a timer (see the WIN32_LocalTime script in Microsoft Windows Scripting with WMI: Self-Paced Learning Guide [Microsoft Press]), but this is a rather cute way to create a simple timer.


Quick Check

Q.

What is the primary function of Do While...Loop?

A.

It enables you to run a script as long as a certain condition is in effect.

Q.

What is one reason for turning off On Error Resume Next during development and testing?

A.

During development and testing, you want to be presented with error messages to facilitate testing and debug operations.


Note

This script is one you would want to run in CScript. To do so, open up a CMD prompt and type cscript and the file name. The complete command line would look something like this: cscript c: \Documents and Settings\%username%\My Documents\Microsoft Press\VBScriptSBS\ch02\MonitorForChangedDiskSpace.vbs (of course you would need to substitute your user name for the %username% portion). CScript is nice because when you want to break out of the program, all you do is press Ctrl+C. If the script is run under WScript (which is the default), to end the program, you have to open up Task Manager and kill the wscript.exe process.


Using the Timer Function and the FormatNumber function

1.
Open Notepad or the script editor of your choice.

2.
On the first line of your script, set Option Explicit, as seen below:

Option Explicit

3.
Declare three variables using the Dim command. I used startTime, endTime, totalTime, as seen below:

Dim startTime,endTime,totalTime

4.
Declare a constant to be used with the Sleep command. I used sleepTime, as seen below:

Const sleepTime = 1000

5.
Use the startTime variable and assign the value that comes back from the Timer function to it, as seen below:

startTime = Timer

6.
Now let's evaluate the value of total time. If it is less than five, then we will continue to loop through our code. This is seen below:

Do While totalTime < 5

7.
Let's print out the value of startTime. You will see it is a large number of seconds.

WScript.Echo startTime

8.
Now let's assign a snapshot to the end time. We again use timer.

endTime = timer

9.
Just for fun, let's print out the value of endTime so we can compare results with startTime.

WScript.Echo endTime

10.
Compute the value of totalTime by subtracting the value of startTime from endTime.

totalTime = endTime - startTime

11.
So we can monitor progress, let's print out the value of totalTime:

WScript.Echo totalTime

12.
Clean up the number that was computed as totalTime by using the formatNumber function. It will trim everything to two decimal places by default, as seen below:

totalTime = formatNumber(totalTime)

13.
Now let's sleep for a little while and print out some blank lines, and then loop. This is done by the following code:

wscript.sleep sleepTime
WScript.Echo vbNewLine
loop

14.
Save and run your script. If you have problems, you can compare your code with the TimerFormatNumberLoop.vbs script in My Documents\MicrosoftPress\VBScriptSBS\Ch02.


Previous Page
Next Page