Repository navigation
Description
Prerequisites
- Write a descriptive title.
- Make sure you are able to repro it on the latest released version
- Search the existing issues.
- Refer to the FAQ.
- Refer to Differences between Windows PowerShell 5.1 and PowerShell.
Steps to reproduce
This is a sub-issue of #25242.
The cmdlet Where-Object does not respect explicit $false values for any of its 31 operator switch parameters. This affects all comparison and logical operator switches.
Example with -EQ:
$data = @(
[PSCustomObject]@{ Name = 'Alice'; Age = 25 }
[PSCustomObject]@{ Name = 'Bob'; Age = 30 }
)
$result = $data | Where-Object Name -EQ:$false
$result.CountExample with -GT:
$result = $data | Where-Object Age -GT:$false
$result.CountExpected behavior
PS> $result = $data | Where-Object Name -EQ:$false
PS> $result.Count
2When -EQ:$false is specified, the -EQ operator should not be active. The cmdlet should fall back to default boolean evaluation of the property value, returning all objects where Name is truthy (non-empty strings).
Similarly for other operators, -[Operator]:$false should behave as if the operator switch was not specified at all.
Actual behavior
PS> $result = $data | Where-Object Name -EQ:$false
PS> $result.Count
0The -EQ:$false is incorrectly interpreted as -EQ $false, comparing the Name property against the boolean value $false instead of disabling the -EQ operator. This causes the filter to return no results because no Name values equal $false.
Affected parameters
All 31 operator switch parameters are affected:
| Category | Parameters |
|---|---|
| Equality | -EQ, -CEQ, -NE, -CNE |
| Comparison | -GT, -CGT, -GE, -CGE, -LT, -CLT, -LE, -CLE |
| Pattern | -Like, -CLike, -NotLike, -CNotLike, -Match, -CMatch, -NotMatch, -CNotMatch |
| Containment | -Contains, -CContains, -NotContains, -CNotContains, -In, -CIn, -NotIn, -CNotIn |
| Type | -Is, -IsNot |
| Logical | -Not |
Error details
No error is thrown. The cmdlet executes but misinterprets the explicit $false value as an operand rather than as a directive to disable the switch.
Environment data
PS> $PSVersionTable
Name Value
---- -----
PSVersion 7.5.4
PSEdition Core
GitCommitId 7.5.4
OS Microsoft Windows 10.0.26100
Platform Win32NT
PSCompatibleVersions {1.0, 2.0, 3.0, 4.0…}
PSRemotingProtocolVersion 2.3
SerializationVersion 1.1.0.1
WSManStackVersion 3.0Visuals
No response
Activity
TobiasPSP commentedon Nov 19, 2025
Parameters in the simplified syntax in
Where-Objectare supposed to mimick operator behavior.While this seems to fall into the typical bucket where parameters do not support
:, in this specific case I doubt the real relevance.What would be a practical use case where the current behavior exhibits a problem?
mklement0 commentedon Nov 19, 2025
Dr. Tobias Weltner (@TobiasPSP), please see the discussion in the associated PR, starting at #26485 (comment)
TobiasPSP commentedon Nov 20, 2025
Thank you.
The simplified syntax of Where-Object was intended to welcome beginners and shield them from the complexity of scriptblocks and $_.
For this significant benefit, it was accepted to pay the price: language inconsistency caused by „abusing“ parameters to mimick operators, leading to unintuitive coloring, unexpected casing, inconsistent tool tips, etc.
Even then, though, parameters like „-gt“ behaved consistently (like true operators), keeping the language predictable and intact.
If the ask is now to leverage the underlying (accidental) parameter nature, and enable negation via switch parameter syntax (which is not supported by true operators), this over-stretches the original idea and completely turns language consistency upside down. In return, the achieved benefit seems marginal, not justifying this impact (from a language design perspective).
The consistent approach would be to use the original scriptblock syntax for anything that is beyond a simple comparison.
Just my personal 2ct, not discussed yet in the WG.
mklement0 commentedon Nov 20, 2025
I agree that there's no strong need to tackle this and, as argued in the linked comment, I think it is unlikely that user will even try something like
-GT:$false, as it is currently the same as-GTand even with the proposed fix it wouldn't offer anything useful.What it comes down to is this:
What is the better behavior IF someone (misguidedly) actually tries
-GT:$false?(a) Currently, the
:$falsepart is effectively ignored.(b) With the proposed fix the behavior is as if
-GThadn't been specified at all.While we can only speculate as to what a hypothetical user trying
-GT:$falsemeant to happen, with (a) their use of:$falseis quietly ignored, which can cause confusion; with (b), assuming that a-Valueargument was also passed, they at least get an error (though the current wording requires that the fact that-GT:$falsewas in effect ignored has to be inferred).As a bonus, (b) is also consistent with how other cmdlets are being fixed with respect to negated switches (see #25242).
So it comes down to whether these - small - benefits are deemed worth having / worth the effort (though quite a bit of effort has already been expended).
iSazonov commentedon Nov 21, 2025
Dr. Tobias Weltner (@TobiasPSP) Should we wait WG re-approving or can continue?
iSazonov commentedon Nov 21, 2025
Since we change behavior I set these labels. Breaking change is under Bracket 3 (grey area).
TobiasPSP commentedon Nov 21, 2025
If it was approved then all is fine :-)