How to NOT Use Win32_Product in Group Policy Filtering

How to NOT Use Win32_Product in Group Policy Filtering

  • Comments 21
  • Likes

Hi all, Ned here again. I have worked many slow boot and slow logon cases over my career. The Directory Services support team here at Microsoft owns a sizable portion of those operations - user credentials, user profiles, logon and startup scripts, and of course, group policy processing. If I had to pick the initial finger pointing that customers routinely make, it's GP. Perhaps it's because group policy is the least well-understood part of the process, or maybe because it's the one with the most administrative fingers in the pie. When it comes down to reality though, group policy is more often not the culprit. Our new changes in Windows 8 will help you make that determination much quicker now.

Today I am going to talk about one of those times that GPO is the villain. Well, sort of... he's at least an enabler. More appropriately, the optional WMI Filtering portion of group policy using the Win32_Product class. Win32_Product has been around for many years and is both an inventory and administrative tool. It allows you to see all the installed MSI packages on a computer, install new ones, reinstall them, remove them, and configure them. When used correctly, it's a valuable option for scripters and Windows PowerShell junkies.

Unfortunately, Win32_Product also has some unpleasant behaviors. It uses a provider DLL that validates the consistency of every installed MSI package on the computer - or off of it, if using a remote administrative install point. That makes it very, very slow.

Where people trip up usually is group policy WMI filters. Perhaps the customer wants to apply managed Internet Explorer policy based on the IE version. Maybe they want to set AppLocker or Software Restriction policies only if the client has a certain program installed. Perhaps even use - yuck - Software Installation policy in a more controlled fashion.

Today I talk about some different options. Mike didn’t write this but he had some good thoughts when we talked about this offline so he gets some credit here too. A little bit. Tiny amount, really. Hardly worth mentioning.

If you have no idea what group policy WMI filters are, start here:

Back? Great, let's get to it.

Don’t use Win32_Product

The Win32_Product WMI class is part of the CIMV2 namespace and implements the MSI provider (msiprov.dll and associated msi.mof) to list and validate installed installation packages. You will see MsiInstaller event 1035 in the Application log for each application queried by the class:

Source: MsiInstaller
Event ID: 1035
Description:
Windows Installer reconfigured the product. Product Name: <ProductName>. Product Version: <VersionNumber>. Product Language: <languageID>. Reconfiguration success or error status: 0.

And constantly repeated System events:

Event Source: Service Control Manager

Event ID: 7035

Description:

The Windows Installer service was successfully sent a start control.

 

Event Type: Information

Event Source: Service Control Manager

Event ID: 7036

Description:

That validation piece is the real speed killer. So much, in fact, that it can lead to group policy processing taking many extra minutes in Windows XP when you use this class in a WMI filter - or even cause processing to time out and fail altogether.. This is even more likely when:

  • The client contains many installed applications
  • Installation packages are sourced from remote file servers
  • Install packages used certificate validation and the user cannot access the certificate revocation list for that package
  • Your client hardware is… crusty.

Furthermore, Windows Vista and later Windows versions cap WMI filters execution times at 30 seconds; if they fail to complete by then, they are treated as FALSE. On those OS versions, it will often appear that Win32_Product just doesn’t work at all.

image

What are your alternatives?

Group Policy Preferences, maybe

Depending on what you are trying to accomplish, Group Policy Preferences could be the solution. GPP includes item-level targeting that has fast, efficient filtering of just about any criteria you can imagine. If you are trying to set some computer-based settings that a user cannot change and don’t mind preferences instead of managed policy settings, GPP is the way to go. As with all software, make sure you evaluate our latest patches to ensure it works as desired. As of this writing, those are:

For instance, let's say you have a plotting printer that Marketing cannot correctly use without special Contoso client software. Rather than using managed computer policy to control client printer installation and settings, you can use GPP Registry or Printer settings to modify the values needed.

image

Then you can use Item Level Targeting to control the installation based on the specialty software's presence and version.

image

image

Alternatively, you can use the registry and file system for your criteria, which works even if the software doesn't install via MSI packages:

image

An alternative to Win32_Product

What to do if you really, really need to use a WMI filter to determine MSI installed versions and names though? If you look around the Internet, you will find a couple of older proposed solutions that - to be frank - will not work for most customers.

  1. Use the Win32reg_AddRemovePrograms class instead.
  2. Use a custom class (like described here and frequently copied/pasted on the Interwebz).

The Win32reg_AddRemovePrograms is not present on most client systems though; it is a legacy class, first delivered by the old SMS 2003 management WMI system. I suspect one of the reasons the System Center folks discarded its use years ago for their own native inventory system was the same reason that the customer class above doesn’t work in #2 - it didn’t return 32-bit software installed on 64-bit computers. The class has not been updated since initial release 10 years ago.

#2 had the right idea though, at least as a valid customer workaround to avoid using Win32_Product: by creating your own WMI class using the generic registry provider to examine just the MSI uninstall registry keys, you can get a fast and simple query that reasonably detects installed software. Armed with the "how", you can also extend this to any kind of registry queries you need, without risk of tanking group policy processing. To do this, you just need notepad.exe and a little understanding of WMI.

Roll Your Own Class

Windows Management Instrumentation uses Managed Operation Framework (MOF) files to describe the Common Information Model (CIM) classes. You can create your own MOF files and compile them into the CIM repository using a simple command-line tool called mofcomp.exe.

You need to be careful here. This means that once you write your MOF you should validate it by using the mofcomp.exe -check argument on your standard client and server images. It also means that you should test this on those same machines using the -class:createonly argument (and not setting the -autorecover argument or #PRAGMA AUTORECOVER pre-processor) to ensure it doesn't already exist. The last thing you want to do is break some other class.

When done testing, you're ready to give it a go. Here is a sample MOF, wrapped for readability. Note the highlighted sections that describe what the MOF examines and what the group policy WMI filter can use as query criteria. Unlike the oft-copied sample, this one understands both the normal native architecture registry path as well as the Wow6432node path that covers 32-bit applications installed on a 64-bit system.

Start copy below =======>

// "AS-IS" sample MOF file for returning the two uninstall registry subkeys

// Unsupported, provided purely as a sample

// Requires compilation. Example: mofcomp.exe sampleproductslist.mof

// Implements sample classes: "SampleProductList" and "SampleProductlist32"

//   (for 64-bit systems with 32-bit software)

 

#PRAGMA AUTORECOVER

 

[dynamic, provider("RegProv"),

ProviderClsid("{fe9af5c0-d3b6-11ce-a5b6-00aa00680c3f}"),ClassContext("local|HKEY_LOCAL_MACHINE\\SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Uninstall")]

class SampleProductsList {

[key] string KeyName;

[read, propertycontext("DisplayName")] string DisplayName;

[read, propertycontext("DisplayVersion")] string DisplayVersion;

};

 

[dynamic, provider("RegProv"),

ProviderClsid("{fe9af5c0-d3b6-11ce-a5b6-00aa00680c3f}"),ClassContext("local|HKEY_LOCAL_MACHINE\\SOFTWARE\\Wow6432node\\Microsoft\\Windows\\CurrentVersion\\Uninstall")]

class SampleProductsList32 {

[key] string KeyName;

[read, propertycontext("DisplayName")] string DisplayName;

[read, propertycontext("DisplayVersion")] string DisplayVersion;

};

<======= End copy above

Examining this should also give you interesting ideas about other registry-to-WMI possibilities, I imagine.

Test Your Sample

Copy this sample to a text file named with a MOF extension, store it in the %systemroot%\system32\wbem folder on a test machine, and then compile it from an administrator-elevated CMD prompt using mofcomp.exe filename. For example:

image

To test if the sample is working you can use WMIC.EXE to list the installed MSI packages. For example, here I am on a Windows 7 x64 computer with Office 2010 installed; that suite contains both 64 and 32-bit software so I can use both of my custom classes to list out all the installed software:

image

Note that I did not specify a namespace in the sample MOF, which means it updates the \\root\default namespace, instead of the more commonly used \\root\cimv2 namespace. This is intentional: the Windows XP implementation of registry provider is in the Default namespace, so this makes your MOF OS agnostic. It will work perfectly well on XP, 2003, 2008, Vista, 7, or even the Windows 8 family. Moreover, I don’t like updating the CIMv2 namespace if I can avoid it - it already has enough classes and is a bit of a dumping ground.

Deploy Your Sample

Now I need a way to get this MOF file to all my computers. The easiest way is to return to Group Policy Preferences; create a GPP policy that copies the file and creates a scheduled task to run MOFCOMP at every boot up (you can change this scheduling later or even turn it off, once you are confident all your computers have the new classes).

image

image

image

image

You can also install and compile the MOF manually, use psexec.exe, make it part of your standard OS image, deploy it using a software distribution system, or whatever. The example above is just that - an example.

Now that all your computers know about your new WMI class, you can create a group policy WMI filter that uses it. Here are a couple examples; note that I remembered to change the namespace from CIMv2 to DEFAULT!

image

image

image

You're in business with a system that, while not optimal, is certainly is far better than Win32_Product. It’s fast and lightweight, relatively easy to manage, and like all adequate solutions, designed not to make things worse in its efforts to make things different.

And another idea (updated 4/23)

AskDS contributor Fabian Müller had another idea that he uses with customers:

1. Define environment variables using GPP based on Registry Item-Level targeting filters or just deploy the variables during software installation phase, e.g. %IEversion%= 9

2. Use this environment variable in WMI filters like this: Root\CIMV2;SELECT VARIABLEVALUE FROM Win32_Environment WHERE NAME='IEversion' AND VARIABLEVALUE='9'

Disadvantage: First computer start or user logon will not pass the WMI filter since the ENV variable had to be created (if set by GPP). It would be better having this environment variable being created during softwareinstallation / deployment (or whatever software being deployed).

Advantage: The environment WMI query is very fast compared. And you can use it “multi-purpose”. For example, as part of CMD-based startup and logon scripts.

An aside

Software Installation policy is not designed to be an enterprise software management solution and neither are individual application self-update systems. SI works fine in a small business network as a "no frills" solution but doesn’t offer real monitoring or remediation, and requires too much of the administrator to manage. If you are using these because of the old "we only fix IT when it's broken" answer, one argument you might take to management is that you are broken and operating at great risk: you have no way to deploy non-Microsoft updates in a timely and reliable fashion.

Even though the free Windows Update and Windows Software Update Service support Windows, Office, SQL, and Exchange patching, it’s probably not enough; anyone with more than five minutes in the IT industry knows that all of your software should be receiving periodic security updates. Does anyone here still think it's safe to run Adobe, Oracle, or thousands of other vendor products without controlled, monitored, and managed patching? If your network doesn't have a real software patching system, it's like a building with no sprinklers or emergency exits: nothing to worry about… until there's a fire. You wouldn’t run computers without anti-virus protection, but the number of customers I speak to that have zero security patching strategy is very worrying.

It's not 1998 anymore, folks. A software and patch management system isn’t an option anymore if you have a business with more than a hundred computers; those days are done for everyone. Even for Apple, although they haven't realized it yet. We make System Center, but there are other vendors out there too, and I’d rather you bought a competing product than have no patch management at all.

Until next time,

- Ned "pragma-tism" Pyle

  • Don't know about everyone else, but the links in the first paragraph seem to be a bit off...

  • Crikey, yeah they are fubar. Me fix now.

  • That was the nuttiest Word doc freak out I have ever seen. It's like it shifted all my hyperlinks down by one from the original correct ones; I had to fix every one.

    Thanks Steve!

  • Looks good now...  I thought I was going nutty (or more so), or just needed some more caffeine!  :)

  • DOH!  I take that back, looks like you have more gremlins at the end of the article.  Time to submit a bug report to the Office Team!   :D

  • You can delete that last post...  I missread a link

  • I will leave it there as a warning to the others!!!

  • This is a great article! Thank you for writing it! I've not had to do anything as wonky as what you're describing thankfully, where I enjoyed it was the custom MOF. I've never seen that before and now must do some reading. But your example solves an issue that I've had for quite a while now. How to quickly return a list of 32 and 64bit software from a computer, without Win32_Product, because it's horrible. In my environment where there are over 200 applications installed on over 250 computers, doing a quick inventory on a given system is the exact opposite, and that's assuming it ever completes!

    Thanks again!

  • My pleasure, Jeffrey.

  • Nice! Always informative. MOF ant that easy and I shy away from it all the time because there always seems to be an easier answer unless you are just looking for some nice reporting.

    Happy to see da post starting to roll in, keep it up.

  • A very useful article but "Win32reg_AddRemovePrograms...a legacy class...the System Center folks discarded it years ago". Is that strictly true? That class is still present in both 2007 and 2012 System Center Configuration Manager clients and is still collected as part of inventory. Your SampleProductsList class definition looks very similar to the Win32reg_AddRemovePrograms in Configuration.mof in the 2007 product. However, yes using that class alone does have its drawbacks when querying 32-bit software on 64-bit systems.

  • Including it for backwards compatibility doesn't mean they are using it. They wrote a native non-WMI inventory system years ago. And, yes, it looks similar on purpose - there's no other way it could look. :)

    I edited the main post slightly to make all this more clear, thanks for the feedback.

  • Thanks coderaven. :)

  • Thanks for getting the word out about Win32_Product. I've seen too many people use it without being aware of the consequences.

    In scripting, I use the WindowsInstaller.Installer object instead of Win32_Product. Its "Products" property returns all of the installed product IDs, which can be used to retrieve various properties for each product using the "ProductInfo" property. Want to know if Office 2010 Pro Plus is installed using VBScript?

    Set objInstaller = CreateObject("WindowsInstaller.Installer")

    Set colProducts = objInstaller.Products

    For Each strProduct In colProducts

    If objInstaller.ProductInfo(strProduct, "ProductName") = "Microsoft Office Professional Plus 2010" Then WScript.Echo "You got it!"

    Next

    msdn.microsoft.com/.../aa369767%28v=vs.85%29.aspx

  • Thanks for the confirmation of what we had seen in our environment caused, not by GPO, but by an in-house application.  There is also another good write-up about Win32_Product at gregramsey.wordpress.com/.../win32_product-is-evil