Skip to content

PSSA should have a new rule to check for properly used Process blocks #1571

Closed
@jbolton-corvalgroup

Description

@jbolton-corvalgroup

For some cases the formatter is changing code where it cannot run. Rules that trigger this are:

  • PSUseConsistentWhitespace.CheckParameter when $True
  • PSAvoidUsingCmdletAliases when $True

The source script triggering this bug is not valid, however

  • the PSAvoidUsingCmdletAliases: pwsh will execute this with no errors (It runs normally, it never assigns $x)
  • the CheckParameter: This code is broken, pwsh will not execute this

Possible Cause of PSAvoidUsingCmdletAliases

From the docs: If your function defines a Begin, Process or End block, 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.

image

Potential fix for PSAvoidUsingCmdletAliases ?

  • PSSA should have a rule to check for functions that have code outside begin/process/end blocks.
  • Can the parser test if there are any begin/process/end statements, 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

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions