You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
Treat -Switch:$false the same as omitting a switch when selecting a parameter set #25027
In short: What this issue proposes is to treat -Switch:$false as if -Switch had not been specified, as these two forms should generally be equivalent, with the former often being used for programmatically building arguments, especially via splatting.
Indeed, checking $Switch.IsPresent yields $false in both cases (for thoughts about the naming of this property, see this comment).
Currently, -SomeSwitch:$false acts the same as passing -SomeSwitch (i.e., implied :$true) in terms of parameter-set selection, which causes all cmdlets that only check whether the relevant parameter set was selected to in effect ignore the $false argument.
MartinGC94's analysis here shows that quite a few existing cmdlets misbehave in this way, and the proposal at hand would presumably automatically fix that.
It is debatable whether this proposal should be considered a feature request or a bug report.
Either way, it is technically a breaking change, but - given the counterintuitive behavior and the presumed rarity of passing negated switches (-SomeSwitch:$false), it hopefully falls into bucket 3
In the vast majority of cases, omitting-SomeSwitch and passing -SomeSwitch:$false (which is the only way to emulate omitting the switch when splatting is used, short of conditionally constructing the splatting hashtable iteratively) should be considered equivalent.
(In edge cases, where -SomeSwitch:$false is designed to override a default value set elsewhere, notably via a preference variable (e.g., -Confirm:$false overriding the $ConfirmPreference variable), a different approach is already necessary, namely if, in addition to $Switch.IsPresent returning $false (which is the case when -Switch:$false is passed), whether this "non-presence" was explicitly signaled via a -Switch:$false argument rather than being implied by omission.)
To illustrate the problem:
functionfoo {
[CmdletBinding(DefaultParameterSetName='NoSwitchSet')]
param(
[Parameter(ParameterSetName='SwitchSet')]
[switch] $Switch
)
[pscustomobject] @{
SwitchValue=$SwitchParameterSetName=$PSCmdlet.ParameterSetName
}
}
# Invocation without -Switch
foo
# Invocation with negated -Switch, which _should_ be equivalent.
foo -Switch:$false# Ditto, via splatting$splat=@{ Switch=$false }
foo @splat
The main conversation point from the prior issue is what does -switch:$false mean semantically? Do the negative of the switch behavior or omit the switch behavior?
For example, how should this be determined semantically?
Format-OutString -italic:$true "italicize me in the console"
Format-OutString -italic:$false "normalize me in the console"
Does -italic:$false mean:
"DO send the ascii escape sequence for formatting reset" (negative behavior)
"DON'T send the ascii escape sequence for mandating italics" (omitting behavior)
Majority of the time, the omission and negative of a switch are the same behavior, but as highlighted in the previous discussions, this may not always be the case. This can be reflected in my example. Both behaviors should result in a non-itacized string, but achieve it through 2 different modes (or behaviors)
My personal take:
However, despite the arguments brought up against it, I think that making -switch:$false follow an omission behavior is much more valuable, because of 2 things:
Like OP stated, this could help resolve parameter sets more accurately
Why would you want to use -switch:$false as a negating behavior when things like -noSwitch,-stopSwitch, or -unSwitch are shorter and require less typing?
The only reason I can see -switch:$false being useful as a negating behavior is when a variable can be used to determine the switching behavior: -switch:$Condition.
However, if you are designing your functions to accept boolean values, why would it not be more appropriate to just use a boolean?
If you are designing your function to accept both a boolean or a switch, why not just use 2 parameters: -switchForConditionA -booleanForConditionA $true/$false?
Ultimately, that's up to each cmdlet to decide, and this proposal is unrelated to this aspect (except that the implementation of this logic may have to change if any current implementation relies on inferring the -italic:$false case from the selected parameter set - such cases, which are limited to cmdlets where the switch in question is a mandatory part of a parameter set - would have to be the subject of a bucket-3 analysis).
That said, to me such extended semantics are best avoided (-Confirm:$false is a rare example among built-in functionality), given that the behavior is obscure and that you'll need to memorize / consult the help to find out which cmdlets apply which logic.
Taking the Get-UpTime -Since:$false call as an example (but it applies analogously to probably most of the similarly broken cmdlets): there is no meaningful interpretation other than to consider it the same as Get-UpTime (i.e. without an argument).
This interpretation is currently not met - i.e. the call is broken, due to ignoring the $false value - owing to the justifiable but currently mistaken assumption that selecting the relevant parameter set implies that the switch value is $true
Therefore, making this assumption hold, as proposed here, implicitly fixes all cmdlets that currently mistakenly rely on it.
Why would you want to use -switch:$false
As stated in the initial post, this is about constructing arguments programmatically - whether with or without splatting.
Yes, you can avoid the problem with additional conditionals (have two variations of the same command line / conditionally add a splatting-hashtable entry after the fact only if the switch is to be passed) - but that is a maintenance headache / an annoying inconvenience.
why would it not be more appropriate to just use a boolean?
[bool] parameters, while technically supported, are best avoided - users don't expect them; they're used to the switch-parameter idiom, which makes for a unified way to represent opt-in behavior. Mixing these two idioms is likely to create confusion.
I'm unclear on how your comment relates to my previous one.
(In case you're thinking that the -switch:$false case cannot be detected in the absence of the selected parameter set implying its having been specified: (a) it can, and (b) note that a switch parameter need not be (and often isn't) a mandatory part of a distinct parameter set.)
What I'm saying is that a ParameterSet is primarily dictated by what is set and used, not by the value.
So if you use -switch, regardless of false or true, switchset is selected.
What you are asking for is to set/use a [switch] value, but make the parameterset believe it wasn't.
This issue might fall under, "you can't have your cake and eat it too." (Observe both omitting and negating behavior)
Plus, say pwsh did allow for this, this would just confuse developers. Is -switch:$false supposed to be negating, omitting, or both? Or maybe there's no consistency (which is possibly a burden on both the end-user and the developer)?
So if you use -switch, regardless of false or true, switchset is selected.
That's the de facto behavior - and this proposal aims to change it.
Conceptualizing -switch:$false as omitting-switch is straightforward, and matches the design intent of splatting / programmatic construction of an argument with -switch:$valueThatMayBeTrueorFalse.
As noted, implementing this change will make countless bugs go away that currently - justifiably, but mistakenly - assume that the parameter set only gets selected if the switch value is, in effect, $true (whether via -switch (typically) or via -switch:$true (programmatically)), and will also prevent future bugs of the same kind.
And, yes, that makes [switch] parameters special - they always have been.
"you can't have your cake and eat it too."
Yes, you can. But I advise against it, precisely for the potential for confusion, as I've previously noted, and as you seem to agree.
In short:
Make -switch:$false the same as omitting-switch for the purposes of parameter-set selection - a simple rule that not only matches what cmdlet authors likely expected, but also simplifies the implementation in the typical use case, where no additional logic needs to be superimposed on the -switch:$false case.
Due to the obscurity of such selective superimpositions, they are best avoided (though -Confirm:$false is a high-profile exception that won't go away). However, implementing this proposal does not prevent their implementation.
Using MartinGC94's code here as a starting point, I tested the 22 commands shipped with PS v7.6.0-preview.2 in Windows that use a mandatory switch parameter to dictate the selected parameter set.
The results indicate there are 8 commands that exhibit the problem described in this issue (FalseSwitchIgnored is True in the results above). That is, for those commands, reasonable user expectation is subverted when certain switch parameters are passed a $false value.
E.g., I suspect most PS users of any experience level would not expect the following to create a new Windows PowerShell session, yet that's precisely what happens.
# The *presence* of the switch selects UseWindowsPowerShellParameterSet.# Irrespective of the switch *value*, CreateRunspacesForUseWindowsPowerShellParameterSet() is called.New-PSSession-UseWindowsPowerShell:$false
The results above do not include:
Non-mandatory switch parameters. There are at least 2 other commands that exhibit the problem (see below).
Commands from modules shipped exclusively with Windows PowerShell (such as Get-WindowsPackage from Dism mentioned here).
Excluding common/optional common parameters, I count a total of 707 switch parameters in commands shipped with PS v7.6.0.
The effort to test the complete set would obviously be considerable, but I did pick out ~40 (not included in the results above) for manual testing. Of those ~40, I found one new instance in which an explicit $false value is ignored: New-Guid -Empty:$false, which brings the total to 10known problematic commands (including Get-Uptime from #25015).
Summary
Instances in which an explicit $false value passed to a mandatory switch parameter is not respected:
I suspect the total number of affected commands in the wild is very large.
From the perspective of a command author, defining multiple, mutually exclusive switches, switching on ParameterSetName within the command body and modifying behaviour accordingly is extremely convenient, yet breaks down with splatting and -Param:$bool syntax. Reworking the switches into a single, enum/set-based parameter is the natural alternative, but is not always viable and requires knowledge of the problem discussed in this issue.
For that reason, I fully support a systematic change that reconciles the selected parameter set with explicitly $false switches.
In the meantime, the following issues asks to document the implications of this practice.
Also, with this proposal treating -NoQualifier:$false equivalent to not specifying -NoQualifier, parameter binding involving mutually exclusive switches will presumably be possible.
For example, the following currently results in an AmbiguousParameterSet parameter binding exception.
$params=@{
Qualifier=$trueNoQualifier=$false
}
Split-Path$PSHOME@params# Parameter set cannot be resolved using the specified named parameters. # One or more parameters issued cannot be used together or an insufficient number of parameters were provided.
Would this introduce a potential for bugs in cmdlets that use -switch:$false as a negating behavior? Are we just trading bugs?
That's a fair question.
As noted in the comment below, checking for -Switch:$false explicitly will still be possible, with a combination of $PSBoundParameters/InvocationInfo.BoundParameters and the value of $Switch/$Switch.IsPresent.
This issue proposes that -Switch:$false doesn't influence the selected parameter set, which means PSCmdlet.ParameterSetName won't reflect the parameter set that would otherwise have been selected.
In PowerShell code:
functionTest1 {
param ([Parameter(ParameterSetName='SwitchParam')] [switch] $SwitchParam)
# Note: !$SwitchParam and !$SwitchParam.IsPresent are equivalent. if ($PSCmdlet.ParameterSetName-eq'SwitchParam'-and!$SwitchParam) {
'Parameter Set: Switch explicitly False'
}
if ($PSBoundParameters.ContainsKey('SwitchParam') -and!$SwitchParam) {
'Bound Parameters: Switch explicitly False'
}
}
Test1 -SwitchParam:$false# Current behavior: # Parameter Set: Switch explicitly False# Bound Parameters: Switch explicitly False# With proposal:# Bound Parameters: Switch explicitly False
I skimmed through a naive GitHub search and didn't see any code that would be broken (no doubt this search could be improved).
Some results such as this resemble the function above, but the use case isn't the same and the proposal wouldn't affect anything.
Other results such as this would actually benefit from the proposal.
InvocationInfo.BoundParameters won't contain the switch.
It should, however, just as it does now - precisely so as to continue to support the (ill-advised) "negated switch" logic.
With that in mind, the only existing code that could be broken is code that checks for an explicitly specified negated switch inside an if ($PSCmdlet.ParameterSetName -eq 'SwitchParam')-like conditional, i.e. code that doesn't just check for $PSBoundParameters.ContainsKey('SwitchParam') -and !$SwitchParam irrespective of the selected parameter set.
To spell it out:
Add-Type-ReferencedAssemblies System.Management.Automation, System.Collections @' using System.Management.Automation; [Cmdlet("Get", "Foo")] [CmdletBinding(DefaultParameterSetName="Default")] public class GetFooCmdlet : PSCmdlet { [Parameter(ParameterSetName="Default")] public object Unused { get; set; } [Parameter(ParameterSetName="Bar", Mandatory=true)] public SwitchParameter Bar { get; set; } protected override void ProcessRecord() { WriteObject(this.ParameterSetName); WriteObject(this.MyInvocation.BoundParameters); } }'@-PassThru |% Assembly |Import-ModuleGet-Foo-Bar:$false
currently yields:
Bar # parameter set 'Bar' *was* selected
Key Value
--------
Bar False
with the proposed change implemented will yield:
Default# parameter set 'Bar' *was not* selected
Key Value
--------
Bar False
That certainly limits the extent of the breaking change drastically (which is in line with my findings from the earlier Test1 search).
Just to be clear, in the case of -Switch:$false, while the parameter will be bound, it won't influence the parameter set chosen thereafter. Or in other words, the parameter will be treated as if it doesn't have a defined parameter set and thus belongs to all parameter sets.
I've adjusted my previous comment to avoid potential confusion.
For whatever my opinion might be worth: I do agree with parsing -switch:$false as the same as -switch not being passed in context of parameter set selecting.
I cannot find a reason for, as general rule, a switch used to select a Parameter Set to be passed as $false and still select the parameter set.
I also bring to point the .IsPresent property of [switch] objects: as Michael Klement (@mklement0) noted elsewhere, it returns $false when the switch is set to $false, exactly like when there is no switch.
This compound confusion: using -switch:$false enables the relative Parameter Set, but if I check its presence with .IsPresent I get a $false.
Completely contradictory.
The Engine WG discussed this. While we agree the behavior can be confusing (and we agree in general that the idea of the negated switch has a lot of issues), we think special casing parameter set selection now would be potentially just as confusing (e.g. a value is clearly being sent, can be seen in bound parameters, yet parameter set selection is unaffected).
We also can't change it across the board due to the many commands that differentiate between the three states (not specified, present, and explicit false) including many built in commands.
we think special casing parameter set selection now would be potentially just as confusing
If framed as follows, there would be no confusion going forward:
-switch:$false is the same as omittingswitch, and therefore has no impact on parameter-set selection; the primary purpose of this syntax is to enable programmatic construction of parameter values (often indirectly, via hashtable-based splatting)
In edge cases, -switch:$false has different semantics, but this is best avoided in user code; a notable case is the common -Confirm parameter, where -Confirm:$false serves to override a preference variable (something that omitting-Confirm couldn't achieve).
Do not use this technique in your own code to implement tri-state logic, as it is both obscure and potentially confusing; the Strongly Encouraged Developer Guidelines suggest using a [Nullable[bool]] parameter instead ($true to set, $false to unset, $null to leave unchanged).
the many commands that differentiate between the three states
The proposal allows them to continue to do so (although, as suggested, no new code should use this approach).
The only existing code that would break are cases where such conceptually tri-state [switch] parameters are mandatory members of a parameter set and the state of the switch is evaluated inside a parameter set-specific conditional. (By contrast, for non-mandatory [switch] parameters , existing code must already explicitly check $PSBoundParameters in order to distinguish the -switch:$false case from the omission case, and that will continue to work.)
Given that the tri-state logic is presumably rare to begin with, the additional constraints likely make the affected cases even rarer, and that should be weighed against what currently broken calls the proposal would implicitly fix (see next point).
Conversely, as surfingoldelephant's analysis shows, implementing the proposal would likely implicitly fix many commands, as they were clearly - and justifiably - designed under the assumption that -switch:$false is indeed the same as omittingswitch.
The point that both myself and Patrick Meinecke (@SeeminglyScience) science are trying to make is that this may end up fixing many cmdlets at the cost of breaking many others.
So far only an analysis of what would be fixed has been proposed. So far no analysis has been provided accounting for what would be broken.
Blue Falcon (@anonhostpi), it's unclear to me how your comment relates to my previous one (in the sense of not adding anything that hasn't already been said and acknowledged), but there's no need to delve into that: I'm opting out of this conversation.
Reacted by Blue Falcon
microsoft-github-policy-service commented on Mar 13, 2025
Activity
similar-issues-ai commentedon Feb 15, 2025
We've found some similar issues:
If any of the above are duplicates, please consider closing this issue out and adding additional context in the original issue.
anonhostpi commentedon Feb 15, 2025
Prior discussions:
The main conversation point from the prior issue is what does
-switch:$falsemean semantically? Do the negative of the switch behavior or omit the switch behavior?For example, how should this be determined semantically?
Does
-italic:$falsemean:Majority of the time, the omission and negative of a switch are the same behavior, but as highlighted in the previous discussions, this may not always be the case. This can be reflected in my example. Both behaviors should result in a non-itacized string, but achieve it through 2 different modes (or behaviors)
My personal take:
However, despite the arguments brought up against it, I think that making
-switch:$falsefollow an omission behavior is much more valuable, because of 2 things:-switch:$falseas a negating behavior when things like-noSwitch,-stopSwitch, or-unSwitchare shorter and require less typing?The only reason I can see
-switch:$falsebeing useful as a negating behavior is when a variable can be used to determine the switching behavior:-switch:$Condition.However, if you are designing your functions to accept boolean values, why would it not be more appropriate to just use a boolean?
If you are designing your function to accept both a boolean or a switch, why not just use 2 parameters:
-switchForConditionA -booleanForConditionA $true/$false?anonhostpi commentedon Feb 15, 2025
This conversation gave me this idea: #25029
mklement0 commentedon Feb 15, 2025
Ultimately, that's up to each cmdlet to decide, and this proposal is unrelated to this aspect (except that the implementation of this logic may have to change if any current implementation relies on inferring the
-italic:$falsecase from the selected parameter set - such cases, which are limited to cmdlets where the switch in question is a mandatory part of a parameter set - would have to be the subject of a bucket-3 analysis).That said, to me such extended semantics are best avoided (
-Confirm:$falseis a rare example among built-in functionality), given that the behavior is obscure and that you'll need to memorize / consult the help to find out which cmdlets apply which logic.Taking the
Get-UpTime -Since:$falsecall as an example (but it applies analogously to probably most of the similarly broken cmdlets): there is no meaningful interpretation other than to consider it the same asGet-UpTime(i.e. without an argument).This interpretation is currently not met - i.e. the call is broken, due to ignoring the
$falsevalue - owing to the justifiable but currently mistaken assumption that selecting the relevant parameter set implies that the switch value is$trueTherefore, making this assumption hold, as proposed here, implicitly fixes all cmdlets that currently mistakenly rely on it.
As stated in the initial post, this is about constructing arguments programmatically - whether with or without splatting.
Yes, you can avoid the problem with additional conditionals (have two variations of the same command line / conditionally add a splatting-hashtable entry after the fact only if the switch is to be passed) - but that is a maintenance headache / an annoying inconvenience.
[bool]parameters, while technically supported, are best avoided - users don't expect them; they're used to the switch-parameter idiom, which makes for a unified way to represent opt-in behavior. Mixing these two idioms is likely to create confusion.anonhostpi commentedon Feb 15, 2025
What you propose is a contradictory behavior.
I want to set/use a switch, but I don't want the function to think it was set/used?
Additionally, switches can already be programmatically applied/omitted using splatting (which is part of why I proposed that new feature request)
mklement0 commentedon Feb 15, 2025
I'm unclear on how your comment relates to my previous one.
(In case you're thinking that the
-switch:$falsecase cannot be detected in the absence of the selected parameter set implying its having been specified: (a) it can, and (b) note that a switch parameter need not be (and often isn't) a mandatory part of a distinct parameter set.)anonhostpi commentedon Feb 15, 2025
What I'm saying is that a ParameterSet is primarily dictated by what is set and used, not by the value.
So if you use -switch, regardless of false or true, switchset is selected.
What you are asking for is to set/use a [switch] value, but make the parameterset believe it wasn't.
This issue might fall under, "you can't have your cake and eat it too." (Observe both omitting and negating behavior)
Plus, say pwsh did allow for this, this would just confuse developers. Is
-switch:$falsesupposed to be negating, omitting, or both? Or maybe there's no consistency (which is possibly a burden on both the end-user and the developer)?mklement0 commentedon Feb 16, 2025
That's the de facto behavior - and this proposal aims to change it.
Conceptualizing
-switch:$falseas omitting-switchis straightforward, and matches the design intent of splatting / programmatic construction of an argument with-switch:$valueThatMayBeTrueorFalse.As noted, implementing this change will make countless bugs go away that currently - justifiably, but mistakenly - assume that the parameter set only gets selected if the switch value is, in effect,
$true(whether via-switch(typically) or via-switch:$true(programmatically)), and will also prevent future bugs of the same kind.And, yes, that makes
[switch]parameters special - they always have been.Yes, you can. But I advise against it, precisely for the potential for confusion, as I've previously noted, and as you seem to agree.
In short:
Make
-switch:$falsethe same as omitting-switchfor the purposes of parameter-set selection - a simple rule that not only matches what cmdlet authors likely expected, but also simplifies the implementation in the typical use case, where no additional logic needs to be superimposed on the-switch:$falsecase.Due to the obscurity of such selective superimpositions, they are best avoided (though
-Confirm:$falseis a high-profile exception that won't go away). However, implementing this proposal does not prevent their implementation.surfingoldelephant commentedon Feb 16, 2025
Using MartinGC94's code here as a starting point, I tested the 22 commands shipped with PS v7.6.0-preview.2 in Windows that use a mandatory switch parameter to dictate the selected parameter set.
Modules shipped with PS v7.6.0
CimCmdletsMicrosoft.PowerShell.ArchiveMicrosoft.PowerShell.DiagnosticsMicrosoft.PowerShell.HostMicrosoft.PowerShell.ManagementMicrosoft.PowerShell.PSResourceGetMicrosoft.PowerShell.SecurityMicrosoft.PowerShell.UtilityMicrosoft.WSMan.ManagementPackageManagementPowerShellGetPSDiagnosticsPSReadLineThreadJobResults
The results indicate there are 8 commands that exhibit the problem described in this issue (
FalseSwitchIgnoredisTruein the results above). That is, for those commands, reasonable user expectation is subverted when certain switch parameters are passed a$falsevalue.E.g., I suspect most PS users of any experience level would not expect the following to create a new Windows PowerShell session, yet that's precisely what happens.
The results above do not include:
Get-WindowsPackagefromDismmentioned here).Excluding common/optional common parameters, I count a total of 707 switch parameters in commands shipped with PS v7.6.0.
Code
The effort to test the complete set would obviously be considerable, but I did pick out ~40 (not included in the results above) for manual testing. Of those ~40, I found one new instance in which an explicit
$falsevalue is ignored:New-Guid -Empty:$false, which brings the total to 10 known problematic commands (includingGet-Uptimefrom #25015).Summary
Instances in which an explicit
$falsevalue passed to a mandatory switch parameter is not respected:Get-Random -ShuffleGet-SecureRandom -ShuffleGet-TimeZone -ListAvailableNew-PSSession -UseWindowsPowerShellRegister-PSResourceRepository -PSGallerySplit-Path -Qualifier/-NoQualifier/-Leaf/-IsAbsolute(not-Extension/-LeafBase)Test-Connection -Repeat/-MtuSize/-TracerouteWhere-Object(all non-common switch parameters)Other known instances:
Get-Uptime -Since(seeGet-Uptime -Sinceignores an explicit$falsevalue #25015)New-Guid -EmptyRough test code
surfingoldelephant commentedon Feb 16, 2025
I suspect the total number of affected commands in the wild is very large.
From the perspective of a command author, defining multiple, mutually exclusive switches, switching on
ParameterSetNamewithin the command body and modifying behaviour accordingly is extremely convenient, yet breaks down with splatting and-Param:$boolsyntax. Reworking the switches into a single, enum/set-based parameter is the natural alternative, but is not always viable and requires knowledge of the problem discussed in this issue.For that reason, I fully support a systematic change that reconciles the selected parameter set with explicitly
$falseswitches.In the meantime, the following issues asks to document the implications of this practice.
Also, with this proposal treating
-NoQualifier:$falseequivalent to not specifying-NoQualifier, parameter binding involving mutually exclusive switches will presumably be possible.For example, the following currently results in an
AmbiguousParameterSetparameter binding exception.anonhostpi commentedon Feb 17, 2025
I know that this issue brings up bugs with the omitting behavior, but that just raises another question:
Would this introduce a potential for bugs in cmdlets that use
-switch:$falseas a negating behavior? Are we just trading bugs?We would also need a list of functions/cmdlets exist that expect
-switch:$falseto be negating instead of omitting.surfingoldelephant commentedon Feb 17, 2025
That's a fair question.
As noted in the comment below, checking for
-Switch:$falseexplicitly will still be possible, with a combination of$PSBoundParameters/InvocationInfo.BoundParametersand the value of$Switch/$Switch.IsPresent.This issue proposes that
-Switch:$falsedoesn't influence the selected parameter set, which meansPSCmdlet.ParameterSetNamewon't reflect the parameter set that would otherwise have been selected.In PowerShell code:
I skimmed through a naive GitHub search and didn't see any code that would be broken (no doubt this search could be improved).
mklement0 commentedon Feb 17, 2025
Thanks for digging deeper.
It should, however, just as it does now - precisely so as to continue to support the (ill-advised) "negated switch" logic.
With that in mind, the only existing code that could be broken is code that checks for an explicitly specified negated switch inside an
if ($PSCmdlet.ParameterSetName -eq 'SwitchParam')-like conditional, i.e. code that doesn't just check for$PSBoundParameters.ContainsKey('SwitchParam') -and !$SwitchParamirrespective of the selected parameter set.To spell it out:
currently yields:
with the proposed change implemented will yield:
surfingoldelephant commentedon Feb 17, 2025
That certainly limits the extent of the breaking change drastically (which is in line with my findings from the earlier
Test1search).Just to be clear, in the case of
-Switch:$false, while the parameter will be bound, it won't influence the parameter set chosen thereafter. Or in other words, the parameter will be treated as if it doesn't have a defined parameter set and thus belongs to all parameter sets.I've adjusted my previous comment to avoid potential confusion.
sirtao commentedon Mar 6, 2025
For whatever my opinion might be worth: I do agree with parsing
-switch:$falseas the same as-switchnot being passed in context of parameter set selecting.I cannot find a reason for, as general rule, a switch used to select a Parameter Set to be passed as
$falseand still select the parameter set.I also bring to point the
.IsPresentproperty of[switch]objects: as Michael Klement (@mklement0) noted elsewhere, it returns$falsewhen the switch is set to$false, exactly like when there is no switch.This compound confusion: using
-switch:$falseenables the relative Parameter Set, but if I check its presence with.IsPresentI get a $false.Completely contradictory.
SeeminglyScience commentedon Mar 10, 2025
The Engine WG discussed this. While we agree the behavior can be confusing (and we agree in general that the idea of the negated switch has a lot of issues), we think special casing parameter set selection now would be potentially just as confusing (e.g. a value is clearly being sent, can be seen in bound parameters, yet parameter set selection is unaffected).
We also can't change it across the board due to the many commands that differentiate between the three states (not specified, present, and explicit false) including many built in commands.
mklement0 commentedon Mar 10, 2025
To be clear:
If framed as follows, there would be no confusion going forward:
-switch:$falseis the same as omittingswitch, and therefore has no impact on parameter-set selection; the primary purpose of this syntax is to enable programmatic construction of parameter values (often indirectly, via hashtable-based splatting)In edge cases,
-switch:$falsehas different semantics, but this is best avoided in user code; a notable case is the common-Confirmparameter, where-Confirm:$falseserves to override a preference variable (something that omitting-Confirmcouldn't achieve).[Nullable[bool]]parameter instead ($trueto set,$falseto unset,$nullto leave unchanged).The proposal allows them to continue to do so (although, as suggested, no new code should use this approach).
The only existing code that would break are cases where such conceptually tri-state
[switch]parameters are mandatory members of a parameter set and the state of the switch is evaluated inside a parameter set-specific conditional. (By contrast, for non-mandatory[switch]parameters , existing code must already explicitly check$PSBoundParametersin order to distinguish the-switch:$falsecase from the omission case, and that will continue to work.)Given that the tri-state logic is presumably rare to begin with, the additional constraints likely make the affected cases even rarer, and that should be weighed against what currently broken calls the proposal would implicitly fix (see next point).
Conversely, as surfingoldelephant's analysis shows, implementing the proposal would likely implicitly fix many commands, as they were clearly - and justifiably - designed under the assumption that
-switch:$falseis indeed the same as omittingswitch.anonhostpi commentedon Mar 10, 2025
The point that both myself and Patrick Meinecke (@SeeminglyScience) science are trying to make is that this may end up fixing many cmdlets at the cost of breaking many others.
So far only an analysis of what would be fixed has been proposed. So far no analysis has been provided accounting for what would be broken.
mklement0 commentedon Mar 11, 2025
Blue Falcon (@anonhostpi), the following reasons have been laid out:
This sounds like a classic bucket 3 candidate to me, yet it is fair to ask for more analysis re (a).
However, doing so is moot:
The reason for my posting another analysis after the decision was made is twofold:
(a) Getting clarity on an issue is always worthwhile, even if it has no effect on the issue at hand - it may inform future decisions.
(b) Secondarily, one can always hope that a decision will be revisited.
anonhostpi commentedon Mar 11, 2025
By analysis, I meant quantitative. No quantitative analysis has been provided proving that no cmdlets would be broken
"The absence of evidence is not the evidence of absence" - Gin Rummy, The Boondocks
mklement0 commentedon Mar 11, 2025
Blue Falcon (@anonhostpi), it's unclear to me how your comment relates to my previous one (in the sense of not adding anything that hasn't already been said and acknowledged), but there's no need to delve into that: I'm opting out of this conversation.
microsoft-github-policy-service commentedon Mar 13, 2025
This issue has been marked as won't fix and has not had any activity for 1 day. It has been closed for housekeeping purposes.
microsoft-github-policy-service commentedon Mar 13, 2025
📣 Hey Michael Klement (@mklement0), how did we do? We would love to hear your feedback with the link below! 🗣️
🔗 https://aka.ms/PSRepoFeedback