Error Control archives - The VBScript Network and Systems Administrator's Cafe

The VBScript Network and Systems Administrator's Cafe:

Error control

Oct 17 2008   11:11PM GMT

Communicating error levels to a calling application from with in VBScript



Posted by: Jerry Lees
VBScript, Error control, exit, on error, errorlevel, WScript.quit, wscript, batch commands

We’ve discussed error handling previously (via the On Error Goto 0 command) in a entry titled, Using error control in a VBScript to recover from odd errors. However, occasionally you need to communicate a condition back to an application or batch file that calls a script as part of its processing. One reason you may need to do this is if you need to call a separate script or application depending on the outcome of the script. You can do this with what is called an error level. Keep in mind this may not have anything to do with an error in the script but can, instead, be used as a method to control how another applicatioin responds to a particular condition.

For example, say you already have a executable that processes a file into a database– but you don’t want to run the executable on a old file because it would cause all sorts of duplicated entries in the database. you might not be able to go back to the person who wrote the executable and have them change it or the executable might not have even been written by the company where you work! You could, however write a script to check the date of a file and if it was created during a time frame return a error level back to a batch file that calls your script and preforms the logic to decide if the executable needed to be ran. Take this batch file for example:

Echo off
cscript Yourscript.vbs
If %errorlevel% == 3 goto runexe
Echo “File to old”
goto EndBatch
:runexe
processingprogram.exe
:EndBatch

This would only run the executable IF your script returned a error level of 3! So you can then preform work and checks never intended by the executable when it was written only if the conditions are correct for it to run.

The line of code in VBScript you would add to your  script to communicate back to the batch file would be:

WScript.quit(3)

This will return a error level of 3 back to the batch file and cause the batch file to THEN run your executable.

So, there you have it! A quick and simple method to extend the life of those aging processes that work fine– just need a minor tweak because your environment has changed.

Sep 26 2008   7:54PM GMT

VBScript Statements: Explanation of the On Error Statement



Posted by: Jerry Lees
VBScript Statements, Error control, on error

The on error statement allows you to somewhat control how the scripting engine handles errors in the scripts you write. It allows you to turn error handling on and off for the scripting engine so that you can handle them in your script.

 The Statement essentially has two ways it is used. First to turn off the script engine error checking:

On Error Resume Next

The second is to turn it on, thereby allowing the script engine to stop execution of a script when an error is encountered. Like so:

On Error Goto 0

One word of caution, It is very tempting to simply place “On error resume next” in a complex script block and not worry about annoying hard to find errors. However, It is generally better to try to find the source of the errors since ignoring the errors can cause unintended consequences– or at the very least difficult to find issues in another piece of code.

In general, if you use On Error Resume Next you should always check for errors and handle them in your code somehow. 


Apr 25 2008   1:26AM GMT

Reporting CPU usage by saving it to a file with the VBScript filesystem object



Posted by: Jerry Lees
VBScript, Functions, Error control, Scripting.FileSystemObject, File System Object

Last time, in my entry entitled VBScript to check CPU and Processor performance counter statistics using WMI, I asked you to modify the code I gave to include the access method type in the function. If you haven’t read the article, take a second to go back and look it over and digest the code because this article is identical to that one, except some added features.

Again I got a rather quick response to the extra credit item that I placed at the end if the article. Basically, you just need to change the code in three places to accomplish this task. We could then use this code in our previous example to create a CSV file for trending and graphing of CPU usage on a server! Here is an example of the code to do this task.

I encourage you to play around with the various methods of file access both with an existing file and a new file that doesn’t exist.

Below is a working example of the code:

Option Explicit
On Error Goto 0
Dim strSrv, strQuery,Errors
Dim Counter, Timeframe, Delay

Delay = 1000 ‘1000 Milliseconds to a second
Timeframe = 300 ’seconds (5 minutes)


strSrv = “.”
For Counter = 1 To Timeframe
 Errors = WriteTextFile (”c:\cpu-usagelog.csv”, GetFormattedCPU (strSrv), ForAppending)
 WScript.Sleep Delay
NextConst ForReading = 1, ForWriting = 2, ForAppending = 8Function GetFormattedCPU(strSrv)
    Dim objWMIService, Item, Proc, start
   
    start = Now()
  
    strQuery = “select * from Win32_PerfFormattedData_PerfOS_Processor”
    Set objWMIService = GetObject(”winmgmts:\\” & StrSrv & “\root\cimv2″)
    Set Item = objWMIService.ExecQuery(strQuery,,48)
    WScript.Echo strQuery
    For Each Proc In Item
       GetFormattedCPU = GetFormattedCPU & Proc.PercentProcessorTime & “, “
       wscript.echo “Processor ” & Proc.Name & ” = ” & Proc.PercentProcessorTime
    Next
   
    GetFormattedCPU = GetFormattedCPU & start  
 
End Function
Function WriteTextFile (OutputFile, Data, AccessType)
    Dim wrtlog, fso
 
    On Error Resume Next
    Set fso = CreateObject(”Scripting.FileSystemObject”)
    Set wrtlog = fso.OpenTextFile (OutputFile, AccessType, true)
 If Err.Number <> 0 Then
  Set wrtlog = fso.OpenTextFile (OutputFile, ForWriting, true)
 End If
    wrtlog.WriteLine(Data)
    WriteTextFile = Err.Number ‘You can use Err.Description here to debug.
    On Error Goto 0
End Function
You now have all the pieces for a fully functional performance logging script, so you’re well on your way to being able to troubleshoot problems deep in the night without getting up and turning on Perfmon. The creates a comma separated value file called cpu-usagelog.csv at the root of the C: drive while the output looks similar to the last time, except it is repeated and I put a time/date stamp in the code by using a new command, now().Also, pay attention to the error handling around the line that writes the data to the file, you’ll likely not see an error related to the file not existing and you using the append access methods, because I’ve checked for it while opening a file. Lastly, notice the for next loop around the function call to call it Timeframe times (Timeframe is multiplied time the sleep Delay to get how long it will capture data). Also notice another new command: Wscript.Sleep, which basically pauses the execution for the number of milliseconds you specify in Delay.

As always, this code works perfectly. However, sometimes the formatting of the blog breaks the code if you copy and paste it into your editor. So, if you’d like to not type or troubleshoot any syntax errors due to the copy and paste problems– I’ve provided the code for download, plus example output files  from my final tests for you. You’ll find the code and other files available for download from my website’s (www.websystemsadministration.com) File Depot under the ITKE Blog Scripts category. Enjoy and happy scripting!

Extra credit: Try and modify this script to monitor something else that is useful to you. Let us all know how you’ve used it.


Mar 12 2008   5:38PM GMT

Use of option explicit and the DIM statement in VBSCRIPT.



Posted by: Jerry Lees
Development, VBScript, VBScript Statements, Variable Types, Error control

As an answer to the extra credit portion of my posting a few days ago:

DIM in a script declares a variable to be used. It just simply creates the variable, nothing more. By default, vbscript will create variables on the fly for you as you use them the first time you use them.

There are other ways to create a variable as well, but create specific types of variables. Here are a few I can think of off the top of my head.

Const  - creates a Constant Variable, while it may seem line an oxymoron, they are sometimes very useful rather than risking typing a long value over and over again. Consider these examples Please note, they are abbreviated here for display purposes— please do not use them in code to launch a rocket to Mars ;-) .

Const Pi = 3.14159265358979323846264338327950288419716939937510582097494459230 ‘ Pi
Const GC = 0.62432998854355087099293638310083724417964262018052 ‘ The Golomb Constant
Const AC = 0.37395581361920228805472805434641641511162924860615  ‘ Artins Constant

By doing this we can type this in our code: 

Answer = Pi * GC * AC

Instead of:

Answer = 3.14159265358979323846264338327950288419716939937510582097494459230 * 0.62432998854355087099293638310083724417964262018052 * 0.37395581361920228805472805434641641511162924860615

And just imagine the mistakes we’d make if we had to type it a bunch of times!

Also there is This command:

Redim  - used to create a single or multi-dimensional array.

For example:

Redim StudentQuarterlyGrades(4) ‘ single dimensional array for grades for a student
Redim ClassQuarterlyGrades(4,13) ‘ a multidimensional array for quarterly grades for a class of 13

Enough of that tangent of extra information! The last  extra credit item was:

option explicit, which forces the writer of a script to declare their variables before they use them.

This can be very valuable and a huge time saver– though it requires a little extra work on the from side declaring variables before you use them. In fact, most programming languages, like c/c++, java, and others, require you to declare the variables prior to use as well as decalre what kind of value you will be putting in them.

Consider this code, without using OPTION EXPLICIT:

StudentFinalGrade = 100
StudentHomeworkGrade = 100

StudentCourseGrade = ((StudentFialnGrade + StudentHomeworkGrade)/200)*100

Do you see the problem? I spelled final wrong in the last line StudentFialnGrade.

Some poor student will get a F (50%), instead of an A (100%) because of that mistake. However, The same code with option explicit and proper DIM statements below (yes, you can declare multiple variables on one line with a comma):

Option Explicit
Dim StudentFinalGrade, StudentHomeworkGrade

StudentFinalGrade = 100
StudentHomeworkGrade = 100

StudentCourseGrade = ((StudentFialnGrade + StudentHomeworkGrade)/200)*100

Yields the following error, pointing to the line and the variable that is either misspelled or not decalred:

… Untitled4.vbs(7, 1) Microsoft VBScript runtime error: Variable is undefined: ‘StudentFialnGrade’
 

Notice how easy that is. Trust me on this. Get into the habit of starting every script with option explicit and using DIM to declare your variables… while it may not matter for 20 -40 line scripts, you will notice it in 100 or 1000 line scripts– and wish you had done it when you spend several hours tracing down why a calculation or string value is coming out differently than you expected!


Feb 29 2008   10:30PM GMT

Using error control in a vbscript to recover from odd errors



Posted by: Jerry Lees
Development, VBScript, Windows Management Interface, Error control

In my last installment, Finding HP Printers using PCL6 Drivers with WMI, I gave you a handy script snippet that showed you how to pull the names of the printer drivers for your printers shared on a print server. In the script I used a few pieces of code that may not be familiar to everyone. In the next few installments we’ll explain better what the script does and how it does it—so hopefully you can begin applying the knowledge elsewhere…

The script was basically (line numbers included as a reference):

1. On Error Resume Next
2. 
strComputer = “.”
3. Set objWMIService = GetObject(”winmgmts:\\” & strComputer & “\root\cimv2″)
4.
Set colItems = objWMIService.ExecQuery(”Select * from Win32_PrinterDriver”,,48)
5.
For Each objItem in colItems
6. 
    Wscript.Echo “ConfigFile: ” & objItem.ConfigFile
7. 
    Wscript.Echo “DataFile: ” & objItem.DataFile
8. 
    Wscript.Echo “DriverPath: ” & objItem.DriverPath
9.
     Wscript.Echo “Name: ” & objItem.Name
10.
   Wscript.Echo “OEMUrl: ” & objItem.OEMUrl
11.
   WScript.Echo “_________________” & vbcrlf
12.
Next

In line 1, the statement On Error Resume Next may be new to you. This statement basically keeps your script from breaking completely and not completing due to a minor error. The down side of this is that if your code isn’t tightly checking for errors it will continue to run with potentially bad logic and cause quite a bit of havoc on your network. IMHO, you should try to avoid it where ever possible. In this case it wasn’t possible because there were to many unknowns.

As an FYI, The brother to On Error Resume Next is On Error Goto 0, basically this turns error checking back on. So, if you need to use it in an area where you’re not certain a piece of code may or may not encounter an error from time to time it’s best to turn error checking back on after that piece of code completes its work.

Consider this example code that has errors:

Wscript.echo “Stepping through ‘Y’ from 1 to “ & X
On Error Resume Next
Wscript.echoo “Error in this line!!!!”
Wscript.echo “Did this line print?”

Of course, if you run this it won’t complete, it will display something similar to:

Stepping through ‘Y’ from 1 to
C:\www.websystemsadministration.com\errorcontrol.vbs(2, 1) Microsoft VBScript runtime error: Object doesn’t support this property or method: ‘Wscript.echoo’
 

This tells us there is an error in line 2 of the script… and gives us a slight hint (sometimes) of what the error is. In this case, we’ve user a function of the Wscript object that does not exist, echoo. Of course we want to know about that. But suppose we didn’t? Well, this would stop vbscript from complaining:

Wscript.echo “Stepping through ‘Y’ from 1 to “ & X
On Error Resume Next
Wscript.echoo “Error in this line!!!!”
Wscript.echo “Did this line print?”

Now it displays:

Stepping through ‘Y’ from 1 to
Did this line print?
 

Notice it skipped the line with an error and went to the next line? To turn error checking back on we just adjust the script this way—but we add a final line with an error to see if it breaks on an error:

Wscript.echo “Stepping through ‘Y’ from 1 to ” & X
On Error Resume Next
Wscript.echoo “Error in this line!!!!”
On Error Goto 0
Wscript.echo “Did this line print?”
Wscript.echoo “What about this new line?!?!”
 

Still the same output, but now you see an error… because we turned error checking back on!

Next installment, I’ll  Explain the Set and the Getobject section of the code.

Extra credit: There is a “soft error” in the script that would never cause the script to break, but cause you TONS of debugging time. Did you find it in the code … or the output? Post a comment and I’ll let you know what I think it is in the comments section in a few days!


Feb 29 2008   2:45AM GMT

Finding HP Printers using PCL6 Drivers with WMI



Posted by: Jerry Lees
Networking, Development, VBScript, Printers, Windows Management Interface, Error control, Printer Administration

Recently, at my work we had a situation where users were reporting the printer was not printing their documents and/or it was printing very slowly. After digging into the problem, I found:

1. the documents were spooling just fine to the printer

2. the documents were not hanging in the printer

3. Sometimes there were documents printing correctly when the user printed

4. on occasion the documents “didn’t print”

Of course, the nearest printer doing it was on the floor below me… I hate stairs. ;-) After digging into it, wasting a ton of paper– and burning untold amounts of Mountain Dew and Dorito calories; I found that the print jobs were always producing printouts! Sometimes it was the document I printed and sometimes it was a single page with the following message in the documents place:

error:

Subsystem:  KERNELError:  IllegalStreamHeaderOperator:  0×0

Position: 0

 The operator and position line held various values, but was always the same first 3 lines. What I found after extensive digging was that this issue was a PCL6 error message. Some people were saying it was a network error and others were saying it was a server print driver error– Don’t they always say it’s one of these, regardless of the problem?

Those who were saying it was a network error were advising that I pulled out a sniffer, like wireshark because packets were being corrupted. I didn’t think this was good advice. First, pulling a sniffer out to troubleshoot printing was like pulling a blowtorch out to light a campfire… sure it will work, but it’s a lot of extra work! Also, I knew that Microsoft printing is done like most things Microsoft– over TCP ports 138,139, and 445 (I believe)– most importantly TCP, since TCP has error correction built in via a checksum.

The others who were saying it was a server issue were recommending that I upgrade ALL the printer drivers on the server. This was quite an undertaking since there were 40 or so printers on the server of various models– most of them made by HP. Knowing HP, the drivers were bundled together into one package and upgrading the drivers for one printer would likely change a bunch of printers. To much risk! 

I did find a few needles in the google hay stack, that were saying the problem was typical for PCL6 and to simply switch the driver back to PCL5. Since both driver types were installed when I installed the printer drivers (always a good idea) I thought I’d give it a shot. Tah Dah! It worked like a charm, with no changes in the documents printer that I could see.

Now that I had one printer fixed, but had to point and clickety click to find the other’s using PCL6 drivers. To much work! So I wrote a quick script to get the bulk of the printer drivers that were being used by the print server so I could focus on the ones needing changing.

Here is the script source, copy it to a .vbs and either; run it from the print server as is or change the second line between the quotes from a period to the name of the print server: (Note: I recommend you run this from the command line with cscript scriptname so you don’t get bombarded by popups)

On Error Resume Next

strComputer = “.”
Set objWMIService = GetObject(”winmgmts:\\” & strComputer & “\root\cimv2″)
Set colItems = objWMIService.ExecQuery(”Select * from Win32_PrinterDriver”,,48)
For Each objItem in colItems
    Wscript.Echo “ConfigFile: ” & objItem.ConfigFile
    Wscript.Echo “DataFile: ” & objItem.DataFile
    Wscript.Echo “DriverPath: ” & objItem.DriverPath
    Wscript.Echo “Name: ” & objItem.Name
    Wscript.Echo “OEMUrl: ” & objItem.OEMUrl
    WScript.Echo “_________________” & vbcrlf
Next

That’s the end of the script! You’ll want to look at the “Name:” lines for the string PCL6. Not all drivers have PCL6 in the name, but a good majority do so it should save you some time!

Take a bit of that time to leave me a comment letting me know if this was helpful!

 Good luck!