WMI – 从Win32_Product中选择需要很长时间

我使用WMI枚举已安装的应用程序,无论我如何构建它,这个块都需要相对较长的时间才能完成。 每次在我的环境中需要13秒。 是否有更好(更快)的方法来检查是否安装了程序? (我使用iTunes作为示例程序来检查)

private static string Timestamp { get { return DateTime.Now.ToString("HH:mm:ss.ffff"); } } private static void LoadInstalledPrograms() { List installedPrograms = new List(); Console.WriteLine("0 - {0}", Timestamp); ManagementObjectSearcher mos = new ManagementObjectSearcher("SELECT * FROM Win32_Product"); Console.WriteLine("1 - {0}", Timestamp); ManagementObjectCollection managementObjectCollection = mos.Get(); Console.WriteLine("2 - {0}", Timestamp); foreach (ManagementObject mo in managementObjectCollection) { installedPrograms.Add(mo["Name"].ToString()); } Console.WriteLine("3 - {0}", Timestamp); Console.WriteLine("Length - {0}", installedPrograms.Count); } 

SELECT * FROM Win32_Product

 0 - 08:08:51.3762 1 - 08:08:51.3942 2 - 08:08:51.4012 3 - 08:09:04.8326 Length - 300 

SELECT * FROM Win32_Product WHERE name =’iTunes’

 0 - 08:14:17.6529 1 - 08:14:17.6709 2 - 08:14:17.6779 3 - 08:14:31.0332 Length - 1 

SELECT * FROM Win32_Product WHERE name LIKE’iTunes’

 0 - 08:16:38.2719 1 - 08:16:38.2899 2 - 08:16:38.2999 3 - 08:16:51.5113 Length - 1 

SELECT name FROM Win32_Product WHERE name LIKE’iTunes’

 0 - 08:19:53.9144 1 - 08:19:53.9324 2 - 08:19:53.9394 3 - 08:20:07.2794 Length - 1 

正如你已经注意到的那样,WMI正在花时间。 通过注册表迭代可能会为您解决问题。

您可以在stackoverflow上查看系统中的已安装应用程序 ,其中提到了两种方法。

如果您查询“Win32_product”, 则msi-installer会检查并validation每个产品。

知识库文章http://support.microsoft.com/kb/974524显示:

Win32_product类不是查询优化的。 查询诸如“select * from Win32_Product where(name like’Sniffer%’)”要求WMI使用MSI提供程序枚举所有已安装的产品,然后按顺序解析完整列表以处理“where”子句。 此过程还会启动对已安装,validation和修复安装的软件包的一致性检查。 对于仅具有用户权限的帐户,由于用户帐户可能无法访问很多位置,因此可能导致应用程序启动延迟,并且事件11708指出安装失败。

Win32reg_AddRemovePrograms是一种更轻松有效的方法,可以避免执行弹性检查的调用,尤其是在锁定环境中。 因此,当使用Win32reg_AddRemovePrograms时,我们不会调用msiprov.dll,也不会启动弹性检查。

所以要小心“Win32_product”。

更新:好文章https://sdmsoftware.com/group-policy-blog/wmi/why-win32_product-is-bad-news/

您应该在WMI查询中使用SELECT Name FROM Win32_Product ,它适用于我

SELECT * make加载所有数据成员,因此使用它需要花费很多时间

正如Bernhard指出的那样, WMI使用Win32_Product启动了对包属性的完整性检查,因此使用起来会很慢 – 在特殊情况下它可以触发MSI自我修复(我从未在机器上看到过这种情况) 。

您可以直接使用MSI自动化界面来枚举通过计算机上的Windows Installer程序包(MSI文件)安装的应用程序,而不是WMI。 这非常快,根本不接触WMI。

请参阅此示例如何找出已安装的产品 – 已安装较新的产品MSI窗口完整版,但基本且易于理解的VBScript示例 – 请查看它 )。 您可以为每种产品检索许多属性,请参阅MSDN自动化界面MSDN文档 。 链接的示例VBScript代码和MSDN文档一起使用可以帮助您快速开始我希望。

PS:我知道这是一个老问题,但这个问题不断出现(特别是WMI的缓慢) – 仅供将来参考。

如前所述,注册表不可靠,WMI很慢。 因此,对我来说,最好的选择是使用Windows Installer API。 将msi.dll添加到您的引用,然后根据您的需要调整以下代码:

 public static string GetVersionOfInstalledApplication(string queryName) { string name; string version; Type type = Type.GetTypeFromProgID("WindowsInstaller.Installer"); Installer installer = Activator.CreateInstance(type) as Installer; StringList products = installer.Products; foreach (string productGuid in products) { string currName = installer.ProductInfo[productGuid, "ProductName"]; string currVersion = installer.ProductInfo[productGuid, "VersionString"]; if (currName == queryName) { name = currName; version = currVersion; return version; } } return null; }