PSSA should have a new rule to check for properly used Process blocks
For some cases the formatter is changing code where it cannot run. Rules that trigger this are:
PSUseConsistentWhitespace.CheckParameterwhen$TruePSAvoidUsingCmdletAliaseswhen$True
The source script triggering this bug is not valid, however
- the
PSAvoidUsingCmdletAliases:pwshwill execute this with no errors (It runs normally, it never assigns$x) - the
CheckParameter: This code is broken,pwshwill not execute this
Possible Cause of PSAvoidUsingCmdletAliases
From the docs: If your function defines a
Begin,ProcessorEndblock, all of your code must reside inside those blocks. No code will be recognized outside the blocks if any of the blocks are defined.
I think the cause is the script reaches a statement that is not inside a begin/process/end block -- so it assumes the function is a non-pipeline function. In that context, process is not a keyword but an identifier. It replaces process with Get-Process (which would the correct behavior if it was a normal function)
Invoke-ScriptAnalyzer has the same behavior.
Potential fix for PSAvoidUsingCmdletAliases ?
- PSSA should have a rule to check for functions that have code outside
begin/process/endblocks. - Can the parser test if there are any
begin/process/endstatements, then treat it as a pipeline function? - Can the formatter abort if errors occur? (Right now there's no errors on mutation)
Steps to reproduce
$script = @' function Do-Stuff { $x = 2 Process { } } '@ $scriptFixed = @' function Do-Stuff { #$x = 2 Process { } } '@ $settings = @{ IncludeRules = @('PSUseCorrectCasing', 'PSUseConsistentIndentation') Rules = @{ PSAvoidUsingCmdletAliases = @{ Enable = $false } PSUseConsistentIndentation = @{ Enable = $true Kind = 'space' PipelineIndentation = 'IncreaseIndentationAfterEveryPipeline' IndentationSize = 4 } } } Invoke-Formatter -ScriptDefinition $script -Settings $settings Invoke-Formatter -ScriptDefinition $scriptFixed -Settings $settings
Expected behavior
Indent and replace aliases.
function Do-Stuff { $x = 2 Process { } } function Do-Stuff { #$x = 2 Process { } }
Actual behavior
Indent, and replaces keyword as if it was not in the keyword context.
function Do-Stuff { $x = 2 Get-Process { } } function Do-Stuff { #$x = 2 Process { } }
Another example not using pipeline functions
Steps to reproduce
$Original = @'
Function BadCode {
"stuff" | Format-CodeColor" 'ps1'
$InputList | ForEach-Object {
} | Select-Object -First 2
| Join-String -sep ", " -OutputPrefix 'Results: '
}
'@
$settings = @{
IncludeRules = @(
"PSUseConsistentWhitespace"
)
Rules = @{
PSUseConsistentWhitespace = @{
Enable = $True
CheckParameter = $false
}
}
}
$out1 = Invoke-Formatter -ScriptDefinition $Original -Settings $settings
$settings.rules.PSUseConsistentWhitespace.CheckParameter = $True
$out2 = Invoke-Formatter -ScriptDefinition $Original -Settings $settings
$out1
'+' * 30
$out2
if ($out1 -ne $out2) {
Write-Error 'formatting does not match'
}
Expected behavior 2
Give an error, or don't mutate code
Actual behavior 2
Function BadCode { "`nPS> Top | Bot | Se" -OutputPrefix 'Results: ' }
Environment data
>> $PSVersionTable | ft Name Value ---- ----- PSVersion 7.0.3 PSEdition Core GitCommitId 7.0.3 OS Microsoft Windows 10.0.19041 Platform Win32NT PSCompatibleVersions {1.0, 2.0, 3.0, 4.0…} PSRemotingProtocolVersion 2.3 SerializationVersion 1.1.0.1 WSManStackVersion 3.0 >> (Get-Module -ListAvailable PSScriptAnalyzer).Version | ForEach-Object { $_.ToString() } 1.19.1 >> $psEditor | select EditorServicesVersion EditorServicesVersion --------------------- 2.3.0.0
