Description
Overview
I was able to successfully suppress the violation of PSUseSingularNouns for two functions within a script using the SuppressMessageAttribute
. But a third function will not suppress even with the presence of the SuppressMessageAttribute
.
Steps to reproduce
-
Use a PSScriptAnalyzer configuration file with the following contents:
@{ Severity = @('Warning', 'Error') IncludeRules = @('PSUseSingularNouns') }
-
Use the following contents for a script file to be analyzed with PSScriptAnalyzer.
# SUCCESS: The rule flags this, but there's explicit code looking for the word 'data' and such a # violation is suppressed. However, without the SuppressMessageAttribute, this function is flagged by # PSScriptAnalyzer v1.21.0 function Get-QueueMessageMetadata { [Diagnostics.CodeAnalysis.SuppressMessageAttribute('PSUseSingularNouns', '')] [CmdletBinding()] Param ( <# Doesn't matter #> ) Begin { } } # SUCCESS: The rule flags this, but the SuppressMessageAttribute successfully suppresses a diagnostic # from being returned. function Start-EmptyQueuesAndStopServices { [CmdletBinding()] [Diagnostics.CodeAanalysis.SuppressMessageAttribute('PSUseSingularNouns', '')] Param ( <# Doesn't matter #> ) Begin { } } # ALWAYS FLAGS: I tried four variations of using SuppressMessageAttribute and it WILL NOT suppress! #[Diagnostics.CodeAnalysis.SuppressMessageAttribute('PSUseSingularNouns', '', Target='Get-QueuesWithMessages')] #[Diagnostics.CodeAnalysis.SuppressMessageAttribute('PSUseSingularNouns, '', Target='Get-QueuesWithMessages', Scope='Function')] #[Diagnostics.CodeAnalysis.SuppressMessageAttribute('PSUseSingularNouns, '', Target='Get-QueuesWithMessages', Scope='Script')] function Get-QueuesWithMesasges { #[Diagnostics.CodeAnalysis.SuppressMessageAttribute('PSUseSingularNouns', '', Target='Get-QueuesWithMessages')] [Diagnostics.CodeAnalysis.SuppressMessageAttribute('PSUseSingularNouns', '')] [CmdletBinding()] Begin { } }
-
PSScriptAnalyzer returns a violation of the PSUseSingularNouns rule for the last function in the script file above even though a suppression attribute exists. And of course, I tried several variations with no success.
It took me quite a while to spot this since I'm so familiar with the code I'm working on. But notice that the last function DOES NOT declare a Param ( )
block! Once I added an empty Param ( )
block, no more violations were reported.
I do not believe this is expected behavior because unless your function requires parameters (or simply, doesn't name them), none of my resources say that the Param ( )
block is required for advanced functions. Additionally, it looks like PowerShell may be parsing the SuppressMessageAttribute
as decorating the Begin { }
block instead of being a "decorator of" the enclosing function.
As an aside, it has always bothered me how attributes for functions are placed inside the function declaration, instead of directly above it as it's done in C#. So, if anything, it looks like a PowerShell parser ambiguity here. Does the attribute decorate the enclosing function, or the block within? Adding a Param ( )
block to the function, it would seem, resolves the parser ambiguity. I even tried putting the [CmdletBinding()]
attribute declaration below the SuppressMessageAttribute
declaration, but the unexpected behavior remains.
Now that I think about this, this issue probably does not belong on the PSScriptAnalyzer repo, but with the PowerShell repo, proper. Let me know if I should post this issue on that repository instead, as it's most likely that the PSScriptAnalyzer team can do anything to PSScriptAnalyzer to "fix" this.
Expected behavior
I expect that if my function does not need parameters, the Param ( )
block can be omitted and that the SuppressMessageAttribute
would still be associated with the function as it is for all other PowerShell functions so that the PSUseSingularNouns rule is suppressed on the affected function.
Actual behavior
PSScriptAnalyzer does not suppress this rule and emits a diagnostic record for the affected function. I suspect the attribute is not "decorating" the right block during parsing--being applied to the Begin { }
block rather than the enclosing function.
Environment data
> $PSVersionTable
Name Value
---- -----
PSVersion 7.4.0-preview.3
PSEdition Core
GitCommitId 7.4.0-preview.3
OS Microsoft Windows 10.0.19042
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.21.0