The Pickiness with PowerShell Philters
Take a look at a few favorite PowerShell cmdlets and you'll notice that more than a few of them have a -filter parameter. There's also the Where-Object cmdlet, which filters items out of the pipeline. You might think that these filtering elements would all work consistently... sadly, you'd be wrong, wrong, wrong.
October 25, 2010
Take a look at a few favorite PowerShell cmdlets and you'll notice that more than a few of them have a -filter parameter. There's also the Where-Object cmdlet, which filters items out of the pipeline. You might think that these filtering elements would all work consistently... sadly, you'd be wrong, wrong, wrong.
Start with Where-Object: It's -filter parameter is technically -filterScript, and it accepts a script block. That's any executable PowerShell command or expression, enclosed in {braces}, that results in a $True or $False:
Get-Service | Where { $_.Status -eq 'Running' }
Within that script block, PowerShell will replace the $_ placeholder with the current pipeline object. The script block is executed once for each piped-in object, and objects whose script results in a $True are piped onto the next cmdlet in the pipeline.
But look at Get-WmiObject: It's -filter parameter accepts a string, and it uses more traditional (non-PowerShell) comparison operators:
Get-WmiObject -class Win32_LogicalDisk -filter "drivetype=3"
That's because most cmdlets that have a -filter parameter, including Get-WmiObject, are actually just passing the filter to whatever is really executing the command. In this case, the filter is passed as a literal string to the WMI service, so the filter is in the syntax accepted by that service (technically, it's called the WMI Query Language, or WQL). It's too bad that PowerShell's creators didn't write the command to accept a script block, and then simply translate that to WQL before passing the filter to WMI. Then you could do this:
Get-WmiObject -class Win32_LogicalDisk -filter { drivetype -eq 3 }
Which would at least be consistent with Where-Object. But then take Get-ADUser, part of Windows Server 2008 R2's ActiveDirectory module. Its -filter parameter does take a PowerShell-style-seeming filter:
Get-ADUser -filter { cn -like 'd*' }
Under the hood, that's doubtless being translated to some LDAP syntax, but it's nice that it's doing the work. Weirdly, you can also provide the filter as a literal string (which makes less sense to me, since there's clearly translation done either way):
Get-ADUser -filter "cn -like 'd*'"
It's like the folks building this cmdlet thought, "well, the filtering stuff is inconsistent, so we'll just be consistent with everything." You can even use either style of quotes:
Get-ADUser -filter 'cn -like "d*"'
Which should cover all bases, I guess. This is likely just an area where the PowerShell team never thought to write out any formal guidance, and so cmdlet authors kind of went and did their own thing. It's too bad, but it's also fixable: It's possible for those cmdlet authors to retrofit a more standardized filtering mechanism without breaking what they're already doing. Is that something you'd like to see?
About the Author
You May Also Like