From 2e7dae1eb7af498837d07cdd57003118735ccfe6 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Wed, 28 Oct 2026 17:04:36 +0000 Subject: [PATCH 1/2] Initial plan From a54f0a29e63f97ed36332ec3a56897bfce1a0923 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Wed, 28 Oct 2026 17:09:18 +0000 Subject: [PATCH 2/2] Fix fallback DSC resource detection Co-authored-by: bergmeister <9250262+bergmeister@users.noreply.github.com> --- Rules/AvoidAlias.cs | 14 ++++++++---- Tests/Rules/AvoidUsingAlias.tests.ps1 | 31 +++++++++++++++++++++++++++ 2 files changed, 41 insertions(+), 4 deletions(-) diff --git a/Rules/AvoidAlias.cs b/Rules/AvoidAlias.cs index 087e6bfc8..ba069453b 100644 --- a/Rules/AvoidAlias.cs +++ b/Rules/AvoidAlias.cs @@ -207,7 +207,9 @@ private bool IsDscResourceDeclaration(CommandAst cmdAst) if (parent is FunctionDefinitionAst || parent is HashtableAst || parent is AssignmentStatementAst - || parent is ParenExpressionAst) + || parent is ParenExpressionAst + || parent is SubExpressionAst + || parent is ArrayExpressionAst) { return false; } @@ -228,7 +230,9 @@ private bool IsDscResourceDeclaration(CommandAst cmdAst) if (parent is FunctionDefinitionAst || parent is HashtableAst || parent is AssignmentStatementAst - || parent is ParenExpressionAst) + || parent is ParenExpressionAst + || parent is SubExpressionAst + || parent is ArrayExpressionAst) { return false; } @@ -305,14 +309,16 @@ private ScriptBlockExpressionAst GetDscResourceBody(CommandAst cmdAst) if (cmdAst.InvocationOperator != TokenKind.Unknown || cmdAst.CommandElements.Count < 2 || !(cmdAst.CommandElements[1] is ExpressionAst) - || cmdAst.CommandElements[1].Extent.Text == "=") + || cmdAst.CommandElements[1].Extent.Text == "=" + || cmdAst.Redirections.Count != 0) { return null; } if (!(cmdAst.Parent is PipelineAst commandPipeline) || commandPipeline.PipelineElements.Count != 1 - || commandPipeline.PipelineElements[0] != cmdAst) + || commandPipeline.PipelineElements[0] != cmdAst + || !(commandPipeline.Parent is NamedBlockAst || commandPipeline.Parent is StatementBlockAst)) { return null; } diff --git a/Tests/Rules/AvoidUsingAlias.tests.ps1 b/Tests/Rules/AvoidUsingAlias.tests.ps1 index 2f2614a40..2bdd55b33 100644 --- a/Tests/Rules/AvoidUsingAlias.tests.ps1 +++ b/Tests/Rules/AvoidUsingAlias.tests.ps1 @@ -201,6 +201,37 @@ Configuration PackageTest { $violations[5].Extent.Text | Should -Be 'Verb' $violations[6].Extent.Text | Should -Be 'gci' } + + It "does not mistake executable pipelines for DSC resources in fallback configuration ASTs" { + $target = @' +{ + Write-Output $(Verb Argument {}) + @(Verb Argument {}) + Verb Argument {} > $null + if (Verb Argument {}) {} + return Verb Argument {} + if ($true) { + Verb SameLineResource {} + Verb NextLineResource + { + } + } +} +'@ + $ast = [System.Management.Automation.Language.Parser]::ParseInput($target, [ref]$null, [ref]$null) + $body = $ast.EndBlock.Statements[0].PipelineElements[0].Expression.Copy() + $configuration = [System.Management.Automation.Language.ConfigurationDefinitionAst]::new( + $ast.Extent, $body, 'Resource', + [System.Management.Automation.Language.StringConstantExpressionAst]::new($ast.Extent, 'Test', 'BareWord')) + $rule = [Microsoft.Windows.PowerShell.ScriptAnalyzer.BuiltinRules.AvoidAlias]::new() + + $violations = @($rule.AnalyzeScript($configuration, $null)) + + $violations.Count | Should -Be 5 + $violations | ForEach-Object { + $_.SuggestedCorrections[0].Text | Should -Be 'Get-Verb' + } + } } Context "Settings file provides allowlist" {