这是这个问题的后续内容。
我使用这个稍微修改过的脚本来枚举所有安装的MSI包:
strComputer = "."
Set objWMIService = GetObject("winmgmts:" & _
"{impersonationLevel=impersonate}!\" & _
strComputer & _
"rootcimv2")
Set colSoftware = objWMIService.ExecQuery _
("SELECT * FROM Win32_Product")
If colSoftware.Count > 0 Then
For Each objSoftware in colSoftware
WScript.Echo objSoftware.Caption & vbtab & _
objSoftware.Version
Next
Else
WScript.Echo "Cannot retrieve software from this computer."
End If
然而,令人惊讶的是其糟糕的表现。枚举我的XP盒子上安装的34个MSI包需要3到5分钟!
相比之下,旁边的Linux盒子需要7秒才能枚举出1400多个RPM叹息
有什么线索吗?
极度缓慢是枚举Win32_Products 的已知/常见问题
如果您需要替代解决方案,请考虑使用"卸载"注册表项(如您提到的原始问题的答案之一所建议的)建立自己的产品列表。
列举卸载的一些通用参考:
- TechNet VBScript示例:列出已安装的软件
- Microsoft KB:如何枚举可以在计算机上卸载的软件产品
要远程执行,请使用WMI注册表类StdRegProv。TechNet甚至方便地提供了一个使用StdRegProv做您想要的事情的简单示例:如何列出给定机器上所有已安装的应用程序
Win32_Product WMI类速度太慢,因为它正在进行一致性检查-每次使用Msiexec.exe处理每个包。
请在此页面查看问题和vbscript代码,以便使用更好的方法:http://csi-windows.com/toolkit/288-win32product-wmi-class-replacement
当您使用在msi.h中声明的api函数时,您的速度很快。我正在为我的软件uptodate使用api,枚举数百个数据包需要一秒钟的时间。
我怀疑是网络问题,Wireshark证明我是对的。
Windows安装程序似乎很乐意尝试重新打开所有原始的.msi文件,包括那些住在网络共享上的文件。
这对我有效,避免了WMI方法的缓慢:
Dim installer
Set installer = CreateObject("WindowsInstaller.Installer")
Dim productCode, productName
For Each productCode In installer.Products
productName = installer.ProductInfo(productCode, "ProductName")
WScript.Echo productCode & " , " & productName
Next
有关Installer
对象的详细信息,请访问http://msdn.microsoft.com/en-us/library/windows/desktop/aa369432(v=vs.85).aspx