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
PSReviewUnusedParameter has false positive when using $MyInvocation.BoundParameters #1505
I don't see this as a false positive. You are not using the FooBar variable. All you do is check whether a certain parameter set is being used, which is different to using the parameter itself. You should be using $FooBar.IsPresent in your case.
Do you agree Jos Koelewijn (@Jawz84)?
You are not using the FooBar variable. All you do is check whether a certain parameter set is being used, which is different to using the parameter itself.
It is a switch, so I may never use that parameter and go with just parameterset name. You may wonder why would someone do this. Imagine a function that calls another function with bound parameter, like someone splat $PSBoundParameters to another function.
I think pssa is doing exactly what can be expected from a static analysis tool; warn for suspect situations. Because the scenario you describe can not be statically analyzed in Powershell, I think there is little that could be done. This is my humble opinion and I may be wrong.
@manigandan-jegannathan-developer I still don't understand why you cannot check the parameter directly, even when splatting with PSBoundParameters in a nested function. Please provide a full (but simple) example where using the parameter directly is not working as expected.
I appreaicte the effort on writing this rule, I am sure it would help many out there. I am trying to add my inputs so that we can improve this rule further.
About that PSBoundParameters, I did not actually test it, but this rule seems to be working fine when PSBoundParameters used, I mean it did not flag. But it flags if $MyInvocation.BoundParameters used ?
For example,
$sb = {
function Get-ContentUMyFunc {
<#
#>
[CmdletBinding()]
Param(
[Parameter()]
[string]
$Path
)
try{
$bp = $MyInvocation.BoundParameters
Get-Content @bp
} catch {
throw
}
}
}
# Invoke-ScriptAnalyzer -ScriptDefinition [scriptblock]$sb | ft -a
RuleName Severity ScriptName Line Message
-------- -------- ---------- ---- -------
PSReviewUnusedParameter Warning 9 The parameter 'Path' has been declared but not used.
I still don't understand why you cannot check the parameter directly
I can definitely use that parameter directly. I just wanted to note that it may flag when someone uses ParameterSetName (Also I do not see anything wrong in using ParameterSetName instead of Parameter). I feel its a false positive in my opinion. We can recommend Suppressing such violations, but I am afraid that would be a bad habit . We are suppressing a rule violation because of a bug in the rule.
Also I just happened to notice that it flags if the parameter is being used in different runspace.
$sb = {
function Test-PSReviewUnusedParameter {
<#
#>
[CmdletBinding()]
Param(
[Parameter(ParameterSetName = 'Foo')]
[string]
$FooBar
)
try{
Invoke-Command -Session $someSession -ScriptBlock {
$Using:FooBar
}
} catch {
throw
}
}
}
# Invoke-ScriptAnalyzer -ScriptDefinition [scriptblock]$sb | ft -a
RuleName Severity ScriptName Line Message
-------- -------- ---------- ---- -------
PSReviewUnusedParameter Warning 9 The parameter 'FooBar' has been declared but not used.
@manigandan-jegannathan-developer Aha, I see, if you use $PSBoundParameters directly instead of $MyInvocation.BoundParameters, then the rule is already setup to not warn. That's because of this code here: https://github.com/PowerShell/PSScriptAnalyzer/blob/master/Rules/ReviewUnusedParameter.cs#L49
That following line could probably be enhanced to include $MyInvocation.BoundParameters as well, I'd like to double check with another expert, whether using the property on $MyInvocation is equivalent in terms of scoping.
changed the title [-]PSReviewUnusedParameter has false positives[/-][+]PSReviewUnusedParameter has false positive when using $MyInvocation.BoundParameters[/+]on May 20, 2020
That following line could probably be enhanced to include $MyInvocation.BoundParameters as well, I'd like to double check with another expert, whether using the property on $MyInvocation is equivalent in terms of scoping.
I think pssa is doing exactly what can be expected from a static analysis tool; warn for suspect situations. Because the scenario you describe can not be statically analyzed in Powershell, I think there is little that could be done. This is my humble opinion and I may be wrong.
I would like to echo this sentiment. This doesn't necessarily mean that we shouldn't do something like turn off the rule when particular variables are used, but PowerShell leans heavily on dynamic features and I would prefer not to create the expectation that static analysis can do it all.
In this case, it seems reasonable that we would detect a common scenario like this and disengage the rule, although we should document cases where the rule gives up.
I would like to echo this sentiment. This doesn't necessarily mean that we shouldn't do something like turn off the rule when particular variables are used, but PowerShell leans heavily on dynamic features and I would prefer not to create the expectation that static analysis can do it all.
Yh, I agree, hence why I marked it as an enhancement instead of a bug. The enhancement is relatively easy, therefore it's also marked as up for grabs.
We should look into a generic solution/improvement to the scoping issue though around child scriptblocks from which a few rules suffer and is probably the number one user annoyance in terms of false positives.
Just look at the line that I linked before: https://github.com/PowerShell/PSScriptAnalyzer/blob/master/Rules/ReviewUnusedParameter.cs#L49
You could do a check if variableCount contains MyInvocation and if so, do another search on scriptBlockAst to get the VariableExpressionAst of MyInvocation out again and do a recursive .FindAll search on it to get its child element of type StringConstantExpressionAst out and check if it is BoundParameters.
The readme has instructions on local development setup here or alternatively you can just use Visual Studio Codespaces or the remote Containers feature in VS-Code that will set everything up to work out of the box. Once you're setup, just call ./build.ps1 and the built module will be in a local folder called out. Familiarity with C# development and AST is assumed, the ShowPSAst is quite useful to visualize the PowerShell AST. At the start of June, I will give a talk at the online and free PSConfEU 2020 where I will demo how to build/debug PSSA as well and you will be able to watch that video on-demand: https://powershell.one/psconfeu/psconf.eu-2020/about
do another search on scriptBlockAst to get the VariableExpressionAst of MyInvocation out again and do a recursive .FindAll search on it to get its child element of type StringConstantExpressionAst out and check if it is BoundParameters.
I am afraid whether that would work. BoundParameters is not a child element of MyInvocation (VariableExpressionAst). Its a member of andMemberExpressionAst, where the expression is VariableExpressionAst. Both of them are child elements of MemberExpressionAst. Can you tell me if I am missing anything here ? Also Show-Ast is really useful.
do another search on scriptBlockAst to get the VariableExpressionAst of MyInvocation out again and do a recursive .FindAll search on it to get its child element of type StringConstantExpressionAst out and check if it is BoundParameters.
I am afraid whether that would work. BoundParameters is not a child element of MyInvocation (VariableExpressionAst). Its a member of andMemberExpressionAst, where the expression is VariableExpressionAst. Both of them are child elements of MemberExpressionAst. Can you tell me if I am missing anything here ? Also Show-Ast is really useful.
Yh, you're right, it looked like a child to me first but is actually at the same level as VariableExpressionAst. I guess the best is to then search for VariableExpressionAst, get the parent MemberExpressionAst by using the .Parent property and from that element do something like a .FindAll(oneAst -> oneAst is StringConstantExpressionAst, searchNestedScriptBlocks: false) search to get the StringConstantExpressionAst that you could then check for the BoundParameters property. That's just a rough idea that should get you there. Have a look at the properties and methods of the individual Ast implementations (Intellisense or docs) that can sometimes be helpful in the AST search as well.
I have submitted a PR fixing this issue. It occurred to me that it should not flag $PScmdlet.MyInvocation.PSBoundParameters as well. So I made required changes to handle all three cases,
Activity
bergmeister commentedon May 20, 2020
I don't see this as a false positive. You are not using the
FooBarvariable. All you do is check whether a certain parameter set is being used, which is different to using the parameter itself. You should be using$FooBar.IsPresentin your case.Do you agree Jos Koelewijn (@Jawz84)?
jegannathanmaniganadan commentedon May 20, 2020
Hey Christoph Bergmeister (@bergmeister) , Hope you are doing good.
It is a switch, so I may never use that parameter and go with just parameterset name. You may wonder why would someone do this. Imagine a function that calls another function with bound parameter, like someone splat $PSBoundParameters to another function.
Matt White (@mattpwhite)
Jawz84 commentedon May 20, 2020
I think pssa is doing exactly what can be expected from a static analysis tool; warn for suspect situations. Because the scenario you describe can not be statically analyzed in Powershell, I think there is little that could be done. This is my humble opinion and I may be wrong.
bergmeister commentedon May 20, 2020
@manigandan-jegannathan-developer I still don't understand why you cannot check the parameter directly, even when splatting with
PSBoundParametersin a nested function. Please provide a full (but simple) example where using the parameter directly is not working as expected.jegannathanmaniganadan commentedon May 20, 2020
I appreaicte the effort on writing this rule, I am sure it would help many out there. I am trying to add my inputs so that we can improve this rule further.
About that
PSBoundParameters, I did not actually test it, but this rule seems to be working fine whenPSBoundParametersused, I mean it did not flag. But it flags if$MyInvocation.BoundParametersused ?For example,
I can definitely use that parameter directly. I just wanted to note that it may flag when someone uses
ParameterSetName(Also I do not see anything wrong in usingParameterSetNameinstead of Parameter). I feel its a false positive in my opinion. We can recommend Suppressing such violations, but I am afraid that would be a bad habit . We are suppressing a rule violation because of a bug in the rule.Also I just happened to notice that it flags if the parameter is being used in different runspace.
bergmeister commentedon May 20, 2020
@manigandan-jegannathan-developer Aha, I see, if you use
$PSBoundParametersdirectly instead of$MyInvocation.BoundParameters, then the rule is already setup to not warn. That's because of this code here: https://github.com/PowerShell/PSScriptAnalyzer/blob/master/Rules/ReviewUnusedParameter.cs#L49That following line could probably be enhanced to include
$MyInvocation.BoundParametersas well, I'd like to double check with another expert, whether using the property on$MyInvocationis equivalent in terms of scoping.bergmeister commentedon May 20, 2020
I just checked with someone and
$MyInvocation.BoundParametersshould be equivalent to$PSBoundParameters, therefore, the following line should be enhanced to include this variable as well: https://github.com/PowerShell/PSScriptAnalyzer/blob/master/Rules/ReviewUnusedParameter.cs#L49[-]PSReviewUnusedParameter has false positives[/-][+]PSReviewUnusedParameter has false positive when using $MyInvocation.BoundParameters[/+]rjmholt commentedon May 20, 2020
James Truher (@JamesWTruher) do you know if this is the case?
I would like to echo this sentiment. This doesn't necessarily mean that we shouldn't do something like turn off the rule when particular variables are used, but PowerShell leans heavily on dynamic features and I would prefer not to create the expectation that static analysis can do it all.
In this case, it seems reasonable that we would detect a common scenario like this and disengage the rule, although we should document cases where the rule gives up.
bergmeister commentedon May 20, 2020
Yh, I agree, hence why I marked it as an enhancement instead of a bug. The enhancement is relatively easy, therefore it's also marked as up for grabs.
We should look into a generic solution/improvement to the scoping issue though around child scriptblocks from which a few rules suffer and is probably the number one user annoyance in terms of false positives.
jegannathanmaniganadan commentedon May 21, 2020
I can take this up, but I never made any contribution to PSSA. Any advise or sample PR fixing similar small issue would be helpful
bergmeister commentedon May 21, 2020
Just look at the line that I linked before: https://github.com/PowerShell/PSScriptAnalyzer/blob/master/Rules/ReviewUnusedParameter.cs#L49
You could do a check if
variableCountcontainsMyInvocationand if so, do another search onscriptBlockAstto get theVariableExpressionAstofMyInvocationout again and do a recursive.FindAllsearch on it to get its child element of typeStringConstantExpressionAstout and check if it isBoundParameters.The readme has instructions on local development setup here or alternatively you can just use Visual Studio Codespaces or the remote Containers feature in VS-Code that will set everything up to work out of the box. Once you're setup, just call
./build.ps1and the built module will be in a local folder calledout. Familiarity with C# development and AST is assumed, the ShowPSAst is quite useful to visualize the PowerShell AST. At the start of June, I will give a talk at the online and free PSConfEU 2020 where I will demo how to build/debug PSSA as well and you will be able to watch that video on-demand: https://powershell.one/psconfeu/psconf.eu-2020/aboutjegannathanmaniganadan commentedon May 21, 2020
Cool, Thanks. I will submit a PR. Thanks Christoph Bergmeister (@bergmeister)
jegannathanmaniganadan commentedon May 21, 2020
I am afraid whether that would work.
BoundParametersis not a child element ofMyInvocation(VariableExpressionAst). Its a member of andMemberExpressionAst, where the expression isVariableExpressionAst. Both of them are child elements ofMemberExpressionAst. Can you tell me if I am missing anything here ? AlsoShow-Astis really useful.bergmeister commentedon May 21, 2020
Yh, you're right, it looked like a child to me first but is actually at the same level as
VariableExpressionAst. I guess the best is to then search forVariableExpressionAst, get the parentMemberExpressionAstby using the.Parentproperty and from that element do something like a.FindAll(oneAst -> oneAst is StringConstantExpressionAst, searchNestedScriptBlocks: false)search to get theStringConstantExpressionAstthat you could then check for the BoundParameters property. That's just a rough idea that should get you there. Have a look at the properties and methods of the individual Ast implementations (Intellisense or docs) that can sometimes be helpful in the AST search as well.rjmholt commentedon May 22, 2020
{ param($x) $MyInvocation.BoundParameters }.Ast.FindAll({ $args[0] -is [System.Management.Automation.Language.MemberExpressionAst] -and $args[0].Expression -is [System.Management.Automation.Language.VariableExpressionAst] -and $args[0].Expression.VariablePath.UserPath -eq 'MyInvocation' -and $args[0].Member -is [System.Management.Automation.Language.StringConstantExpressionAst] -and $args[0].Member.Value -eq 'BoundParameters' }, $true)jegannathanmaniganadan commentedon May 22, 2020
Thanks Rob Holt (@rjmholt), that is exactly what I am doing.
jegannathanmaniganadan commentedon May 27, 2020
I have the changes ready, waiting for my firm to approve my OSS contribution.
jegannathanmaniganadan commentedon Jun 11, 2020
I have submitted a PR fixing this issue. It occurred to me that it should not flag $PScmdlet.MyInvocation.PSBoundParameters as well. So I made required changes to handle all three cases,