PowerShell / PSScriptAnalyzer

Download ScriptAnalyzer from PowerShellGallery
https://www.powershellgallery.com/packages/PSScriptAnalyzer/
MIT License
1.84k stars 372 forks source link

AvoidReservedCharInCmdlet throws System.NullReferenceException sometimes due to CommandInfo.ResolveParameter issue #1538

Closed LaurentDardenne closed 10 months ago

LaurentDardenne commented 4 years ago

I report this error although I cannot reproduce the bug, moreover the analyzed code is private :-/

The exception is random during a build via PSake. I already had this error with the previous version 1.8. The exception is most often raised when I open a powershell session and then execute my build script. When, after the triggering of the error, I relaunch my error script, I no longer have an error

I have not yet had time to run only the PSSA command line.

Actual behavior

[STA] E:\Projets\xxxx> $error[0]|select *

PSMessageDetails      :
Exception             : System.NullReferenceException: Object reference not set to an instance of an object.
                           at System.Management.Automation.CommandInfo.ResolveParameter(String name)
                           at Microsoft.Windows.PowerShell.ScriptAnalyzer.Helper.GetExportedFunction(Ast ast)
                           at Microsoft.Windows.PowerShell.ScriptAnalyzer.BuiltinRules.AvoidReservedCharInCmdlet.<AnalyzeScript>d__0.MoveNext()
                           at System.Collections.Generic.List`1..ctor(IEnumerable`1 collection)
                           at System.Linq.Enumerable.ToList[TSource](IEnumerable`1 source)
                           at Microsoft.Windows.PowerShell.ScriptAnalyzer.ScriptAnalyzer.<>c__DisplayClass83_1.<Analyze
                        SyntaxTree>b__2()
TargetObject          : E:\RELEASES\xxx\yyyy\Modules\Log4Posh\Log4Posh.psm1
CategoryInfo          : InvalidOperation: (E:\RELEASES\xxx…\Log4Posh.psm1:String) [Invoke-ScriptAnalyzer],
                        NullReferenceException
FullyQualifiedErrorId : RULE_ERROR,Microsoft.Windows.PowerShell.ScriptAnalyzer.Commands.InvokeScriptAnalyzerCommand
ErrorDetails          :
InvocationInfo        : System.Management.Automation.InvocationInfo
ScriptStackTrace      : at <ScriptBlock>, E:\Projets\xxx\build.psake.ps1: line 154
                        at Invoke-Task, E:\...\Modules\psake\4.9.0\public\Invoke-Task.ps1: line 108
                        at Invoke-Task, E:\...\Modules\psake\4.9.0\public\Invoke-Task.ps1: line 84
                        at <ScriptBlock>, E:\...\Modules\psake\4.9.0\public\Invoke-psake.ps1: line 303
                        at ExecuteInBuildFileScope,
                        E:\...\Modules\psake\4.9.0\private\ExecuteInBuildFileScope.ps1: line 57
                        at Invoke-psake, E:\...\Modules\psake\4.9.0\public\Invoke-psake.ps1: line 258
                        at <ScriptBlock>, E:\Projets\xxx\build.ps1: line 14
                        at <ScriptBlock>, <No file>: line 1
PipelineIterationInfo : {}

--OR

PSMessageDetails      :
Exception             : System.NullReferenceException: Object reference not set to an instance of an object.
                           at System.Management.Automation.CommandInfo.ResolveParameter(String name)
                           at Microsoft.Windows.PowerShell.ScriptAnalyzer.Helper.GetExportedFunction(Ast ast)
                           at Microsoft.Windows.PowerShell.ScriptAnalyzer.BuiltinRules.AvoidReservedCharInCmdlet.<AnalyzeScript>d__0.MoveNext()
                           at System.Collections.Generic.List`1..ctor(IEnumerable`1 collection)
                           at System.Linq.Enumerable.ToList[TSource](IEnumerable`1 source)
                           at Microsoft.Windows.PowerShell.ScriptAnalyzer.ScriptAnalyzer.<>c__DisplayClass83_1.<Analyze
                        SyntaxTree>b__2()
TargetObject          : E:\RELEASES\XXX\Modules\YYY\YYY.psm1
CategoryInfo          : InvalidOperation: (E:\RELEASES\xxx...yyyy.psm1:String) [Invoke-ScriptAnalyzer],
                        NullReferenceException
FullyQualifiedErrorId : RULE_ERROR,Microsoft.Windows.PowerShell.ScriptAnalyzer.Commands.InvokeScriptAnalyzerCommand
ErrorDetails          :
InvocationInfo        : System.Management.Automation.InvocationInfo
ScriptStackTrace      : at <ScriptBlock>, E:\Projets\xxx\build.psake.ps1: line 154
                        at Invoke-Task, E:\SYSTOOLS\XXX\Modules\psake\4.9.0\public\Invoke-Task.ps1: line 108
                        at Invoke-Task, E:\SYSTOOLS\XXX\Modules\psake\4.9.0\public\Invoke-Task.ps1: line 84
                        at <ScriptBlock>, E:\SYSTOOLS\XXX\Modules\psake\4.9.0\public\Invoke-psake.ps1: line 303
                        at ExecuteInBuildFileScope,
                        E:\SYSTOOLS\XXX\Modules\psake\4.9.0\private\ExecuteInBuildFileScope.ps1: line 57
                        at Invoke-psake, E:\SYSTOOLS\XXX\Modules\psake\4.9.0\public\Invoke-psake.ps1: line 258
                        at <ScriptBlock>, E:\Projets\xxxs\build.ps1: line 14
                        at <ScriptBlock>, <No file>: line 1
PipelineIterationInfo : {}

The first three lines are always the same :


Exception             : System.NullReferenceException: Object reference not set to an instance of an object.
                           at System.Management.Automation.CommandInfo.ResolveParameter(String name)
                           at Microsoft.Windows.PowerShell.ScriptAnalyzer.Helper.GetExportedFunction(Ast ast)

The fourth concerns a rule name which can be different :

  at Microsoft.Windows.PowerShell.ScriptAnalyzer.BuiltinRules.AvoidReservedCharInCmdlet.<AnalyzeScript>d__0.MoveNext()

The TargetObject property points to a module of the project. The module may not have been modified for several days and may not trigger an error during the previous analysis (10 minutes ago)

Environment data

v5.1  Windows server 2012

> (Get-Module -ListAvailable PSScriptAnalyzer).Version | ForEach-Object { $_.ToString() }
Get-Module

ModuleType Version    Name                                ExportedCommands
---------- -------    ----                                ----------------
Manifest   3.1.0.0    Microsoft.PowerShell.Management     {Add-Computer, Add-Content, Checkpoint-Computer, Clear-Con...
Manifest   3.1.0.0    Microsoft.PowerShell.Utility        {Add-Member, Add-Type, Clear-Variable, Compare-Object, Con...
Script     1.0.0.0    posh-git                            {Add-PoshGitToProfile, Expand-GitCommand, Format-GitBranch...
Script     4.9.0      psake                               {Assert, Exec, FormatTaskName, Framework, Get-PSakeScriptT...
Script     2.0.2      PSReadline                          {Get-PSReadLineKeyHandler, Get-PSReadLineOption, Remove-PS...
Script     1.19.0     psscriptanalyzer                    {Get-ScriptAnalyzerRule, Invoke-Formatter, Invoke-ScriptAn...

Test without any error, performed after the error is triggered :

[STA] E:\Projets\XXXs> $error.Clear(); cls;1..20|% {.\build.ps1}

Command line :

$analysisResult = Invoke-ScriptAnalyzer -Path $ModuleOutDir -Settings $ScriptAnalyzerSettingsPath -Recurse -Verbose:($VerbosePreference -eq 'Continue')

#Setting file 
@{
    ExcludeRules = @(
        'PSAvoidGlobalVars', #Legacy
        'PSAvoidUsingWMICmdlet', #Legacy
        'PSAvoidUsingDeprecatedManifestFields',
        'PSMissingModuleManifestField',
        'PSUseToExportFieldsInManifest',
        'PSUseUsingScopeModifierInNewRunspaces',
        'PSReviewUnusedParameter'
    )

    # Check if the scripts uses cmdlets that are compatible PS 3.0,
    Rules = @{
        PSUseCompatibleCommands = @{
            # Turns the rule on
            Enable = $true

            # Lists the PowerShell platforms we want to check compatibility with
            TargetProfiles = @(
                #PowerShell Version 3.0 Operating System Windows Server 2012
                'win-8_x64_6.2.9200.0_3.0_x64_4.0.30319.42000_framework'
            )
        }
    }
}
rjmholt commented 4 years ago

Looks like the old CommandInfo off the pipeline thread race condition

bergmeister commented 4 years ago

We could apply something similar to PR #1523

rjmholt commented 4 years ago

The problem I see is that taking a CommandInfo object and accessing it off the original pipeline thread is always going to have this race condition. Even falling through the cache still presents the possibility of a race condition. The only safe way to manipulate these objects is to leave the pipeline on a dedicated thread and run delegates on it that copy the needed values over. I'm currently building something like this for PSES for other reasons, but it's not infeasible. Honestly though, this is a big reason why I think depending on PowerShell for linting here is an issue

SydneyhSmith commented 4 years ago

Thanks @LaurentDardenne could you please to run only the PSSA command line when you have the chance and let us know if you are able to reproduce this?

Looks like the issue may be coming from PowerShell here, still, PSSA should protect itself from these types of errors/better handle parameter binding especially since we expect PSSA to be backwards compatible...we may want to check for a throw as well here, alternatively this rule could not use the helper function at all

avezinaATastus commented 4 years ago

Hi,

I think I am having a very similar issue. When analyzing PSShouldProcess, I get the Object reference not set to an instance of an object. Exception :

@{Exception=System.NullReferenceException: Object reference not set to an instance of an object.
   at Microsoft.Windows.PowerShell.ScriptAnalyzer.BuiltinRules.UseShouldProcessCorrectly.TryGetShouldProcessValueFromAst(FunctionInfo functionInfo, Boolean& hasShouldProcessSet)
   at Microsoft.Windows.PowerShell.ScriptAnalyzer.BuiltinRules.UseShouldProcessCorrectly.SupportsShouldProcess(String cmdName)
   at Microsoft.Windows.PowerShell.ScriptAnalyzer.BuiltinRules.UseShouldProcessCorrectly.CheckForSupportShouldProcess()
   at Microsoft.Windows.PowerShell.ScriptAnalyzer.BuiltinRules.UseShouldProcessCorrectly.<AnalyzeScript>d__7.MoveNext()
   at System.Collections.Generic.List`1..ctor(IEnumerable`1 collection)
   at System.Linq.Enumerable.ToList[TSource](IEnumerable`1 source)
   at Microsoft.Windows.PowerShell.ScriptAnalyzer.ScriptAnalyzer.<>c__DisplayClass83_1.<AnalyzeSyntaxTree>b__2()}

I had no problem yesterday, but today, analyzing doesn't work.

I found that it is specifically the PSShouldProcess rule that makes it not work. If excluded, it pass.

None of my function uses ShouldProcess.

Environment : Windows 10 2004, PS 5.1

Get-Module 

ModuleType Version    Name                                ExportedCommands
---------- -------    ----                                ----------------
Script     2.0.11     BuildHelpers                        {Add-TestResultToAppveyor, Export-Metadata, Find-NugetPackage, Get-BuildEnvironment...}
Script     1.3.1      Configuration                       {Add-MetadataConverter, ConvertFrom-Metadata, ConvertTo-Metadata, Export-Configuration...}
Manifest   3.1.0.0    Microsoft.PowerShell.Management     {Add-Computer, Add-Content, Checkpoint-Computer, Clear-Content...}
Manifest   3.0.0.0    Microsoft.PowerShell.Security       {ConvertFrom-SecureString, ConvertTo-SecureString, Get-Acl, Get-AuthenticodeSignature...}
Manifest   3.1.0.0    Microsoft.PowerShell.Utility        {Add-Member, Add-Type, Clear-Variable, Compare-Object...}
Manifest   3.0.0.0    Microsoft.WSMan.Management          {Connect-WSMan, Disable-WSManCredSSP, Disconnect-WSMan, Enable-WSManCredSSP...}
Script     0.14.0     platyPS                             {Get-HelpPreview, Get-MarkdownMetadata, Merge-MarkdownHelp, New-ExternalHelp...}
Script     0.4.0      PowerShellBuild                     {Build-PSBuildMAMLHelp, Build-PSBuildMarkdown, Build-PSBuildModule, Build-PSBuildUpdatableHelp...}
Script     0.2.0      PowerShellEditorServices.Commands   {Clear-Host, ConvertFrom-ScriptExtent, ConvertTo-ScriptExtent, Find-Ast...}
Binary     0.2.0      PowerShellEditorServices.VSCode     {Close-VSCodeHtmlContentView, New-VSCodeHtmlContentView, Set-VSCodeHtmlContentView, Show-VSCodeHtmlContentView...}
Script     4.8.0      psake                               {Assert, Exec, FormatTaskName, Framework...}
Script     2.0.2      PSReadLine                          {Get-PSReadLineKeyHandler, Get-PSReadLineOption, Remove-PSReadLineKeyHandler, Set-PSReadLineKeyHandler...}
Script     1.19.0     PSScriptAnalyzer                    {Get-ScriptAnalyzerRule, Invoke-Formatter, Invoke-ScriptAnalyzer}

By the tag 'Consider 2.0', do you mean I should try 2.0 ? Since it is not on the PSGallery yet, how should I install it ? Thanks

rjmholt commented 4 years ago

@avezinaATastus that looks like a different issue in this method:

https://github.com/PowerShell/PSScriptAnalyzer/blob/d04c03907b4a4b675bcc3cec3a32cbf3c4ee2d64/Rules/UseShouldProcessCorrectly.cs#L344-L398

Please open a new issue

LaurentDardenne commented 4 years ago

@SydneyhSmith

Thanks @LaurentDardenne could you please to run only the PSSA command line when you have the chance and let us know if you are able to reproduce this?

Yes I can, but not before a few weeks.

rjmholt commented 4 years ago

By the tag 'Consider 2.0', do you mean I should try 2.0 ? Since it is not on the PSGallery yet, how should I install it ?

That tag means we're considering addressing this issue in the 2.0 version, which is still being worked on.

LaurentDardenne commented 4 years ago

@SydneyhSmith My code having evolved, it no longer causes an error via psake or on the command line. The only thing that differs on the first run is the scan time, but that's unrelated.

First run 
--------------------------------------------------
Build Time Report
--------------------------------------------------
Name               Duration
----               --------
Init               00:00:00.033
Clean              00:00:00.073
BeforeBuild        00:00:00.001
RemoveConditionnal 00:00:00.000
BeforeStageFiles   00:00:00.001
CoreStageFiles     00:00:00.292
TestBOM            00:00:05.819
TestLocalizedData  00:00:00.000
AfterStageFiles    00:00:00.001
StageFiles         00:00:00.001
Analyze            00:00:40.536        <-------
TestBOMAfterAll    00:00:09.232
AfterBuild         00:00:00.007
Build              00:00:00.001
Total:             00:00:56.163

Next :
-----------------------------------
Build Time Report
-----------------------------------
Name               Duration
----               --------
Init               00:00:00.003
Clean              00:00:00.159
BeforeBuild        00:00:00.002
RemoveConditionnal 00:00:00.000
BeforeStageFiles   00:00:00.001
CoreStageFiles     00:00:00.137
TestBOM            00:00:07.524
TestLocalizedData  00:00:00.000
AfterStageFiles    00:00:00.001
StageFiles         00:00:00.001
Analyze            00:00:01.004      <------
TestBOMAfterAll    00:00:14.883
AfterBuild         00:00:00.004
Build              00:00:00.001
Total:             00:00:23.749

The module was not installed via Install-Module but downloaded from the PS Gallery + 'XCopy'.

Pxtl commented 1 month ago

I have this bug in 1.22.0. Does anybody know what magical trick can be done to avoid it? It may be that, like OP, I have installed PSScriptAnalyzer in a local directory instead of just install-module and letting module-search handle it.