Repository navigation
Rule PSAvoidShouldContinueWithoutForce doesn't enforce correct use of the Force parameter #1308
Copy link
Copy link
Open
Labels
Description
Currently PSScriptAnalyzer shows a PSAvoidShouldContinueWithoutForce violation for any scripts using $PSCmdlet.ShouldContinue that do not include a $Force parameter.
However, once the parameter the violation is resolved; even if that parameter is never used elsewhere in the code.
Steps to reproduce
function Invoke-MVP {
[CmdletBinding(SupportsShouldProcess = $true)]
[OutputType('System.String')]
Param (
[Parameter()]
[switch]$Force # Including this parameter resolves the PSAvoidShouldContinueWithoutForce violation; even though we don't reference Force in the rest of the code
)
if ($PSCmdlet.ShouldContinue('Should I continue','Should I continue')) {
'I continued'
}
}
# ...
Invoke-ScriptAnalyzer -Path '.\Invoke-MVP.ps1'Expected behavior
A violation of rule PSAvoidShouldContinueWithoutForce should occur.
Actual behavior
The code is deemed free of violations.
Environment data
> $PSVersionTable
Name Value
---- -----
PSVersion 5.1.14409.1018
PSEdition Desktop
PSCompatibleVersions {1.0, 2.0, 3.0, 4.0...}
BuildVersion 10.0.14409.1018
CLRVersion 4.0.30319.42000
WSManStackVersion 3.0
PSRemotingProtocolVersion 2.3
SerializationVersion 1.1.0.1
> (Get-Module -ListAvailable PSScriptAnalyzer).Version | ForEach-Object { $_.ToString() }
1.18.1Reactions are currently unavailable
Activity
JohnLBevan commentedon Aug 10, 2019
Question: Does anyone have a preference on which line is flagged as in violation?
[CmdletBinding(SupportsShouldProcess = $true)][switch]$Force$PSCmdlet.ShouldContinue('Should I continue','Should I continue'))i.e. as it's the combination of these three, plus the lack of the use of the force parameter further on which cause the issue.
My instinct is to attach the violation to the
[CmdletBinding(SupportsShouldProcess = $true)]line, as this is the line the violation for not having theForceparameter is attached to, so remains consistent; but I can see how it could be argued other ways.JohnLBevan commentedon Aug 10, 2019
Note: All of the following scenarios should be deemed valid:
In theory the below is also valid... but I suspect this is considered bad practice so should be reported as a violation / up to the coder to hide this via a
SupressMessageAttributeattribute if they can justify going this route.Note: I wouldn't have it treat
$noToAll = $Forceas acceptable, since that's counter intuitive. If people wanted an option for defaulting that they'd be better of using a,$AvoidClobber/$NoForceoption; which is outside the scope of this rule.bergmeister commentedon Aug 15, 2019
I'd flag on
[CmdletBinding(SupportsShouldProcess)]. You're right that the correct usage can be hard to determine, I originally thought that we could simply check for the presence of the-Forceswitch but remembered only now that we already have theAvoidShouldContinueWithoutForcerule for that. Unless you've got some use cases where we know for sure that the usage is not correct, then we might need to close the issue if it is too hard to accurately make a decision of the usage...thomasrayner commentedon Aug 30, 2019
If you declare a parameter and then never use it, should you get a
UseDeclaredVarsMoreThanAssignmentsviolation (or something similar)? 🤔I know this is an issue about specifically using a
$Forceparam if you haveSupportsShouldProcess, but it made me wonder about the above.mattmcnabb commentedon Dec 8, 2019
That rule doesn't currently look at param blocks, but I think this is a good idea for a new rule. I have a POC of it that works so far but doesn't cover cases like
$PSBoundParameters. Does anyone else agree that this might be a good rule to implement? If so I'll take a stab at it.