代码之家  ›  专栏  ›  技术社区  ›  invertigo

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

  •  4
  • invertigo  · 技术社区  · 12 年前

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

        private static string Timestamp
        {
            get { return DateTime.Now.ToString("HH:mm:ss.ffff"); }
        }
    
        private static void LoadInstalledPrograms()
        {
            List<string> installedPrograms = new List<string>();
            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);
        }
    

    从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
    

    从Win32_Product WHERE名称中选择名称,如“iTunes”

    0 - 08:19:53.9144
    1 - 08:19:53.9324
    2 - 08:19:53.9394
    3 - 08:20:07.2794
    Length - 1
    
    6 回复  |  直到 12 年前
        1
  •  6
  •   Community Mohan Dere    6 年前

    如果查询“Win32_product” msi安装程序检查并验证每个产品。

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

    Win32_product Class未进行查询优化。从Win32_Product where(名称如“Sniffer%”)中选择*等查询要求WMI使用MSI提供程序枚举所有已安装的产品,然后按顺序分析完整列表以处理where子句。此过程还启动已安装软件包的一致性检查,验证并修复安装。对于仅具有用户权限的帐户,由于用户帐户可能无法访问相当多的位置,因此可能会导致应用程序启动延迟,并导致事件11708说明安装失败。

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

    因此,请小心使用“Win32_product”。

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

        2
  •  3
  •   Community Mohan Dere    9 年前

    正如你已经注意到的那样,WMI正在抓紧时间。遍历注册表可能会为您带来好处。

    你可以看看 Get installed applications in a system 这里是stackoverflow,这里提到了两种方法。

        3
  •  2
  •   Stein Åsmul    8 年前

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

    您可以使用 MSI自动化接口 直接枚举通过计算机上的Windows安装程序包(MSI文件)安装的应用程序。这非常快速,根本不涉及WMI。

    参见此示例 : how to find out which products are installed - newer product are already installed MSI windows ( 完整但基本且易于理解的VBScript示例-请查看 ). 您可以为每个产品检索许多财产,请参阅 MSDN documentation for the MSI automation interface 。我希望链接的VBScript示例代码和MSDN文档可以帮助您快速入门。

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

        4
  •  2
  •   tilchev    8 年前

    如上所述 here 注册表不可靠,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;
    }
    
        5
  •  1
  •   willnode    12 年前

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

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

        6
  •  0
  •   js2010    3 年前

    Powershell 5.1改为“get package”。

    get-package *chrome*
    
    Name                           Version          Source                 ProviderName
    ----                           -------          ------                 ------------
    Google Chrome                  109.0.5414.75                           msi