Thursday, May 31, 2012

Inverting WMI filters

Hi out there in the net! Been some time since my last post, so here we go for an early summer edition. Enjoy the warm rain!

Some of you may have used WMI filtering for Group Policy Objects already. WMI filters are a smart method to target GPOs dynamically based on properties of the actual computer system.

But from time to time, a question arises:
How can I target a GPO to a system that has NOT property xyz?

This translates to “how can I invert the result of a WMI filter?”
Imagine the following scenario:

We have a Domain containing a bunch of Servers. Some of them are Citrix Terminal Servers. We want to deploy a GPO that is applied to  all Servers except the Terminal Servers.
Or imagine the following:

We want to deploy MSI packages via GPO, but only to Computers that do not have a given software installed (a given executable file is not present).
The following samples are derived from the first scenario, but I’m sure you’ll manage to implement them for different situations ;-)

What can we filter for?

As you may know, all Citrix Servers have a service running called “IMAService”, that’s responsible for keeping the TS Farm connected (shortly spoken, of course). So our  filter to target for TS Servers may look like this:
Select * from win32_service where name=”IMAService”

This filter evaluates to true on all TS Servers. But how to convert this to a filter that’s true on all other servers? Well, first shot:
Select * from win32_service where NOT name=”IMAService”

See the mistake? This filter matches on ANY service whose name is not “IMAService”, and sure this filter will be true on each and every system we have – even on the TS Servers it will be true.
What now?

Well – there’s Group Policy Preferences and Item Level Targeting, let’s have a look on that: We now will combine that with traditional WMI filtering.
This is how it works!

First, create a new Group Policy Object, navigate to Computer Configuration - Preferences – Windows Settings – Environment and create 2 items. Both define the same environment variable, but with a different value.

Please note that we define the variable “IsTerminalServer” with a value of either 1 or 0.
Then, edit both items, go to the “Common” tab, optionally check “Remove this item when it is no longer applied” (not required, but does not matter anyway),  and make sure to check “Item-level targeting”:

 Now click “Targeting” and in the ILT editor “New Item”  - “WMI Query”. Here’s the ILT filter for the first entry that sets our variable value to 1:

And here’s the filter for the second entry that sets our variable value to 0:

The only difference: The second filter has “Item Options” – “Is Not”, resulting in “does not return a value” in the filter expression you see.
Note: It’s even be possible to retrieve properties of the returned object and save them to (temporary) variables we could use in path or file name fields on the “General” tab… But we don’t need that feature right now.

Remark: In the second above mentioned scenario (targeting for the non-existence of a file), you wouldn’t use a WMI Query – there’s a filter for files already present. I recommend using the predefined filters whenever possible. In my experience, they are easy to use and perform very fast. WMI queries tend to be slow...
Here’s all about Item Level Targeting in detail:
And - unlike Windows in general - within GPP the fabulous "F1" key is always worth being pressed if you need more information...

Now link this new GPO to your Domain or any appropriate OU.

What do we have achieved yet?

Well – each Server that has the IMAService will receive the environment variable “IsTerminalServer” with a value of 1. All other Servers will receive the same variable with a value of 0. Half way done ;-)
Now create one or two WMI filters:

This filter evaluates to true if “IsTerminalServer” is present and contains “1”. The presence and content of the variable is controlled by our previously created GPO with GPP and ILT.

This filter evaluates to true if “IsTerminalServer” is present and contains “0”. The presence and content of the variable is controlled by our previously created GPO with GPP and ILT.
Here’s all about querying WMI  in detail:

And here’s all you can query WMI for:
(Most times, you will only use the Win32 classes anyway…)

Link the latter WMI filter to your GPO you want to target to all servers EXCEPT Terminal Servers, and you’re done. The only caveat with this procedure: The GPO using the WMI filter does not work on first boot, but on the second boot (at first boot, the GPP Environment has to be processed, but that happens after WMI filters have been evaluated, so our variable is missing at this very moment…). If you use the WMI filter in user GPOs, it will work immediately.
Cool, isn’t it?

Well, to be honest: The GPP online help suggests using environment variables as an intermediate mechanism when  complex ILT filters are required – build an environment variable based on a complex ILT filter and use this environment variable as a simple ILT filter in other GPP elements. But they forgot to mention the added value when using this with WMI filters.

Stay tuned, regards Martin