windows安装程序-为什么枚举已安装的MSI包如此缓慢



这是这个问题的后续内容。

我使用这个稍微修改过的脚本来枚举所有安装的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

最新更新