WMI queries in powershell 'Invalid query'

3.9k Views Asked by At

Trying to learn more about WMI and powershell(noob) commands.

Running this:

Get-WMIObject -Namespace root\Subscription -Class __FilterToConsumerBinding

Gets me this(fine):

__GENUS                 : 2
__CLASS                 : __FilterToConsumerBinding
__SUPERCLASS            : __IndicationRelated
__DYNASTY               : __SystemClass
__RELPATH               : __FilterToConsumerBinding.Consumer="NTEventLogEventConsumer.Name=\"SCM Event Log Consumer\"",Filter="__EventFilter.Name=\"SCM Event Log Filter\""
__PROPERTY_COUNT        : 7
__DERIVATION            : {__IndicationRelated, __SystemClass}
__SERVER                : COMPUTERNAME
__NAMESPACE             : ROOT\Subscription
__PATH                  : \COMPUTERNAME\ROOT\Subscription:__FilterToConsumerBinding.Consumer="NTEventLogEventConsumer.Name=\"SCM Event Log Consumer\"",Filter="__EventFilter.Name=\"SCM Event Log Filter\""
Consumer                : NTEventLogEventConsumer.Name="SCM Event Log Consumer"
CreatorSID              : {1, 2, 0, 0...}
DeliverSynchronously    : False
DeliveryQoS             : 
Filter                  : __EventFilter.Name="SCM Event Log Filter"
MaintainSecurityContext : False
SlowDownProviders       : False
PSComputerName          : COMPUTERNAME

Why does this query give me the same result as above:

Get-WMIObject -Namespace root\Subscription -Class __FilterToConsumerBinding -Filter "__PATH LIKE '%SCM%'"

But this one, looking for the text in 'Filter' :

Get-WMIObject -Namespace root\Subscription -Class __FilterToConsumerBinding -Filter "Filter LIKE '%SCM%'"`

gives me an invalid query error

    Get-WMIObject : Invalid query "select * from __FilterToConsumerBinding where Filter LIKE '%SCM%'"
    At line:1 char:1
    + Get-WMIObject -Namespace root\Subscription -Class __FilterToConsumerB ...
    + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
        + CategoryInfo          : InvalidArgument: (:) [Get-WmiObject], ManagementException
        + FullyQualifiedErrorId : GetWMIManagementException,Microsoft.PowerShell.Commands.GetWmiObjectCommand

I don't get it why doesn't the same query work on both objects? Thanks!

Doesn't work on EventConsumer either but it does work on EventFilter!

Get-WMIObject -Namespace root\Subscription -Class __EventFilter -Filter "Name LIKE '%SCM%'"


__GENUS          : 2
__CLASS          : __EventFilter
__SUPERCLASS     : __IndicationRelated
__DYNASTY        : __SystemClass
__RELPATH        : __EventFilter.Name="SCM Event Log Filter"
__PROPERTY_COUNT : 6
__DERIVATION     : {__IndicationRelated, __SystemClass}
__SERVER         : COMPUTERNAME
__NAMESPACE      : ROOT\Subscription
__PATH           : \\COMPUTERNAME\ROOT\Subscription:__EventFilter.Name="SCM Event Log Filter"
CreatorSID       : {1, 2, 0, 0...}
EventAccess      : 
EventNamespace   : root\cimv2
Name             : SCM Event Log Filter
Query            : select * from MSFT_SCMEventLogEvent
QueryLanguage    : WQL
PSComputerName   : COMPUTERNAME
1

There are 1 best solutions below

2
On BEST ANSWER

Short answer... your ability to filter on a property depends on what kind of WMI Class it is and what the property types are.

Long answer... To get more information about a WMI class in PowerShell, use the Get-CimClass cmdlet. Properties can have different value types based on the data they return (ie String, Integers, Boolean). In your example, you are trying to query the property "Filter" which is a reference type. A reference type doesn't have a literal value, it is just a reference to an instance from another class. You can tell a reference property because it shows a full or partial path to another class (as you saw in your example "__EventFilter" was referenced. You can also get the property type information from this powershell command:

Get-CimClass -Namespace "root\Subscription" -Class __FilterToConsumerBinding | Select-Object -ExpandProperty CimClassProperties | Where-Object {$_.Name -eq 'Filter'}

Reference type properties show up on WMI classes that have a class qualifier called "Association" set to true. Class qualifiers are properties for the class itself that dictate how the class behaves. You can see all the class qualifiers using this command.

Get-CimClass -Namespace "root\Subscription" -Class __FilterToConsumerBinding | Select-Object -ExpandProperty CimClassQualifiers

Unfortunately, Since WQL is a query language you cannot filter instances of a class based on properties with a reference type using a WHERE clause. You can only use simple types such as a string, integer, or property of an embedded object (embedded objects are extremely rare though).

Since the class __EventFilter is whats referenced by the "Filter" property, and that class DOES has simple property types we can start from there. You can query __EventFilter by the Name property, which is a string type, without any problem.

There are some advanced query techniques (ASSOCIATORS OF and REFERENCES OF) that can help you get the instance from __FilterToConsumerBinding with queries based on references but its a multi-step process. I'd recommend checking out the Microsoft Doc on it Microsoft Doc WQL but here is a basic two step PowerShell command that will first get the name of the referenced instance then any instances that reference it.

$InstanceName = (Get-WmiObject -Namespace "ROOT\subscription" -Query "SELECT * FROM __EventFilter WHERE Name LIKE '%SCM%'").Name
Get-WmiObject -Namespace "ROOT\subscription" -Query "REFERENCES OF {__EventFilter.Name='$InstanceName'}"

Since REFERENCES OF will search an entire namespace you can narrow your results down to a specific class by adding a WHERE clause and naming the ResultClass as your target class. The revised second line of your command would now be

Get-WmiObject -Namespace "ROOT\subscription" -Query "REFERENCES OF {__EventFilter.Name='$InstanceName'} WHERE ResultClass = __FilterToConsumerBinding"

This should return the instance you are looking for only from __FilterToConsumerBinding. (*Note that there are no quotes around the class name. Including double or single quotes will give an invalid query error.

To answer your question about the __EventConsumer class, this brings up another WMI concept called abstract classes. I won't go into too much detail about this but an abstract class is essentially a base class (starting point for other classes) that other classes can inherit. Unlike standard base classes, though, abstract classes can not have its own instances. You can find out if a class is abstract by getting the class qualifiers of the __EventConsumer class. You'll notice if you run the command below, you will see it has the "abstract" class qualifier.

Get-CimClass -Namespace "root\Subscription" -Class __EventConsumer | Select-Object -ExpandProperty CimClassQualifiers

Since an abstract class can't contain any instances itself, if you enumerate it, it will return instances for all the classes that use it as a base class. In your example, __EventConsumer is actually yielding an instance from NTEventLogEventConsumer. Since enumerating an abstract class returns a number of different classes there would not always be the promise of the same properties to filter by so filtering is not allowed unless you are filtering on a property that is contained in the base class. To see what the base class of a WMI class is, you can use this command and see that the base class for NTEventLogEventConsumer is __EventConsumer.

Get-CimClass -Namespace "root\Subscription" -Class NTEventLogEventConsumer | Select-Object -ExpandProperty CimSuperClassName

You can usually enumerate all instances from an abstract class using the query SELECT * FROM __EventConsumer. This will show all instances but once you add a WHERE clause with a property not included in the base class, you either receive invalid query or no instances will be returned. This is the reason why you can directly query NTEventLogEventConsumer but not __EventConsumer.

Hope this helps.