PowerShell’s -EQ Operator: Reference Equality vs Value Equality

A question recently came up asking why the -eq operator doesn’t work for two different (but equal) SecureStrings.


 


By default, almost all environments (the .NET Framework included) test if two things are exactly the same – that they are stored in the same place in memory. This is called reference equality.


 


[D:\documents\WindowsPowerShell]


PS:14 > $test = Read-Host -AsSecureString


****


 


[D:\documents\WindowsPowerShell]


PS:15 > [Object]::ReferenceEquals($test, $test)


True


 


[D:\documents\WindowsPowerShell]


PS:16 > $test -eq $test


True


 


That’s not usually what people want, so each individual type of object is (optionally) responsible for supporting a value-based equality test. They do this by implementing interfaces (software contracts) called IComparable and / or IEquatable:


 


[D:\documents\WindowsPowerShell]


PS:17 > $string1 = “Test”


 


[D:\documents\WindowsPowerShell]


PS:18 > $string2 = “Test”


 


[D:\documents\WindowsPowerShell]


PS:19 > [Object]::ReferenceEquals($string1, $string2)


False


 


[D:\documents\WindowsPowerShell]


PS:20 > [String].GetInterfaces()


 


IsPublic IsSerial Name


——– ——– —-


True     False    IComparable


True     False    ICloneable


True     False    IConvertible


True     False    IComparable`1


True     False    IEnumerable`1


True     False    IEnumerable


True     False    IEquatable`1


 


[D:\documents\WindowsPowerShell]


PS:21 > $string1 -eq $string2


True


 


 


The implementors of the SecureString class have chosen to not implement these contracts, so PowerShell supports only reference equality on these types:


 


[D:\documents\WindowsPowerShell]


PS:30 > [System.Security.SecureString].GetInterfaces()


 


IsPublic IsSerial Name


——– ——– —-


True     False    IDisposable


 


[D:\documents\WindowsPowerShell]


PS:31 > $test1 = Read-Host -AsSecureString


****


 


[D:\documents\WindowsPowerShell]


PS:32 > $test2 = Read-Host -AsSecureString


****


 


[D:\documents\WindowsPowerShell]


PS:33 > $test1 -eq $test2


False


 

Leave a Reply