The VBScript Network and Systems Administrator's Cafe


March 14, 2008  5:57 PM

Using XML in vbscript via Microsoft.XMLDOM to work with data feeds

Jerry Lees Jerry Lees Profile: Jerry Lees

In this installment I wanted to both celebrate and congratulate the winners of the ITKE Challenge that has been running over the last few months for an XBOX 360 ELITE system, among other prizes. I also wanted to write about XML use in vbscript as well so the challenge was how to accomplish both tasks…

Then I remembered a great community site, that I’ve been a member of for a little over a year or so, called 360voice. Basically, those guys have a truly awesome idea over there… I play games with my Xbox 360 and it blogs about the times we have—and I don’t have to do any work on my own. ;-) If you have a 360 and don’t have an account setup, go over and check it out, tell ‘em Jlees sent you. Heck, while you are at it watch my blog there and drop me a note.

At any rate, one of my challenges was to get everyone the same XML file, while not creating it myself because I wanted the script to be useful under certain circumstances. 360voice came through with their API Documentation! Think about it… now your scripting life has insite into your gaming life (and other’s as well) you could write a script to compare your achievements to your buddies, show the games you haven’t completed, and all sorts of other stuff. Why?? Because you can!

Consider this working code (that indecently pulls the XML directly from the website without saving it locally) that shows the last 10 days of gamerscore history for two gamertags in the output, in my case I chose mine, Jlees, and one of the owners of the site, changeagent, to do the comparison.. From this script alone you could graph your gamerscore and a buddies so you can compare and have irrefutable bragging rights about your gaming powers! (notice: that I put just about everything together we’ve talked about up to now in this one script, if your just joining us you might want to go back and brush up the last few weeks worth of blogs really quick. Also, I’ve noticed some cases where the sourcecode does not copy correctly, so I have uploaded the source to this article to my website here for you to download.)

Option Explicit

Dim GamerTag1,GamerTag2, GamerScore, Days, xmlDoc, x, y, Value, Count

GamerTag1 = “CrashSerious” ‘change this to your gamertag
GamerTag2 = “ChangeAgent” ‘change this to your buddies gamer tag
‘ a quick note on the following line. It’s great the folks at
www.360voice.com gave us this API
‘ While you likely can change this to something other than 10 below, I strongly encourage you To
‘ limit it to less than a month. The pulling of this data will no doubt have an impact on their servers
‘ and excessive pulls will likely get you blocked, the API removed, or restricted.
‘ Basically, be a good neighbor.
Days = 10 ‘ change this to the number of days to pull.

DisplayTagHistory(GamerTag1)
DisplayTagHistory(GamerTag2)

Sub DisplayTagHistory(GamerTag)
 set xmlDoc=CreateObject(“Microsoft.XMLDOM”)

 ReDim GamerScore(Days)

 xmlDoc.async=”false”
 xmlDoc.load(“
http://www.360voice.com/api/score-getlist.asp?tag=” & GamerTag & “&num=” & days)
 for Each x in xmlDoc.documentElement.childNodes
   If x.nodename = “info” Then ‘ this is where the gamer tag is located in the node named “gamertag”
    WScript.Echo GetTagValue(x,”gamertag”)
   End If
 
   If x.NodeName = “gamerscore” Then
  Count = 0
  For Each y In x.childnodes  ‘ this is where the score for that day is located
         ‘ in a node named “value”
   GamerScore(Count) = GetTagValue(y,”value”)
   ‘below we output the data. You could easily change the “vbTab & “:” & vbTab” to
   ‘a , and create a CSV or write to a file. the world’s wide open from here.
   WScript.Echo Date-Count & vbTab & “:” & vbTab & Gamertag & vbTab & “: ” & GamerScore(Count)
   Count = Count + 1
  Next
   End If
 Next
End sub

‘note this function assumes only one node named the same as SrchStr is in the XMLTAG child node.
‘ if there is more than one, only the last value will be returned.
Function GetTagValue(XMLTag, SrchStr)
 for each Value In XMLTag.childNodes
    if ucase(Value.nodename) = Ucase(SrchStr) Then
     GetTagValue = Value.text ‘get the value in the node requested.
    End If
 Next 
End Function

The output, with the script untouched, should look like so:

 JLees
3/14/2008 : JLees : 23740
3/13/2008 : JLees : 23730
3/12/2008 : JLees : 23730
3/11/2008 : JLees : 23730
3/10/2008 : JLees : 23730
3/9/2008 : JLees : 23730
3/8/2008 : JLees : 23700
3/7/2008 : JLees : 23700
3/6/2008 : JLees : 23700
3/5/2008 : JLees : 23700
ChangeAgent
3/14/2008 : ChangeAgent : 12817
3/13/2008 : ChangeAgent : 12817
3/12/2008 : ChangeAgent : 12817
3/11/2008 : ChangeAgent : 12817
3/10/2008 : ChangeAgent : 12817
3/9/2008 : ChangeAgent : 12817
3/8/2008 : ChangeAgent : 12817
3/7/2008 : ChangeAgent : 12817
3/6/2008 : ChangeAgent : 12817
3/5/2008 : ChangeAgent : 12777

I only used ONE new thing in this code Microsoft.XMLDOM, which we’ll discuss in a later entry but I wanted to call your attention to the following line in this entry:

xmlDoc.load(“http://www.360voice.com/api/score-getlist.asp?tag=” & GamerTag & “&num=” & days) 

 

This line is the one where you would specify the path for the XML file, whether it is a local file or a file on the internet—like this rss feed to my blog. Also note that the DisplayTagHistory subroutine is highly focused to this XML feed and will likely need some work to get it to display another.

Enjoy!

Extra Credit: Can you modify the code to include the other owner of the 360voice site and compare his score with mine and changeagent’s? His Gamertag is Fatty Chubs.

March 12, 2008  5:38 PM

Use of option explicit and the DIM statement in VBSCRIPT.

Jerry Lees Jerry Lees Profile: Jerry Lees
Wireless

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!


March 10, 2008  3:33 PM

Working with Subroutines and Functions in VBScript

Jerry Lees Jerry Lees Profile: Jerry Lees
Installation, Windows on Intel, Wireless

In this installment, we’ll discuss the advantages of using Subroutines and Functions in your script rather than using a all-in-one script that runs from start to finish. I’ll only give a breif over veiw of subroutines and function, but more information on them can be found in the VBScript User’s guide and Language reference.

First, Functions and subroutines are basically smaller pieces of your script. They are generally a part that completed a specific task in the script and are very helpful in accomplishing the following:

      Creating reusable code to use in other scripts without having to re-write the code
      Making your code more readable
      Using the same set of code multiple times in the same script without a loop of some type.
      Helpful in debugging a script and disabling a section of code
      Helpful in organising the logic of the script into smaller bite sized pieces

They essentially are the work horse of your script. In General, I try to keep all the logic of a script in a Function or a subroutine– that way If I have to make modifications I’m only going to at worst break a small (but possibly important) piece of the script. Remember, Subroutines and functions can call other subroutines and functions– so they are not limited to just being used within your main script– Infact, a single function or subroutine can call itself! This is outside the scope of this posting, but is called a recursive funtion or subroutine.

They both get passed information when they are called and  preform their work according to what the information they have been given. These values passed can literally be anything you need to make the subroutine or function work. These values are generally only what the function needs to preform it’s work. For example:

Say you need to calculate the price you pay for an item at the store, so you can have exact change in cash. Think about what information you need. You just need the price of the item and any sales tax on the item, you don’t need anything else like where the store is or who the cashier is. That’s essentially what a subroutine is!

Now, Functions and subroutines are VERY similar. In fact, there is only one major difference in the two of them. They both offer a way to better organize your code into bite sized chunks, create re-usable sections that are easier to manage and modify, and they both preform a very specific task.

The only difference is that a subroutine does it’s work and deals with it’s result inside itself without communicating the end result back to the routine that called it to run.  So it’s kind of a loner… just does it’s work and doesn’t bother anyone else with the details or the result. This is useful for file or screen I/O where you don’t need any information returned to you. Basically, it’s a script all in itself. In our earlier example the subroutine would need to print out or do something with the values calculated and no other area of the program would be aware of where the result.

A function on the other hand will communicate back to the calling routine some value… possibly the result of some calculation, like our total price of the item, or an error condition for the calling routine to process and deal with in a manner that is fitting for the situation.

In my example below I provide you with both examples of a subroutine and a function to add two numbers together. Notice that when I call the subroutine in vbscript I do not use parenthesis around the values I pass to the routine, but with a function I do use them. This is just simply the way it is done in VBScript and will result in an error if your do it the other way around.

Option Explicit
Dim ReturnValue

TestSub 2,2 ‘ subroutine call– notice no ( ) around the two values!?!?!
ReturnValue = TestFunction (2,2) ‘function call– notice the ( ) around the two values… plus some thing else!
WScript.Echo “Function returned: ” & ReturnValue

‘ end of main code

Function TestFunction (Value1, Value2)
‘ Function to add two numbers and RETURN the value to the calling routine.

Dim Sum
 Sum = value1 + Value2
 WScript.Echo (“Functions: All your work is done here and used here, but can be sent back to the main script.”)
 WScript.Echo Value1 & ” + ” & Value2 & ” = ” & Sum

TestFunction = Sum

End Function
Sub TestSub (Value1, Value2)
‘ Subroutine to add two values together… notice all the work is done and used here?

Dim Sum
 Sum = value1 + Value2
 WScript.Echo (“Subroutines: All your work is done here and used here.”)
 WScript.Echo Value1 & ” + ” & Value2 & ” = ” & Sum

end Sub

Play with this code… see if you can figure it out. In a few days I will explain it in a bit of better detail. Take note of how I build the function, subroutine, and see if you can figure out the line that does the magic of returning the value from the function. 

Extra Credit: Did you notice the line that had option explicit and the lines that have Dim in them? What do they do? Post a comment and I’ll let you know in a few days.
 


March 7, 2008  10:22 PM

Eventlog search tool — Find quick help with windows event log entries

Jerry Lees Jerry Lees Profile: Jerry Lees
SalesLogix, Wireless

While not VBScript related, I found this Microsoft Eventlog and Error Message Search a few days ago as I stumbled around looking for tools that I thought network administrators would need on my site that I’ve been toying with– I had to share the tool with you as well!

 The tool itself is an awesome resource, similar to EventID.net– except it’s FREE and it comes from Microsoft themselves providing links to Microosft content about the event entry or error message.

 You can search for any combination of the following:

Microsoft Product|
Version
Message ID
Event Source
File Name
Language

When you do it takes you to a search result page that lists the available results for your specific search, each seem to have not only an example of the message, but also an explanation of what the event means…. and the best part a section entitled User Action that gives a possible solution for the problem!

 Enjoy the tip!


March 4, 2008  1:57 AM

Determining properties and methods used in a WMI object for use in a vbscript.

Jerry Lees Jerry Lees Profile: Jerry Lees
Remote management, Windows on Intel, Wireless

In this entry we’ll take a look at the microsoft documentation for win32_printerdriver and determine how we can determine what values to use to get data once we’ve created a script to get set of data back from a WMI object into a collection object. Most of the previous discussion can be read, in order in my blog but here are links in order, if your just tuning in:

Finding HP Printers using PCL6 Drivers with WMI
Using error control in a vbscript to recover from odd errors
Using Set, GetObject, ExecQuery, and For Next in VBSCRIPT to use WMI objects

Microsoft has a great deal of documentation here on the win32 WMI classes.  However, here is an excerpt from their win32_Printer class. Most of their documentation is written for c/c++ programmers it seems– don’t let that scare you off, you don’t need this code in yours nor do you need c/c++ experience to use them.

Below you see the first line creates a “class” called Win32_PrinterDriver that is of a type called CIM_Service. Essentially, a class contains data and tools you can use in your programs. CIM_Service is just the name of the data type the class is created as– you’ll see references to CIM all over the place with WMI. It stands for Common Information Model, check out the preceding link for more information.

After that, the items in curly braces ( {} ) are the actual names of the properties and what types of data they contain. Again, as long as you are using the data in strictly Vbscript code you don’t even need to know what the type is– VBSCRIPT takes care of that for you. However, on ocassion you’ll see a “type mismacth” error in your code. This is simply referring to the fact that you have put a value in a variable of one type (a string for example) into a variable that is meant to have another type (an integer for example), typically this happens when you use a external component that was written in another language that is more strict about the data types than vbscript, like c, c++, or others. (Which is almost all of them outside of the Visual BASIC family)

class Win32_PrinterDriver : CIM_Service
{
  string Caption;
  string ConfigFile;
  string CreationClassName;
  string DataFile;
  string DefaultDataType;
  string DependentFiles[];
  string Description;
  string DriverPath;

};

In the code I wrote for this series I used Wscript.echo to print the data to the screen inside the For Each/Next loop, like so:

Wscript.Echo “DriverPath: ” & objItem.DriverPath

Remember, objitem was a collection of printer driver information objects?
Notice the last part of that line, .DriverPath?
Notice the last line I gave you from the microsoft documentation?

Yeap, they are both DriverPath! There’s a reason… they are the same thing! Essentially, ANY of the items listed in the Win32 classes can de used in conjuction with a collection object– providing you have collected the same type of object with a WMI object before hand! So this documentation is like GOLD for a systems administrator! So, if you didn’t take a hour or 50 before when I gave you the link check it out here again.

For example, I didn’t use the property Version in my original code. If you needed this information in the program you could add another line in the For Each/Next loop to gather that information as well! Like so:

WScript.Echo “Version: ” & objItem.Version

You can do that with any of the properties and methods in the win32_printerdriver class, and it expands beyond that to all of WMI.

One thing to keep in mind with much of WMI is that it is dependent on the driver or hardware manufacturer to provide the information– not all manufacturers provide that information 100% reliably, so you’ll have to play and tweak what your hardware vendor does give you. My bet is even if it’s not 100% of all the information available, it will be more than you had to start with without hours of digging.

So, here is the original code again. Take a few minutes to play around with the code and the win32_printer driver documentation and see what interesting pieces of information you can pull out of WMI.


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 concludes this series!

 Extra Credit: Can you modify the code above to pull actual printer hardware/software data from Win32_Printer? Hint: stay clear of the properties with a [] after them for now, they will potentially trip you up. And also, remember just because it pulled back one value that was blank doesn’t mean you did something wrong– some items aren’t populated by hardware vendors to WMI unfortunately.


March 3, 2008  9:11 PM

Using Set, GetObject, ExecQuery, and For Next in VBSCRIPT to use WMI objects

Jerry Lees Jerry Lees Profile: Jerry Lees

In my last blog entry I explained error control via on error resume next and on error goto 0, there are other ways as well– but for now this should work to get us by.

Next well discuss the Set, GetObject, ExecQuery, and “For Each” commands in the script we worked with, these are on lines 3, 4 and 5 below.

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

The Set command basically tells cscript (or wscript) to assign the value of a variable to be the value of another or creates an object. For all intensive purposed, you can think of an object as a piece of specialized code that is already written that you can call from within your program and use as if it were your own. An object can contain many different types of values, that are referenced by names. These names are either properties (values) or methods (functions to do something and probably give you a value back).

Next, the GetObject command. this is the true heart of our WMI script. In fact, this is where almost all the magic happens! The Getobject comamnd lets us use pieces of code outside of our application as if we had written them on our own– the plus being that we don’t have to write them. In this case it is a WMI call to retrieve an object called “winmgmts:\\.\root\cimv2″.

This object is the root WMI provider that is built into the OS and the period represents the local machine, to get other machine you would specify it’s name instead– this is why we used a variable in the script. (Remember, scripts are powerful when they are reusable for the same situation at a different time, so try to use variables where ever you think a piece of information could change in the furture to allow you to reuse the script.) This WMI provider returns a WMI object that allows us to reference and use the piece of the OS that deals with WMI. Notice we SET the object to the variable objWMIService in the line?

 In the next line of code we actually USE it, again another SET command. But this time we use:
… objWMIService.ExecQuery(”Select * from Win32_PrinterDriver”….

The execQuery method is a part of the WMI classes Microsoft has written, and we are simply calling it to preform work. In this case, we are constructing a call to pull back all the printer drivers. The part in the quotes works exactly like a simple SQL statement would operate. Essentially in english it works like– Select all values from Table containing the printer driver information. This “table” contains lots of information on the printer drivers, I’ve only chosen to show a few items from the table, you can get more information here.

After this command completes, colItems will contain a collection of objects that each have properties named the same as the columns in the table. We use the For Each command on line 5 to loop through each member of a collection one at a time and do something with the data (or to the data). The Next command on line 12 loops back to the beginning as long as there is another object after the one currently being used in the collection.

That’s it! It’s pretty easy stuff, once you get the concepts down. Remember, The WMI object is used to execute a query against the WMI database on the system. This query returns a collection of objects containing data for the query you built.

The actual data returned (and names of methods and properties used to get the data) depends on the query you specified. More on that next time!


February 29, 2008  10:30 PM

Using error control in a vbscript to recover from odd errors

Jerry Lees Jerry Lees Profile: Jerry Lees

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!


February 29, 2008  2:45 AM

Finding HP Printers using PCL6 Drivers with WMI

Jerry Lees Jerry Lees Profile: Jerry Lees
Wireless

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:  0x0

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!


February 20, 2008  5:12 PM

Expert Says Scripting is Key to Career Advancement.

Jerry Lees Jerry Lees Profile: Jerry Lees
Wireless

SearchWinIt has an interesting podcast that caught my eye just now, titled Microsoft issues largest patch bundle since August. However, the truly interesting thing to me was said around 5minutes 59 seconds into it. They said Brian Desmond, an Active Directory MVP, said that “Learning any scripting or programming language is especially important for those hoping to land jobs with larger companies”. Brian’s got some good stuff on his blog, so be sure an check it out here.

Immediately after they mentioned another (unmentioned) expert said admins could get by without learning any scripting in companies with  “30 users or less.”


February 20, 2008  7:47 AM

Using Windows Management Interface (WMI) to Make Your Life Easy.

Jerry Lees Jerry Lees Profile: Jerry Lees
Wireless

In this blog entry I want to setup the next few blog entries that will deal with a technology that is quite possibly one of the most powerful tools in a Network Administrators tool chest… the Windows Management Interface or WMI.

WMI is a powerful tool when combined with scripting, you can use it to gather a vast array of information very quickly from a system or a number of systems. It is pretty easy to use once you have a basic script to setup the objects to make the calls, you know the Win32 class you want to call to query the information, and when you know what properties and/or methods to use. (no, this isn’t exactly the same as the C win32 classes or the windows foundation classes)

Think of Methods as subroutines or functions to accomplish a specific task, like starting a service. Think of properties as variables that you can check the value of to do something.

WMI can be used to also make configuration changes as well– imagine the company you work for just bought another company and you need to add their DNS suffix to all your servers and client machine’s TCP/IP properties’ search order and there are several hundred machines. Would you touch them all over a weekend? No! Be Lazy, and gain the respect of your new bosses if you were on the other side of the buy out! ;-) Do it with WMI in under an hour while you sip a Mountain Dew.

Another possibility is, say you have a Production SQL server that needs a RAM upgrade but no one can recall exactly what the memory configuration is that makes up the 4Gb of RAM in it. Was it 4 1Gb sticks, or 8 512Mb sticks? Were there any free slots? Guess you’ll have to come in during the 3am maintenance window (for 5 minutes) to figure it out so you can order the right parts. No! Be Lazy, WMI can tell you EXACTLY what the memory configuration is to make up the total and how many slots are available/free!

 Here is a good introduction article on WMI for you to look over and read. After reading that article you might want to poke around the Microsoft Documentation for the Win32 Classes for WMI. Be sure and bookmark the win32 classes page– it will be invaluable to you.

To make a call from a script to WMI you have to “create the WMI object” you want to work with. This is done in just a few lines of code. Then you actually create the object with a SQL like call like any of the following (These are examples to get the juices flowing… I haven’t tested them):

  • Select * from Win32_PrinterDriver
  • Select Caption from Win32_BIOS where Releasedate < ’07/01/07′
  • Select * from Win32_Service where Started = True

After that you treat the object you created just like any other object, you just have to know what the properties and methods are, here is a highlight of some of the properties and methods for Win32_Service.

The properties are:

AcceptPause
AcceptStop
Caption
Description
DisplayName
ProcessId
Started
State
Status

Example Methods are:

StartService
StopService
Create 

There are others, but I think you’ll get the general idea. Next time, I’ll be sharing a quick script to display Device Drivers that are in use by printers on a server or workstation. Until then… Be Lazy!


Forgot Password

No problem! Submit your e-mail address below. We'll send you an e-mail containing your password.

Your password has been sent to: