From a67f3474efa147cd6c8a4a8cf1ecfc8f1d78df19 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Wed, 28 Oct 2026 21:30:19 +0000 Subject: [PATCH 1/3] Initial plan From 18c85ec5e7c87bab6f426bb4e6f105a88923b37d Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Wed, 28 Oct 2026 21:34:22 +0000 Subject: [PATCH 2/3] Reject ampersand-separated DSC body pairing Co-authored-by: bergmeister <9250262+bergmeister@users.noreply.github.com> --- Rules/AvoidAlias.cs | 8 ++++---- Tests/Rules/AvoidUsingAlias.tests.ps1 | 6 ++++-- 2 files changed, 8 insertions(+), 6 deletions(-) diff --git a/Rules/AvoidAlias.cs b/Rules/AvoidAlias.cs index 7b8a46c2f..8e10301fd 100644 --- a/Rules/AvoidAlias.cs +++ b/Rules/AvoidAlias.cs @@ -348,7 +348,7 @@ private ScriptBlockExpressionAst GetDscResourceBody(CommandAst cmdAst) && bodyPipeline.PipelineElements.Count == 1 && bodyPipeline.PipelineElements[0] is CommandExpressionAst bodyExpression) { - if (HasSemicolonSeparator(pipeline, bodyPipeline) + if (HasStatementSeparator(pipeline, bodyPipeline) || bodyExpression.Redirections.Count != 0) { return null; @@ -364,7 +364,7 @@ private ScriptBlockExpressionAst GetDscResourceBody(CommandAst cmdAst) return null; } - private bool HasSemicolonSeparator(Ast statement, Ast nextStatement) + private bool HasStatementSeparator(Ast statement, Ast nextStatement) { int separatorStart = statement.Extent.EndOffset; int separatorLength = nextStatement.Extent.StartOffset - separatorStart; @@ -375,13 +375,13 @@ private bool HasSemicolonSeparator(Ast statement, Ast nextStatement) string script = statement.Extent.EndScriptPosition.GetFullScript(); string separator = script.Substring(separatorStart, separatorLength); - if (separator.IndexOf(';') < 0) + if (separator.IndexOf(';') < 0 && separator.IndexOf('&') < 0) { return false; } Parser.ParseInput(separator, out Token[] tokens, out ParseError[] errors); - return tokens.Any(token => token.Kind == TokenKind.Semi); + return tokens.Any(token => token.Kind == TokenKind.Semi || token.Kind == TokenKind.Ampersand); } /// diff --git a/Tests/Rules/AvoidUsingAlias.tests.ps1 b/Tests/Rules/AvoidUsingAlias.tests.ps1 index 731dc4137..1c2470447 100644 --- a/Tests/Rules/AvoidUsingAlias.tests.ps1 +++ b/Tests/Rules/AvoidUsingAlias.tests.ps1 @@ -233,12 +233,14 @@ Configuration PackageTest { } } - It "does not pair following-line blocks with commands when the block has redirections or a statement terminator intervenes" { + It "does not pair following-line blocks with commands when the block has redirections or a statement separator intervenes" { $target = @' { gci . {} > $null gci .; {} + gci . & + {} } '@ $ast = [System.Management.Automation.Language.Parser]::ParseInput($target, [ref]$null, [ref]$null) @@ -250,7 +252,7 @@ Configuration PackageTest { $violations = @($rule.AnalyzeScript($configuration, $null)) - $violations.Count | Should -Be 2 + $violations.Count | Should -Be 3 $violations | ForEach-Object { $_.Extent.Text | Should -Be 'gci' $_.SuggestedCorrections[0].Text | Should -Be 'Get-ChildItem' From cb23c461315faeca651bcf5c9584d53f3d5f74ae Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Wed, 28 Oct 2026 21:51:34 +0000 Subject: [PATCH 3/3] Fix DSC separator detection across PowerShell versions Co-authored-by: bergmeister <9250262+bergmeister@users.noreply.github.com> --- Rules/AvoidAlias.cs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/Rules/AvoidAlias.cs b/Rules/AvoidAlias.cs index 8e10301fd..f40d961f1 100644 --- a/Rules/AvoidAlias.cs +++ b/Rules/AvoidAlias.cs @@ -348,7 +348,7 @@ private ScriptBlockExpressionAst GetDscResourceBody(CommandAst cmdAst) && bodyPipeline.PipelineElements.Count == 1 && bodyPipeline.PipelineElements[0] is CommandExpressionAst bodyExpression) { - if (HasStatementSeparator(pipeline, bodyPipeline) + if (HasStatementSeparator(cmdAst, bodyPipeline) || bodyExpression.Redirections.Count != 0) { return null; @@ -364,9 +364,9 @@ private ScriptBlockExpressionAst GetDscResourceBody(CommandAst cmdAst) return null; } - private bool HasStatementSeparator(Ast statement, Ast nextStatement) + private bool HasStatementSeparator(CommandAst statement, Ast nextStatement) { - int separatorStart = statement.Extent.EndOffset; + int separatorStart = statement.CommandElements[statement.CommandElements.Count - 1].Extent.EndOffset; int separatorLength = nextStatement.Extent.StartOffset - separatorStart; if (separatorLength <= 0) {