Troubleshooting the Application of Two WMI Classes

 

Hey, Scripting Guy! Question

Hey, Scripting Guy! The examples produced from the "Scriptomatic Version 2.0 by The Microsoft Scripting Guys" for the entries Win32_ServiceSpecification and Win32_ServiceControl both return error 0x80041002 under Windows Server 2003. I can't find another WMI class that exposes the recovery options for services, which is something I need to be able to scrape off 100+ servers for auditing. Is that WMI class missing or broken possibly? I can run WMI scripts using just about any other WMI class except those two. What’s up?

- MP

SpacerHey, Scripting Guy! Answer

Hi MP,

Both of the Win32_ServiceSpecification and Win32_ServiceControl WMI classes are supplied by the MSI provider. We just tested it on our Windows XP computer, and they work fine. There is nothing magic about Scriptomatic. If the class does not work via a script generated by Scriptomatic, you probably have a problem with WMI on your computer. You will find some resources on the Script Center to assist you in troubleshooting this issue.

Because you are talking about Windows Server 2003, you need to realize that the MSI provider is not installed by default. To install the MSI provider on your Windows Server 2003 machine, you go into Add or Remove Programs, and click Add/Remove Windows Components. The Windows Components Wizard appears. Scroll down the list of components until you see Management and Monitoring Tools, and then click Details. In the Management and Monitoring Tools dialog box, choose WMI Windows Installer Provider. It is a very small installation. Because you say you have over 100 servers, you can use sysocmgr and script the installation. This KB article talks about using sysocmgr to install optional components. If you follow the article, you will need to know the component to add. This line of code placed in your file will do the trick:

WbemMSI = On

This script will tell you if the MSI provider is installed:

FindMSIProvider.vbs

strComputer = "."
wmiNS = "\root\cimv2"
strProv = "MSI"
Set objWMIService = _
    GetObject ("winmgmts:\\" & strComputer & wmiNS) Set colItems = 
objWMIService.InstancesOf("__Win32Provider")

For Each objItem In colItems
With objItem
If InStr(1,.name, strProv,1) then
    WScript.echo .Name, .clsid _
    & vbcrlf & "hostingModel: " & .hostingModel

End If
End with
Next
 

How Can I Create and Assign a New IP Address and Subnet Mask to Statically Configure the IP Settings for the Local Area Network?

 

Hey, Scripting Guy! Question

Hey, Scripting Guy! I am try to create a script that will ask for a new IP address and Subnet mask, and then assign those values to statically configure the IP settings for the Local Area Network. I have looked at this article for changing the IP address and subnet mask. But this script attempts to change all network adapters. Any ideas?

- DD

SpacerHey, Scripting Guy! Answer

Hi DD,

We have lots of ideas about this. You first need to identify which network adapter you wish to change. The problem is that a "normal" computer can have as many as a dozen network adapters—a pptp adapter, a ppoe adapter, a connection manager adapter, a Bluetooth adapter—as well as the standard ethernet card and wireless network adapter. The problem comes into play when attempting to find the real network card. As seen in the following image, there are multiple network adapters:

Image of multiple network adapters

 

In the script you mentioned, it uses Where IPEnabled=True to attempt to limit the network cards that are only enabled with an IP address. On many computers this approach will work. In fact, this works on my laptop as seen here (using Windows ):

PS C:\> Get-WmiObject win32_networkadapterconfiguration -filter "ipenabled = $true"

DHCPEnabled      : True
IPAddress        : {192.168.1.97, fe80::e9db:821c:506c:7e24}
DefaultIPGateway : {192.168.1.254}
DNSDomain        : nwtraders.com
ServiceName      : e1express
Description      : Intel(R) 82566MM Gigabit Network Connection
Index            : 4

Why, you may ask, does this query work? Well it is because I disable all network adapters I am not using for security reasons. I had a scary experience a long time ago in an airplane when I was working and suddenly an icon popped up that said, "Now connected to Dave’s laptop." I opened the connection, and sure enough I could browse Dave’s laptop. At that point in life, I started disabling all network adapters I was not using. Plus it simplifies things like we are trying to do today!

All we really need to do is to find some property that will allow us to differentiate one specific network adapter from all the other possible network adapters. To do this, let’s take a look at the properties of the WIN32_NetworkAdapterConfiguration WMI class. They are seen here:

ArpAlwaysSourceRoute
ArpUseEtherSNAP
Caption
DatabasePath
DeadGWDetectEnabled
DefaultIPGateway
DefaultTOS
DefaultTTL
Description
DHCPEnabled
DHCPLeaseExpires
DHCPLeaseObtained
DHCPServer
DNSDomain
DNSDomainSuffixSearchOrder
DNSEnabledForWINSResolution
DNSHostName
DNSServerSearchOrder
DomainDNSRegistrationEnabled
ForwardBufferMemory
FullDNSRegistrationEnabled
GatewayCostMetric
IGMPLevel
Index
InterfaceIndex
IPAddress
IPConnectionMetric
IPEnabled
IPFilterSecurityEnabled
IPPortSecurityEnabled
IPSecPermitIPProtocols
IPSecPermitTCPPorts
IPSecPermitUDPPorts
IPSubnet
IPUseZeroBroadcast
IPXAddress
IPXEnabled
IPXFrameType
IPXMediaType
IPXNetworkNumber
IPXVirtualNetNumber
KeepAliveInterval
KeepAliveTime
MACAddress
MTU
NumForwardPackets
PMTUBHDetectEnabled
PMTUDiscoveryEnabled
ServiceName
SettingID
TcpipNetbiosOptions
TcpMaxConnectRetransmissions
TcpMaxDataRetransmissions
TcpNumConnections
TcpUseRFC1122UrgentPointer
TcpWindowSize
WINSEnableLMHostsLookup
WINSHostLookupFile
WINSPrimaryServer
WINSScopeID
WINSSecondaryServer

As you can see, there is a lot to choose from. Obviously, the MACAddress property would not be good to use, unless you had a listing of all the MACaddresses on your network. The DHCPServer property would be an interesting property to use if for instance you were getting ready to decommission a particular server. I have used the index property and the caption property for this purpose as well. For instance, if all your computers have the same kind of network card, the use of the caption property makes sense because you can filter on the maker’s name.

The WIN32_NetworkAdapter class has a netConnectionID property. This property is the same as the name property that displays "Local Area Connection." You can use the netConnectionID property to find the index or the DeviceID property of your network adapter. You can then use this to allow you to connect back to your specific network adapter. You can do this via two separate WMI queries, or you can use the association class: WIN32_NetworkAdapterSetting. This WMI class relates the WIN32_NetworkAdapter class with the WIN32_NetworkAdapterConfiguration class. The GetLocalAreaConnectionIP.ps1 script illustrates this technique.

GetLocalAreaConnectionIP.ps1

Get-WmiObject -Class win32_NetworkAdapterSetting | 
Foreach-object {
  If( ([wmi]$_.element).netConnectionID -eq "local area connection")
    {
     "Adapter: $($_.setting)"
     [wmi]$_.setting
     [wmi]$_.element
    } #end if
 } #end foreach

This article is part of a nine-part series about the above concepts, using VBScript in the examples.

Top of pageTop of page

How Can I Tell Which Version of Microsoft Office Is on My Computer?

 

Hey, Scripting Guy! Question

Hey, Scripting Guy! Is it possible to write a script that will show the version of Office on my computer?

- LM

SpacerHey, Scripting Guy! Answer

Hi LM,

Of course. We can use the WIN32_Product WMI class, which is provided by the MSI provider. Using Windows PowerShell, your script might look something like this:

GetOfficeVersion.ps1

Get-WmiObject -class win32_product -filter "name like '%office%'"

Using VBScript, the script would be a bit longer:

GetOfficeVersion.vbs

wmiquery = "Select * from Win32_Product where name like '%office%'"
Set objWmi = GetObject("Winmgmts:")
Set colItems = objWmi.execquery(wmiQuery) 
For Each item In colItems  
WScript.Echo item.name 
Next

How Can I Read Text Files Via ADO?

 

Hey, Scripting Guy! Question

Hey, Scripting Guy! Sorry to bother you. I hope you can help me. I am following your instructions about reading text files via ADO. I am working in a tab-delimited file in Visual Basic 2008. I modified the text format in my registry to tab delimited. I also created a schema.ini file in the same folder of my txt files.The schema defines the datatype of each column, but one column that is supposed to be considered as text, the ADO column, is not importing the data. (When I check the column 3 value, there is nothing). This is the schema:

[HCSR879C_092_20081103.txt]
Format=TabDelimited
Col1 = ProgramName text
Col2 = ProgramCode text
Col3 = LocationCode text
Col4 = SmstrHrsCrdt double
Col5 = WrkFrcContEdu double
Col6 = NonFundContEdu double
Col7 = AdultLitcy double
Col8 = UndupEnroll double

Col3 is a mix. It can be numeric or text or alphanumeric. So in the schema its datatype is text, but it seems that ADO does not care. I am a little frustrated after an hour of trying different approaches. Any help will be really appreciated.

- JM

SpacerHey, Scripting Guy! Answer

Hi JM,

The Much ADO About Text Files article is something we still refer to on occasion. You should give it a read. You do not or should not need both a schema.ini and a registry entry. The article was written for VBScript and not for Visual Basic or Visual Basic .NET. However, I imagine it should work. If I were doing Visual Basic .NET, I think I would use ADO.NET instead of COM ADO because it is generally easier to use. I would think the problem is with your schema.ini file, but that’s just a guess. Make sure the file is in the same folder as the one from where you are reading the CSV file. Here are some more Help articles. They should apply to both ADO.NET and COM ADO as well:

http://support.microsoft.com/kb/149090/en-us

http://support.microsoft.com/kb/146224/en-us

http://support.microsoft.com/kb/205439/en-us

You may be able to find some inspiration in our Databases Scripting Hub. You may also want to ask a question at the The Official Scripting Guys Forum, there are a lot of very smart people who hang out over there.

 

How Can I Extract Information About Remote Users on My Citrix Server?

 

Hey, Scripting Guy! Question

Hey, Scripting Guy! I am still plugging away at my attempt to extract information regarding remote users on my Citrix servers. I am able to create a file from the output of the "QWINSTA.EXE" command. However, I cannot seem to copy that file to my own "C:\temp\" folder. The script below is what I am using:

Const ForReading = 1
Const ForWriting = 2

Set oWshNet = CreateObject("WScript.Network")
sComputerName = "myComputer"

sUserName = GetUser(sComputerName)

Function GetUser(sHost)
    Set oShell = CreateObject("Wscript.Shell")
    Set oFS = CreateObject("Scripting.FileSystemObject")
    Set fileName = oFS.CreateTextFile("C:\temp\RemoteUsers.txt")
    sTmpFile = oFS.GetSpecialFolder(2).ShortPath & "\" & "RemoteUsers.txt"

'Run command and redirect stdout and stderr into temp file
    oShell.Run "%ComSpec% /c %SystemRoot%\System32\QWINSTA.EXE /SERVER:" _
 & sHost & " >" & sTmpFile & " 2>&1", 0, True

'Open the temp file
    Set oTF = oFS.OpenTextFile(sTmpFile)
    Set newFile = oFS.OpenTextFile(fileName, ForWriting)
    oFS.CopyFile sTmpFile, fileName, True
End Function

The error that appears occurs in this line:

 Set newFile =oFS.OpenTextFile(fileName, ForWriting)

The error message indicates a "Type Mismatch". I cannot see how this could be, since both files have been created as "Text" files.

The "sTmpFile" path is to "Documents & Settings\ (my User ID)\LocalSettings\Temp". Can you see anything that I may have missed, vis-a-vis the proper use of the File System Object? This should not be such a difficult process. However, I simply cannot see what is amiss.

- FS

SpacerHey, Scripting Guy! Answer

Hi FS,

You are in fact getting a type mismatch error. You are creating a file object here:

  Set fileName = oFS.CreateTextFile("C:\temp\RemoteUsers.txt")

The OpenTextFile method takes a string and not a file object. Notice that you have a file object stored in the filename variable—not a string!

oFS.OpenTextFile(fileName, ForWriting)

If you store your file name / path in a variable, you can then modify your codethusly:

filePath = "C:\temp\RemoteUsers.txt"
Set fileName = oFS.CreateTextFile(filePath)
oFS.OpenTextFile(filePath, ForWriting)

Of course I would recommend renaming the filename variable to something else, such as objFile. You are right, it should not be this hard. This is why we invented Windows PowerShell.

 

How Can I Archive E-Mail on a Schedule Using Windows PowerShell?

 

Hey, Scripting Guy! Question

Hey, Scripting Guy! I have created a Windows PowerShell script that will go into specified mailboxes on Exchange Server and extract old e-mails out to an Outlook PST file. I have also created a Windows PowerShell script to be run from a command so that it can be called with a task scheduler.

In the Windows PowerShell script, I have hard coded a date that is back 6 months, -EndDate "09/16/08". What I would like to do is add a line to the script that automatically removes the last 6 months allowing me to put the .bat file into a scheduler and it would clean on its own.

I am sure that I use the Get-Date cmdlet, but I am unsure of the syntax. Thanks guys, I would have never gotten this far had it not been for your articles.

- TC

SpacerHey, Scripting Guy! Answer

Hi TC,

I am glad you find our articles helpful. You can do this:

(get-date).adddays(-180)

 

How Can I Permit a Nonadministrator to Make Remote WMI Calls into a Remote PC?

 

Hey, Scripting Guy! Question

Hey, Scripting Guy! I need a script that changes the DCOM permission on a remote PC so that a non-administrator user can make remote WMI calls into the remote PC. I need this script so that I can carry out the task for 8000+ PCs.

- VN

SpacerHey, Scripting Guy! Answer

Hi VN,

This article talks about the remote WMI connection. Beginning with Windows Vista, you can use methods from this WMI class: win32_DcomApplicationSetting. Prior to that, you are pretty much limited to hacking the registry. You may want to ping the Official Scripting Guys Forum to see if anyone has already written any scripts to do this. You may also be interested in the scripts found in the Community-Submitted Scripts Center.

 

This concludes another Quick-Hits Friday. This also brings to a close another exciting week at the Script Center! Take care, and join us next week. TTFN.

 

Ed Wilson and Craig Liebendorfer, Scripting Guys