WMI - select from Win32_Product takes a long time

11,224

Solution 1

WMI is taking it's time as you already noticed. Iterating through the registry might do the trick for you.

You might have a look at Get installed applications in a system here on stackoverflow, where both methods are mentioned.

Solution 2

If you query "Win32_product" the msi-installer checks and validates every product.

The KB article http://support.microsoft.com/kb/974524 shows:

Win32_product Class is not query optimized. Queries such as “select * from Win32_Product where (name like 'Sniffer%')” require WMI to use the MSI provider to enumerate all of the installed products and then parse the full list sequentially to handle the “where” clause. This process also initiates a consistency check of packages installed, verifying and repairing the install. With an account with only user privileges, as the user account may not have access to quite a few locations, may cause delay in application launch and an event 11708 stating an installation failure.

Win32reg_AddRemovePrograms is a much lighter and effective way to do this, which avoids the calls to do a resiliency check, especially in a locked down environment. So when using Win32reg_AddRemovePrograms we will not be calling on msiprov.dll and will not be initiating a resiliency check.

So be careful with "Win32_product".

Update: nice article https://sdmsoftware.com/group-policy-blog/wmi/why-win32_product-is-bad-news/

Solution 3

You Should use SELECT Name FROM Win32_Product in WMI Query, it works for me

SELECT * make Load all Data Members, so using it are taking much time

Solution 4

As Bernhard points out, WMI use of Win32_Product initiates an integrity check of the package estate, and will hence be quite slow to use - and in special cases it can trigger an MSI self-repair (I have never seen this happen on my machines).

Instead of WMI, you can use the MSI automation interface directly to enumerate the applications installed via Windows Installer packages (MSI files) on the machine. This is very quick and doesn't touch WMI at all.

See this example: how to find out which products are installed - newer product are already installed MSI windows (full blown, but basic and easy to understand VBScript example - do check it out). There are many properties you can retrieve for each product, please consult the MSDN documentation for the MSI automation interface. The linked sample VBScript code and the MSDN documentation taken together should help you get going quickly I hope.

P.S: I know this is an old question, but this issue keeps coming up (specifically the slowness of WMI) - just for future reference.

Solution 5

As mentioned here Registry is not reliable and WMI is slow. Thus for me the best option was using Windows Installer API. Add msi.dll to your references and then adapt the following code to your needs:

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;
}
Share:
11,224
invertigo
Author by

invertigo

.NET Developer, Systems Engineer

Updated on June 05, 2022

Comments

  • invertigo
    invertigo almost 2 years

    I am enumerating installed applications using WMI, and this block is taking a relatively long time to complete no matter how I structure it. It takes 13 seconds in my environment every time. Is there a better (faster) way to check if a program is installed? (I'm using iTunes as an example program to check for)

        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);
        }
    

    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
    
  • invertigo
    invertigo almost 10 years
    iterating through the registry is substantially faster, though it has its own nuances i'll have to work through to see if its a viable option
  • invertigo
    invertigo over 9 years
    this ended up being the best solution because it was a) faster and b) selecting from win32_product logs and entry to event viewer for each application that was queried, an undesirable side effect for my application
  • Stein Åsmul
    Stein Åsmul over 6 years
    Yes, I have added another answer to this question with information on how to use the MSI automation interface to enumerate installed MSI files instead. I just want to mention that use of WMI's Win32_Product does indeed initiate a check of the package estate, but a self-repair is only triggered if an inconsistency is found. I have never had this happen on any of my boxes, but it can happen. But overall WMI is quite slow. It is useful, but use something else if you can.
  • Kiquenet
    Kiquenet almost 5 years
    alternative to use WMI Win32_Product ?