Tuesday, November 25, 2014

WMI Filter Performance in Group Policy Objects

Hi all.

This is a follow-up to my previous post on WMI Filter Performance. I was curious about whether these findings for different kinds of WMI queries would have a noteable impact on GPO processing performance.

TL;DR: WMI filters in GPOs benefit from proper queries. Never "select * from" anything, always "select name" or whatever key property your class has. This simple change can speed up WMI filter evaluation by up to 95%.

To verify, I created a GPO with a simple ADM setting and linked a WMI filter to it. Then I created 200 copies of my GPO (PoSh Copy-GPO) and linked them to a testing OU (PoSh New-GPLink) with inheritance blocked. Combined with the WMI filter that has 5 queries, this results in a 1000x evaluation of the query itself.

My OU looks something like that:


(...and so on up to 200)

And this is my WMI filter:


(Silly, I know - but sufficient...)

My reasons to do 200 GPOs and a 5x WMI filter:
  1. GPMC gets really sluggish when dealing with huge numbers of GPOs - and I wanted to be able to provide some screen shots
  2. You cannot link unlimited GPOs to an OU - the gPLink attribute is limited in its size
Now let's check how this "mess" performs. I enabled GPSVC debug logging and did a gpupdate /force /target:user on a virtual machine that was running build 9841, one CPU, 2 GB.



CPU load went straight up to 100%, and with all my 200 GPOs and 1000 WMI queries, I got the following start and end GPSVC.LOG entries:

GPSVC(3d8.e58) 15:37:54:512 ProcessGPO(User):  Searching
[...]

GPSVC(3d8.e58) 15:45:35:854 ProcessGPO(User):  Found extensions:  [{35378EAC-683F-11D2-A89A-00C04FBBCFA2}{D02B1F73-3407-48AE-BA88-E8213C6761F1}]

So this is a 07:41 evaluation time. Remarkable...


Then I simply changed my 5 WMI queries according to my findings that we should not select *, but the key property:



Ran gpupdate again and checked results:

GPSVC(3d8.cb0) 16:10:22:602 ProcessGPO(User):  Searching
[...]

GPSVC(3d8.cb0) 16:11:09:368 ProcessGPO(User):  Found extensions:  [{35378EAC-683F-11D2-A89A-00C04FBBCFA2}{D02B1F73-3407-48AE-BA88-E8213C6761F1}]

Evaluation time went down to 00:47 - compared to the above 07:41, that's an enormous performance gain.


I finally deleted the WMI filter to get the "basic" time needed for evaluation:

GPSVC(3d8.cb0) 16:14:41:336 ProcessGPO(User):  Searching
[...]

GPSVC(3d8.cb0) 16:14:54:383 ProcessGPO(User):  Found extensions:  [{35378EAC-683F-11D2-A89A-00C04FBBCFA2}{D02B1F73-3407-48AE-BA88-E8213C6761F1}]

That's 00:13 for evaluation without any filters.

In other words: Basic evaluation time for 200 GPOs is about 65 ms per GPO (200 GPOs, 13 Seconds). WMI query evaluation time with proper queries is about 34 ms per query (with Win32_Service). Using an improper query pushes this time up to 458 ms per query.

That said - check your filters. And do it NOW!

Sunday, November 09, 2014

WMI filter queries and thoughts on performance

Hi all again on this wonderful, warm and sunny November Sunday :-)

TL;DR: In WMI filters, always select the key property of the class you are querying instead of 'SELECT * FROM'. This can reduce evaluation time by up to 90 percent!


If you use WMI filters, you should care about performance. Each filter in fact does need some time to be evaluated, and to verify this, we can easily use PoSh with its Measure-Command and Get-WmiObject cmdlets. In my previous post about WMI filters I'm targeting for OS versions. Let's verify one of these filters and its performance. To minimize noise, I crafted a 1000x loop around Get-WmiObject.



As we see, this filter takes about 23 ms average to evaluate. That's not a great issue, but if we use a lot of WMI filters, it can degrade performance notably.

So far, this is not a new thing. But why I'm writing this post at all? I recently came across this post on WindowsNetworking.com that states: Do not use the * wildcard selector, but instead use selected properties. What that means in the above query: Replace * with BuildNumber. Let's see how it performs after this small change.

 

Notably, execution time went down from 23 ms to 15 ms!  

Select all properties: 23 ms
Select named property: 15 ms (-35%)

I was so excited about this 35% performance gain that I repeated this test with a lot of different classes and properties, and I also replaced the selected property with different other properties. One test was with a filter we use to target laptops:
select * from Win32_Battery
Let's verify how this one performs with the wildcard selection and with a distinct property.

 

This filter has no performance gain. Why? Because my test computer does not have a battery - the filter doesn't return any instances, so we cannot select any properties. But let's check another class - Win32_Service. I chose to filter for Name='winmgmt'.

 

Wow - things get weird! A dropdown from 118 ms to 15 ms, just by selecting a property instead of everything! This was so astonishing that I immediately repeated this test. This time, I chose to add a third query which selects DisplayName instead of Name.



The first two runs are almost identical to the above ones: 119 ms compared to 16 ms. The third run takes 103 ms which is quite slow. Seems logical - we are targeting Name='winmgmt', so WMI must have read the Name property already. In addition, Name is the key property of Win32_Service.

Select all properties: 119 ms
Select named property: 103 ms (-13%)
Select key property: 16 ms (-87%)

I verified the influence of the key property through a test with the following query:
SELECT DisplayName FROM Win32_Service WHERE DisplayName = 'Server'
This query took almost exactly the same amount of time as
SELECT DisplayName FROM Win32_Service WHERE Name = 'Server'
As soon as I do not select Name, but any other property, it takes about 100 ms instead of about 15 ms, regardless of the property I'm filtering for.
 
To finally proof the key property influence, the following test was done without selecting a distinct service, but simply all services. Again, one query selects *, one query selects Name and one query selects DisplayName.



The first query - not surprising - takes 126 ms which is almost equal to the above one. The second and third query clearly proof that selecting the key property of a class can improve query speed by about 50%.

Select all properties: 126 ms
Select named property: 106 ms (-16%)
Select key property: 47 ms (-63%)

To cross verify this for other classes, I did tests with Win32_CodecFile and with Win32_Environment (both have the key property Name).

With Win32_CodecFile, we see no difference. But that's ok - still selecting a distinct property instead of * is better, because performance at least doesn't degrade if we do so :-)




With Win32_Environment, we see little differences, but we see them. And they again proof that it is better to select any property instead of just '*', and that it is better to select the key property than any other one.



Select all properties: 23,6 ms
Select named property: 21,0 ms (-11%)
Select key property: 20,4 ms (-14%)

That's it for now, happy fast filtering :-)