Correct handling of explicit -[Operator]:$false parameter values in Where-Object#26485
Conversation
|
Such using (-GT:$false now throw) looks weird :-) @mklement0 What do you think? |
There was a problem hiding this comment.
Pull Request Overview
This PR fixes the handling of explicit :$false parameter values for comparison operators in Where-Object. When a switch parameter operator is explicitly set to $false (e.g., -GT:$false), the cmdlet should fall back to default boolean property evaluation instead of using that operator.
Key changes:
- Added
if (value)guards to all 33 operator parameter setters inWhereObjectCommandto prevent operator assignment when explicitly set to$false - Added comprehensive test coverage for the
:$falsebehavior across multiple operators - Tests verify both the boolean evaluation fallback and the error handling when
:$falseis used with-Value
Reviewed Changes
Copilot reviewed 2 out of 2 changed files in this pull request and generated no comments.
| File | Description |
|---|---|
| src/System.Management.Automation/engine/InternalCommands.cs | Added conditional guards to all operator property setters (EQ, NE, GT, LT, Like, Match, Contains, In, Is, Not, and their case-sensitive variants) to only apply operators when explicitly set to $true |
| test/powershell/Modules/Microsoft.PowerShell.Core/Where-Object.Tests.ps1 | Added new test context with 11 tests covering :$false behavior for representative operators and error cases when combined with -Value parameter |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
It does. The awkwardness comes from the fact that what are semantically operators are - of technical necessity - implemented as However, it is consistent with the other fixes of the negated-switch problem to treat In the case of these operator switches, this has the following implications for those representing binary operators, using the example of
I'd say that, unlike with more typical It may make sense with In short: While users are unlikely to run into this scenario, resolving it in a manner consistent with the other negated-switch fixes makes sense to me. @yotsuda, as an aside:
The current, problematic inability to make the input object itself (rather than one of its properties) the target of the evaluation has been discussed before: |
|
Thank you @mklement0 for the thorough analysis and for confirming the consistency with other negated-switch fixes! I appreciate the pointer to #8357 regarding the -Property limitation. |
|
@mklement0 Thanks! I think it is a breaking change - brucket 3 (unlikely grey area) @yotsuda Please add this in the PR description.
|
test/powershell/Modules/Microsoft.PowerShell.Core/Where-Object.Tests.ps1
Outdated
Show resolved
Hide resolved
|
|
||
| It "-GT:$false should behave like default boolean evaluation" { | ||
| # With -GT:False, the parameter is not specified, so default boolean evaluation applies | ||
| $result = $testData | Where-Object Age -GT:$false |
There was a problem hiding this comment.
@yotsuda It seems -LT is skipped. Please re-check that we have test for all operators.
There was a problem hiding this comment.
Thank you for pointing this out. I've added the missing tests for all case-insensitive operators in 357e79c:
- -LT:$false
- -NE:$false
- -GE:$false
- -LE:$false
- -NotLike:$false
- -NotMatch:$false
- -NotContains:$false
- -NotIn:$false
- -IsNot:$false
Also fixed the escaping of $false in test names and the Context title for consistent display.
All 17 case-insensitive operators are now covered. I didn't add tests for the case-sensitive variants (-CEQ, -CGT, -CLT, etc.) since they share the same setter logic in the property implementations. Should I add those as well for completeness?
There was a problem hiding this comment.
It would be nice to cover all code paths.
There was a problem hiding this comment.
Thank you! I've added tests for all 14 case-sensitive operators (CEQ, CNE, CGT, CLT, CGE, CLE, CLike, CNotLike, CMatch, CNotMatch, CContains, CNotContains, CIn, CNotIn) and additional error tests in 688b06c.
All 59 tests pass. This now covers all code paths for explicit :$false handling.
| It "-GT:$false with -Value should throw an error requiring an operator" { | ||
| # When a switch parameter is set to $false with -Value specified, | ||
| # it should throw an error because no valid operator is active | ||
| { $testData | Where-Object Age -GT:$false -Value 25 } | Should -Throw -ErrorId 'OperatorNotSpecified,Microsoft.PowerShell.Commands.WhereObjectCommand' |
There was a problem hiding this comment.
An operator is required to compare the two specified values. Include a valid operator in the command, and then try the command again. For example, Get-Process | Where-Object -Property Name -eq Idle
Hmm, formally it is not correct. @mklement0 Do you expect user's reports about this? It seems we need to update the error message.
There was a problem hiding this comment.
Yes, the operator is technically there, but conceptually it isn't, due to its negation.
Given that I expect very few users to even attempt this, I don't think it's worth addressing in the error message.
….Tests.ps1 Co-authored-by: Ilya <darpa@yandex.ru>
- Add tests for -LT, -NE, -GE, -LE, -NotLike, -NotMatch, -NotContains, -NotIn, -IsNot - Fix escaping of $false in test names for consistent display
There was a problem hiding this comment.
Pull Request Overview
Copilot reviewed 2 out of 2 changed files in this pull request and generated no new comments.
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
iSazonov
left a comment
There was a problem hiding this comment.
Although not all tests have been formally added (to cover everything), I believe they will not add value.
|
@mklement0 Thanks for help! |
PR Summary
Fix #26480
Fix incorrect behavior when switch parameters (comparison operators) are explicitly set to
$falseinWhere-Object.Breaking Change
This PR contains a breaking change categorized as Bucket 3: Unlikely Grey Area (ref: breaking-change-contract.md#bucket-3).
Previous behavior: When operator parameters (e.g.,
-Not,-EQ) were explicitly set to:$false, the cmdlet would still attempt to use that operator, leading to incorrect results.New behavior: When operator parameters are explicitly set to
:$false, the cmdlet correctly falls back to default boolean property evaluation (as if no operator was specified).Rationale: This corrects behavior in a subtle corner case that has no obvious utility. The previous behavior was unintuitive and likely not depended upon by existing scripts.
PR Context
When using
Where-Objectwith explicit:$falseon operator parameters (e.g.,-Not:$false,-EQ:$false), the cmdlet should fall back to default boolean property evaluation instead of using the specified operator.Before this fix:
After this fix:
PR Checklist