Tek-Tips is the largest IT community on the Internet today!

Members share and learn making Tek-Tips Forums the best source of peer-reviewed technical information on the Internet!

  • Congratulations Mike Lewis on being selected by the Tek-Tips community for having the most helpful posts in the forums last week. Way to Go!

Win32_Product returns (null): 0x80041010 Error

Status
Not open for further replies.

cluM09

Technical User
May 15, 2004
127
0
0
US
Hello,

I tried to write a script to enumerate the installed software on a Windows 2003 Server. However, I keep getting the error (null): 0x80041010 from the WMI class Win32_Product. The script works fine on my XP workstation and Windows 2000 Server machines.

My code is listed below:

strComputer = "."
arrSoftware = EnumSoftware(strComputer)

For Each objItem In arrSoftware
Wscript.Echo objItem
Next

Private Function EnumSoftware(ByVal strComputer)
Dim objDicData, objWMIService, colItems, objItem
Set objDicData = CreateObject("Scripting.Dictionary")
Set objWMIService = GetObject("winmgmts:" _
& "{impersonationLevel=impersonate}!\\" & strComputer & "\root\cimv2")
Set colItems = objWMIService.ExecQuery("SELECT * FROM Win32_Product")
For Each objItem In colItems
If Not objDicData.Exists(objItem.Caption) Then
objDicData.Add objItem.Caption, objItem.Caption & vbTab & objItem.Version
End If
Next
EnumSoftware = objDicData.Items
Set objWMIService = Nothing: Set colItems = Nothing
End Function

I get the WMI error at the line "For Each objItem In colItems" in the the For Loop in the function.

I would appreciate it if anyone can point me to the right direction on how to correct this problem.

Thanks!

CluM09
 
Win32_Product class is not installed by default on Windows Server 2003.

1. In Add or Remove Programs, click Add/Remove Windows Components.

2. In the Windows Components Wizard, select Management and Monitoring Tools and then click Details.

3. In the Management and Monitoring Tools dialog box, select WMI Windows Installer Provider and then click OK.

4. Click Next.

--------------------------------------------------------------------------------
dm4ever
My philosophy: K.I.S.S - Keep It Simple Stupid
 
dm4ever,

Thank you for the information!

But I have a lot of Windows 2003 Servers that are configured that way in my environment.

Is there any other alternative to eneumerate the software installed on the Windows 2003 Server machines?

I found an MSI script that can also enumerate the installed software from However, it can only be run on the console of the machine to enumerate the installed software.

I modified the script to enumerate the product name and version in a command prompt mode, but I don't think that this script can be modidied to run remotely like WMI script. However, the script does run much faster than WMI script. Do you have any idea how to modify this script so that I can run remotely?

I hate to use a method to copy the script to the remote machine, run it, and collect the data back since some of our servers have their admin share disabled.

The code I have so far is listed below:

Dim WI, ProgramObject, AEnum(), sID, oProds, i2
Set WI = CreateObject("WindowsInstaller.Installer") '--create Installer object.
Set oProds = WI.Products '-- Windows Installer Products collection.
i2 = oProds.count
'-- Fill array with IDs of installed software.

If (i2 > 0) then '-- if there are W.I. installations then ....
ReDim AEnum(i2 - 1)
For i = 0 to (i2 - 1)
AEnum(i) = oProds.Item(i) '-- .... collect an array of the Product IDs.
Next

'-- describe first installed program returned in list of IDs:
'sID = AEnum(0) '-- first product ID.
For Each sID In AEnum

Set ProgramObject = GetProduct(sID) '-- Get Product object, an instance of MSIProduct class for this Product ID.
If Not ProgramObject Is Nothing Then '-- test for success in returning a Product object.
Wscript.Echo ProgramObject.Name & vbTab & ProgramObject.Version
End If

Set ProgramObject = Nothing

Next

End If

Set oProds = Nothing
Set WI = Nothing

Function GetProduct(sGUID)
Dim RetGP, ObMSIGP
On Error Resume Next
Set ObMSIGP = New MSIProduct
RetGP = ObMSIGP.GetP(sGUID)
If (RetGP = True) Then
Set GetProduct = ObMSIGP
End If
Set ObMSIGP = Nothing
End Function

Class MSIProduct
Private WI, sID, DB, BooDB, View, Rec
Private AData(), AFeats()

Public Function GetP(ProdGUID)
Dim AProps, i, i2, sItem, SL
On Error Resume Next
Err.clear
i = WI.ProductState(ProdGUID)
If (Err.number <> 0) or (i < 2) Then '-- Not installed.
GetP = False
Exit Function
End If

AProps = array("ProductName", "VersionString", "InstallDate", "Publisher", "LocalPackage", "InstallLocation")
sID = ProdGUID
'-- first Get most basic properties of product.
'-- InstallLocation is Not included here because it's often missing.
'-- InstallSource is Not included because it's Not of much use, only telling the path
'-- of MSI file at time of install.
For i = 0 to 5
sItem = AProps(i)
AData(i) = WI.ProductInfo(sID, sItem)
Next

'-- Collect list of features into the AFeats array.
ReDim AFeats(0) '-- Set at least one array item For return If no features.
AFeats(0) = ""
Set SL = WI.Features(sID)
If (isEmpty(SL) = False) Then
i = SL.Count
If (i > 0) Then
ReDim AFeats(i - 1)
For i2 = 0 to (i - 1)
AFeats(i2) = SL.Item(i2)
Next
End If
Set SL = Nothing
End If

GetDB AData(4) '-- Get database object If LocalPackage path is valid.
GetP = True
End Function

Public Property Get Name()
Name = AData(0)
End Property

'-- Publisher -------------------
Public Property Get Company()
Company = AData(3)
End Property

'-- Version -------------------
Public Property Get Version()
Version = AData(1)
End Property

'-- InstallDate -------------------
Public Property Get InstallDate()
InstallDate = AData(2)
End Property

'-- MSIFilePath -------------------
Public Property Get MSIFilePath()
MSIFilePath = AData(4)
End Property

'-- parent folder path of installed program.
Public Property Get ProgramPath()
ProgramPath = AData(5)
End Property

'-- Features as array. If none avail. Then Features(0) = ""
Public Property Get Features()
Features = AFeats
End Property

'-- Boolean value - whether or not feature is currently installed.
Public Property Get FeatureInstalled(sFeat)
Dim i3
On Error Resume Next
i3 = WI.FeatureState(sID, sFeat)
If (i3 = 3) Then
FeatureInstalled = True
Else
FeatureInstalled = False
End If
End Property

'-- feature parent. Returns parent feature name or "none". --------------
Public Property Get FeatureParent(sFeat)
Dim s1
On Error Resume Next
s1 = WI.FeatureParent(sID, sFeat)
If (len(s1) = 0) Then s1 = "none"
FeatureParent = s1
End Property

'-- feature description. This is available from the Session object but that would mean
'-- creating an installation session just to get this info. Since the database had to be
'-- opened anyway, the description can be retrieved from the Feature table. -------
'-- This returns feature description, if any. In many cases description is missing.
'-- In that Case it returns "none".
Public Property Get FeatureDescription(sFeat)
Dim s1
If (BooDB = False) Then
FeatureDescription = ""
Exit Property
End If
On Error Resume Next
Set View = DB.OpenView("SELECT `Description` FROM `Feature` WHERE `Feature` = '" & sFeat & "'")
View.execute
Set Rec = View.Fetch
If Not Rec is Nothing Then
s1 = Rec.stringdata(1) '--description.
If (len(s1) = 0) Then s1 = "none"
FeatureDescription = s1
Set Rec = Nothing
End If
Set View = Nothing
End Property

'-- Property that enables checking whether MSI file was available and whether database was successfully opened.
Public Property Get HaveDatabase() '--boolean.
HaveDatabase = BooDB
End Property

'-- feature components. returns array of component names for given feature. If failed, returns array(0) = "" ---------
Public Property Get Components(sFeature)
Dim s1, AComps(), iComps
ReDim AComps(0)
AComps(0) = ""
If (BooDB = False) Then
Components = AComps
Exit Property
End If
On Error Resume Next

iComps = 0
Set View = DB.OpenView("SELECT `Component_` FROM `FeatureComponents` WHERE `Feature_` = '" & sFeature & "'")
View.execute
Do
Set Rec = View.Fetch
If Rec is Nothing Then Exit Do
s1 = Rec.stringdata(1)
If (len(s1) > 0) Then
ReDim preserve AComps(iComps)
AComps(iComps) = s1
iComps = (iComps + 1)
End If
s1 = ""
Loop
Set Rec = Nothing
Set View = Nothing
Components = AComps
End Property

'-- Get array of files included in given component as: FileName|version. return array(0) = "" If failed.
Public Property Get Files(sComponent)
Dim s1, AFils(), iFils
ReDim AFils(0)
AFils(0) = ""
If (BooDB = False) Then
Files = AFils
Exit Property
End If
On Error Resume Next
iFils = 0
Set View = DB.OpenView("SELECT `FileName`, `Version` FROM `File` WHERE `Component_` = '" & sComponent & "'")
View.execute
Do
Set Rec = View.Fetch
If Rec is Nothing Then Exit Do
s1 = Rec.stringdata(1)
If (len(s1) > 0) Then
ReDim preserve AFils(iFils)
s1 = s1 & "|" & Rec.stringdata(2)
AFils(iFils) = s1
iFils = (iFils + 1)
End If
s1 = ""
Loop
Set Rec = Nothing
Set View = Nothing
Files = AFils
End Property

'--/////////// Private ///////////////------------------

Private Sub Class_Initialize()
BooDB = False
Set WI = CreateObject("WindowsInstaller.Installer")
ReDim AData(5)
End Sub

Private Sub Class_Terminate()
Set DB = Nothing
Set WI = Nothing
End Sub

'-- Get Database object for package file so that feature and component info. can be extracted.
'-- The OpenDatabase Function of the Installer object will return a database object that provides
'-- access to the numerous tables that collectively hold the information about what the program
'-- is, what features are included, what components make up those features, what files and
'-- Registry settings make up those components, etc.
'-- To get the Database object a file path to the MSI install file is needed.
'-- That was retrieved through the "LocalPackage" value of the Installer.ProductInfo Property.
'-- If no local MSI file is found then the database cannot be opened and some info. will
'-- not be available.
Private Sub GetDB(sPath)
Dim FSO
Err.clear
On Error Resume Next
Set FSO = CreateObject("Scripting.FileSystemObject")
If (FSO.FileExists(sPath) = False) Then
Set FSO = Nothing
Exit Sub
End If
Set DB = WI.OpenDatabase(sPath, 0) '-- database object.
If (Err.number = 0) Then BooDB = True '-- success. BooDB = True informs other functions that
'-- a database object has been retrieved and can be used.
Set FSO = Nothing
End Sub

End Class


Thanks again!

CluM09
 
I think the quickest way would be to get the information from the registry using WMI and StdRegProv

HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall

This method should return all the software since Win32_Product only returns software installed using an MSI package.

--------------------------------------------------------------------------------
dm4ever
My philosophy: K.I.S.S - Keep It Simple Stupid
 
dm4ever,

I also have a function to get the installed software from the registry, but it cannot get all the installed software. The reason is that not all software installation will have the uninstall entries in the registry. Also, the registry entries will not contain the version information for the software.

Therefore, I need to find another alternative.

CluM09
 
Have you looked under:
HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\Installer\UserData

--------------------------------------------------------------------------------
dm4ever
My philosophy: K.I.S.S - Keep It Simple Stupid
 
Status
Not open for further replies.

Part and Inventory Search

Sponsor

Back
Top