Repository navigation
PSSA should have a new rule to check for properly used Process blocks #1571
Description
Activity
Meta: Should I have broken this into two issues? (I submitted on the wrong account)
Indent, and replaces keyword as if it was not in the keyword context.
This is behaving as expected.
PSAvoidUsingCmdletAliasesalso warns about and replaces implicitGet-prefix aliasing.In the example you give,
processis not parsed as a keyword. If you invoke your function, it will run theGet-Processcommand. PSScriptAnalyzer is doing its best to tell you this.Importantly, the PowerShell parser (the same one that parses your script on execution) is what makes this distinction before PSScriptAnalyzer does any processing. By the time the script gets to PSScriptAnalyzer, there's a large structural distinction between a
processblock and aprocesskeyword:PS> { >> process { } >> }.Ast Attributes : {} UsingStatements : {} ParamBlock : BeginBlock : ProcessBlock : process { } EndBlock : DynamicParamBlock : ScriptRequirements : Extent : { process { } } Parent : { process { } } PS> { >> write-host 'Hi' >> process { } >> }.Ast Attributes : {} UsingStatements : {} ParamBlock : BeginBlock : ProcessBlock : EndBlock : write-host 'Hi' process { } DynamicParamBlock : ScriptRequirements : Extent : { write-host 'Hi' process { } } Parent : { write-host 'Hi' process { } }In the first case, a
ScriptBlockAstobject is produced with aProcessBlockparameter populated. In the second case,ProcessBlockis null andEndBlockis now populated. So the structure of the AST has removed any ambiguity by the time PSScriptAnalyzer sees your script.You can see this in the absence of PSScriptAnalyzer by trying to define a function like this directly in PowerShell. When
processis used after other statements, it's parsed as a command name within the implicitendblock (in a function), so you see a runtime error message here fromGet-Process:PS> function Test >> { >> Write-Host "Hi" >> process { "Hi" } >> } PS> test Hi Get-Process: Line | 4 | process { "Hi" } | ~~~~~~~~ | Cannot evaluate parameter 'Name' because its argument is specified as a script block and there is no input. A script block cannot be evaluated without input.When
processcomes first, it defines aprocessblock, and the parser will error if naked statements also occur outside of blocks:PS> function Test >> { >> process { "Hi" } >> write-host "Hi" >> } ParserError: Line | 4 | write-host "Hi" | ~~~~~~~~~~ | unexpected token 'write-host', expected 'begin', 'process', 'end', or 'dynamicparam'.So the formatting here has not mutated your code to change its meaning; it still does the same thing as the original script you wrote.
A remaining question is whether it's worth investing in a rule to warn about using commands that shadow keywords like this.
Reacted by Jake Bolton- changed the title
[-]`PSAvoidUsingCmdletAliases` and `CheckParameter` damage code when code is outside process blocks[/-][+]PSSA should have a new rule to check for properly used Process blocks[/+]on Aug 18, 2020 Rob Holt (@rjmholt) This was resolved in #1638 . Do I need to do anything to close my ticket?
Metadata
Metadata
Assignees
Type
Projects
- StatusShow more project fieldsDone
For some cases the formatter is changing code where it cannot run. Rules that trigger this are:
PSUseConsistentWhitespace.CheckParameterwhen$TruePSAvoidUsingCmdletAliaseswhen$TrueThe source script triggering this bug is not valid, however
PSAvoidUsingCmdletAliases:pwshwill execute this with no errors (It runs normally, it never assigns$x)CheckParameter: This code is broken,pwshwill not execute thisPossible Cause of
PSAvoidUsingCmdletAliasesI think the cause is the script reaches a statement that is not inside a
begin/process/endblock -- so it assumes the function is a non-pipeline function. In that context,processis not a keyword but an identifier. It replacesprocesswithGet-Process(which would the correct behavior if it was a normal function)Invoke-ScriptAnalyzerhas the same behavior.Potential fix for
PSAvoidUsingCmdletAliases?begin/process/endblocks.begin/process/endstatements, then treat it as a pipeline function?Steps to reproduce
Expected behavior
Indent and replace aliases.
Actual behavior
Indent, and replaces keyword as if it was not in the keyword context.
Another example not using pipeline functions
Steps to reproduce
Expected behavior 2
Give an error, or don't mutate code
Actual behavior 2
Environment data