Windows Management Interface archives - The VBScript Network and Systems Administrator's Cafe

The VBScript Network and Systems Administrator's Cafe:

Windows Management Interface

Apr 13 2009   3:18PM GMT

Finding the owner of a process remotely with VBScript via the Win32_process class



Posted by: Jerry Lees
WMI, Windows Management Interface, win32_process, System Administration, Systems Administration, Administration tools, VBScript, VBScript Functions, Functions

 Recently I had an issue where I needed to find the user running a series of processes on a large number of servers. Initially, it was a long process of logging onto each server then opening task manager and sorting by process name. After about 5 servers, I realized it was going to take hours to sort out the users running the processes… so I spent 30 minutes not preforming this process and wrote a script to do the rest of the work in less than a minute!

The function below uses the Win32_Process WMI class to enumerate processes running on a server that are named the same as the process name you give it. It then outputs the name of the user running the process.

Below is the function… Enjoy!

 Function FindProcessOwner( StrComputer1, ProcessName)

Dim objWMIService, colItems, objItem, Username, Domain

On Error Resume Next
‘ error control block
Set objWMIService = GetObject(”winmgmts:{impersonationLevel=impersonate}//” & strComputer1 & “\root\cimv2″)
If Err.Number <> 0 Then
WScript.Echo “An Error Occured (” & StrComputer1 & “): ” & Err.Description
End If
Set colItems = objWMIService.ExecQuery (”Select * from Win32_Process Where Name = ‘” & ProcessName & “‘”)
WScript.Echo “Searching for processes on ” & StrComputer1 & “.”
WScript.Echo colItems.count & ” processes found.”
For Each objItem in colItems
objItem.getowner Username, Domain
FindProcessOwner = FindProcessOwner & VbCrLf & strComputer1 & “: ” & objItem.name &_
“(PID: ” & objItem.processid & “) the owner is: ” & Domain & “\” & Username
Next
On Error GoTo 0
End Function

Jan 5 2009   2:03AM GMT

Retrieve environment variable values from a remote system with WMI



Posted by: Jerry Lees
WMI, Environment Variables, Win32_Environment, VBScript, Windows Management Interface, System Administration, Remote management, PATH variable

Back in October I shared with you a way to retrieve environment variables with a script titled Using Environment variables inside a VBScript script. The script worked like a champ and got me through several tight binds in gathering information, hopefully it has for you as well. However, it has one flaw… it doesn’t work on a remote system! In fact, it only works on the system that the script is running on.

So, I had to recently go back to the drawing board and create a script and series of functions that would work remotely so that I could wrap it in a function to gather information from a bunch of servers. I also Learned a thing or two in the process!

First, The script uses the Win32_environment classes in WMI and this class returns ALL envirnment variables for ALL users. That threw me for a loop when I saw multiple PATH environment variables– some that were different. Second, The search is case sensitive without using the SQL % wildcards (I didn’t need them, so implementing that is left up to you the reader.)

I have the three functions I wrote, that are really variations of one another below. Just add them to your script and call them with the appropriate values and you should be in business!

Function RemoteAllEnvironmentVariables(ServerName)
     ‘Lists all environment variables on the remote system
    
Dim objWMIService, colItems, objItem
 
     RemoteAllEnvironmentVariables = “”
     Set objWMIService = GetObject(”winmgmts:\\” & ServerName & “\root\cimv2″)
     Set colItems = objWMIService.ExecQuery(”Select * from Win32_Environment”)
     For Each objItem in colItems
         RemoteAllEnvironmentVariables = RemoteAllEnvironmentVariables & objitem.name & “: ” & objItem.VariableValue & VbCrLf
     Next
End Function

Function RemoteAllEnvironmentVariablesVariations(ServerName, VariableName)
     ‘Lists all environment variables on the remote system, along with every case variation
     Dim objWMIService, colItems, objItem
 
     RemoteAllEnvironmentVariablesVariations = “”
     Set objWMIService = GetObject(”winmgmts:\\” & ServerName & “\root\cimv2″)
     Set colItems = objWMIService.ExecQuery(”Select * from Win32_Environment”)
     For Each objItem in colItems
         If UCase objItem.name) = UCase(VariableName) Then
         RemoteAllEnvironmentVariablesVariations = RemoteAllEnvironmentVariablesVariations & objitem.name & “: ” & objItem.VariableValue & VbCrLf
         End If
     Next
End Function

 
Function RemoteEnvironmentVariable(ServerName, VariableName)
     ’Lists all environment variables on the remote system, exactly as you typed it in the function call.
     Dim objWMIService, colItems, objItem
 
     RemoteEnvironmentVariable = “”
     Set objWMIService = GetObject(”winmgmts:\\” & ServerName & “\root\cimv2″)
     Set colItems = objWMIService.ExecQuery(”Select * from Win32_Environment Where Name = ‘” & VariableName & “‘”)
     For Each objItem in colItems
         RemoteEnvironmentVariable = objItem.VariableValue
     Next
End Function


Jan 2 2009   3:01AM GMT

Searching the Windows Eventlog for specific events with WMI



Posted by: Jerry Lees
Win32_NTLogEvent, WMI, Windows Management Interface, VBScript, Systems Administration, systems management

On occasion as a systems administrator you have to find the proverbial needle in the haystack with respect to the events in the event logs. You know what I mean, the one event you care about and need to know when it occured as part of your troubleshooting… then throw in that you need to do it in many servers. That’s a mess!

Sure, you can use event viewer and pull out some superadmin skills to filter the events to only see the ones you want– but your still only looking at one server at a time! Yes, you could export the events from multiple servers to a CSV file and then compile them into one excel spreadsheet– but that would take hours to do.

What if I told you there was a way to do it with VBScript? How much would you expect to pay? Three easy payments of 19.99?? … WAIT, don’t answer because it’s FREE!

The script below calls a function it defines called GetLogInfo to gather the requested event information to standard the standard output (the console). The function uses the Win32_NTLogEvent class from— you guessed it, our life long friend WMI! It accepts four inputs, in order; a string that is the name of the server, the Event ID that you are looking for, the specific application log you want to search, and the date in YYYYMMDD format. (Hint: if you have custom event logs on your server, or it is a DNS server or a Domain Controller, you can specify the name of the log instead of Application, System, or Security to get at the log information.)

Here is the script I wrote:

GetLogInfo “ServerName”,”1309″, “application”, “20081218″

Function GetLogInfo( StrComputer1, EventID, EventLogType, YYYYMMDD)

    Dim objWMIService, colItems, objItem
    Dim TempStr

    On Error Resume Next
    ‘ error control block
    Set objWMIService = GetObject(”winmgmts:{impersonationLevel=impersonate}//”_
    & strComputer1 & “\root\cimv2″)
    Set colItems = objWMIService.ExecQuery (”Select * from Win32_NTLogEvent Where EventCode=” &_
    EventID & ” and logfile=’” & EventlogType & “‘”)
    For Each objItem in colItems
        TempStr = “”
        If mid(objItem.timegenerated,1,8) = YYYYMMDD Then
            TempStr = objItem.message
        End if
    Next
    On Error GoTo 0
End Function


Mar 4 2008   1:57AM GMT

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



Posted by: Jerry Lees
Development, VBScript, DataCenter, WMI, Windows Management Interface

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.


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!