PowerShell: Filtering Left Could Produce Different Results Than Filtering with Where-Object

While doing some testing on my Windows 8 machine today, I discovered an issue where Filtering Left could produce different results than filtering with the Where-Object cmdlet.

Nothing special here. Just using the Get-Volume cmldet and filtering left with its DriveLetter parameter. Using either an upper or lowercase ‘C’ returns the same results:

Using the Where-Object cmdlet to do the filtering, while not a best practice when the filtering can be accomplished earlier in the pipeline, should return the same results or at least you would think it should. Using an upper case ‘C’ returns the same results, but using a lower case ‘c’ does not return any results:

Looking at both the datatype for the DriveLetter parameter (input) and the type of object that the DriveLetter property (output) produces shows they’re both [Char]. Based on this, I would expect what I’m inputing for the DriveLetter parameter and what the cmdlet is producing for its output to the pipeline for the DriveLetter property which is used for input by the Where-Object cmdlet to work consistently.

I’m not a developer and  a quick search on the Internet didn’t clear up whether the [Char] data type in PowerShell is case sensitive or not. So it was time for a quick test to check:

I defined a new variable named $charTest that is a [Char] datatype. I verified what it contained, tested it against upper and lower case both of which returned True, tested it against another value which returned False, and finally verified that it was an object type of [Char] to to make sure it was the right data type. Based on this test, it doesn’t appear that a [Char] datatype in PowerShell is case sensitive.

Update:
This appears to be an issue with the new PowerShell version 3 syntax for the Where-Object cmdlet which I was using in the previous examples. Using the older PowerShell version 2 syntax for the Where-Object cmdlet returns the correct results:

Be sure to read my next blog where I followed up on this issue and discovered it doesn’t occur on two other Windows 8 machines that I tested it on. This is a very strange issue. Also be sure to read Peter Kriegel’s comment on this blog article (I forgot all about implicit conversions of data types).

µ

2 Comments

  1. pamkkkkk

    This problem is as old as programming is!
    And even the solutions are even old as the hills.
    But you question how PowerShell tread this is interesting!

    Your example is doing Wrong! You are comparing a Char with a String!
    ‘C’ | Get-Member # results in String !!!!!!
    So internally the Char is converted to a String and the String comparer is Working.
    Please Read for the PowerShell type-conversion algorithm the very good Book from Bruce Payette! :
    http://www.manning.com/payette2/
    [excerpt]
    Anything [string] The PowerShell internal string converter is used.
    [/excerpt]

    But even on my Systems (PowerShell 2.0 and 3.0 on Win7) with the correct Char compare, Char seems not to be case sensitive!
    [Char]’c’ –eq [Char]’C’ # results in $True

    If you have a type of Char, think of it as a (integer) Number (Ascii Code)! In most languages Char is treated as a Byte (8 Bit) value or if you have Unicode like PowerShell as a Type of Single (16 Bit) value.
    [Int][Char]’c’# results in 99
    [Int][Char]’C’# results in 67
    So the best way to think of a Chare compare is to think it is a Number compare!

    But this is not for PowerShell as we seen!
    I think PowerShell converts a Char internally to a String and uses the String comparer!?
    But the Where-Object seems to have a different behavior!
    You found a PowerShell Pitfall!

    To get always around this pitfall, use the following solutions:

    1. If you compare Strings use the Tolower() or ToUpper() on both sides of the compare (or ToUpper())!
    “HeLLo”.ToLower() –eq “hello” # results in $True!
    Tipp: You can Cast the Char to a String like that ([String]’C’).Tolower()

    2. Instead of using the accurate comparer use the Like Operator! This works even for Chars!
    [char]’c’ -like [char]’C’ # results in $True!

    So this must even result in $True (cant test it have no Win8):
    Get-Volume | where DriveLetter -Like ‘c’

    Hope it is understandable

    Peter Kriegel
    http://www.admin-source.de

    Reply

Leave a Reply

%d bloggers like this: