@@ -296,6 +296,111 @@ function SuppressPasswordParam()
296296 # All violations should be suppressed since there's no RuleSuppressionID filtering
297297 $diagnostics | Should - HaveCount 0
298298 }
299+
300+ It " Should work with custom rule from issue #1686 comment" {
301+ # This test recreates the exact scenario from GitHub issue 1686 comment
302+ # with a custom rule that populates RuleSuppressionID for targeted suppression
303+
304+ # Custom rule module that creates violations with specific RuleSuppressionIDs
305+ $customRuleScript = @'
306+ function Measure-AvoidFooBarCommand {
307+ [CmdletBinding()]
308+ [OutputType([Microsoft.Windows.PowerShell.ScriptAnalyzer.Generic.DiagnosticRecord[]])]
309+ param(
310+ [Parameter(Mandatory)]
311+ [ValidateNotNullOrEmpty()]
312+ [System.Management.Automation.Language.ScriptBlockAst]
313+ $ScriptBlockAst
314+ )
315+
316+ $results = @()
317+
318+ # Find all command expressions
319+ $commandAsts = $ScriptBlockAst.FindAll({
320+ param($node)
321+ $node -is [System.Management.Automation.Language.CommandAst]
322+ }, $true)
323+
324+ foreach ($commandAst in $commandAsts) {
325+ $commandName = $commandAst.GetCommandName()
326+ if ($commandName -match '^(Get-FooBar|Set-FooBar)$') {
327+ # Create a diagnostic with the command name as RuleSuppressionID
328+ $result = [Microsoft.Windows.PowerShell.ScriptAnalyzer.Generic.DiagnosticRecord]::new(
329+ "Avoid using $commandName command",
330+ $commandAst.Extent,
331+ 'Measure-AvoidFooBarCommand',
332+ 'Warning',
333+ $null,
334+ $commandName # This becomes the RuleSuppressionID
335+ )
336+ $results += $result
337+ }
338+ }
339+
340+ return $results
341+ }
342+
343+ Export-ModuleMember -Function Measure-AvoidFooBarCommand
344+ '@
345+
346+ # Script that uses the custom rule with targeted suppression
347+ $scriptWithCustomRuleSuppression = @'
348+ [System.Diagnostics.CodeAnalysis.SuppressMessageAttribute('Measure-AvoidFooBarCommand', RuleSuppressionId = 'Get-FooBar', Scope = 'Function', Target = 'Allow-GetFooBar')]
349+ param()
350+
351+ function Test-BadCommands {
352+ Get-FooBar # Line 6 - Should NOT be suppressed (wrong function)
353+ Set-FooBar # Line 7 - Should NOT be suppressed (different RuleSuppressionID)
354+ }
355+
356+ function Allow-GetFooBar {
357+ Get-FooBar # Line 11 - Should be suppressed (matches RuleSuppressionId and Target)
358+ Set-FooBar # Line 12 - Should NOT be suppressed (different RuleSuppressionID)
359+ }
360+ '@
361+
362+ # Save custom rule to temporary file
363+ $customRuleFile = [System.IO.Path ]::GetTempFileName()
364+ $customRuleModuleFile = [System.IO.Path ]::ChangeExtension($customRuleFile , ' .psm1' )
365+ Set-Content - Path $customRuleModuleFile - Value $customRuleScript
366+
367+ try
368+ {
369+ # Check suppressed violations - this is the key test for our fix
370+ $suppressions = Invoke-ScriptAnalyzer `
371+ - ScriptDefinition $scriptWithCustomRuleSuppression `
372+ - CustomRulePath $customRuleModuleFile `
373+ - SuppressedOnly `
374+ - ErrorAction SilentlyContinue
375+
376+ # The core functionality: RuleSuppressionID with named arguments should work for custom rules
377+ # We should have at least one suppressed Get-FooBar violation
378+ $suppressions | Should -Not - BeNullOrEmpty - Because " RuleSuppressionID named arguments should work for custom rules"
379+
380+ $getFooBarSuppressions = $suppressions | Where-Object { $_.RuleSuppressionID -eq ' Get-FooBar' }
381+ $getFooBarSuppressions | Should -Not - BeNullOrEmpty - Because " Get-FooBar should be suppressed based on RuleSuppressionID"
382+
383+ # Verify the suppression occurred in the right function (Allow-GetFooBar)
384+ $getFooBarSuppressions | Should -Not - BeNullOrEmpty
385+ $getFooBarSuppressions [0 ].RuleName | Should - BeExactly ' Measure-AvoidFooBarCommand'
386+
387+ # Get unsuppressed violations to verify selective suppression
388+ $diagnostics = Invoke-ScriptAnalyzer `
389+ - ScriptDefinition $scriptWithCustomRuleSuppression `
390+ - CustomRulePath $customRuleModuleFile `
391+ - ErrorAction SilentlyContinue
392+
393+ # Should still have violations for Set-FooBar (different RuleSuppressionID) and Get-FooBar in wrong function
394+ $setFooBarViolations = $diagnostics | Where-Object { $_.RuleSuppressionID -eq ' Set-FooBar' }
395+ $setFooBarViolations | Should -Not - BeNullOrEmpty - Because " Set-FooBar should not be suppressed (different RuleSuppressionID)"
396+
397+ }
398+ finally
399+ {
400+ Remove-Item - Path $customRuleModuleFile - ErrorAction SilentlyContinue
401+ Remove-Item - Path $customRuleFile - ErrorAction SilentlyContinue
402+ }
403+ }
299404 }
300405
301406 Context " Rule suppression within DSC Configuration definition" {
0 commit comments