From 714d0ca2fa0480d3900a16e5532f4e19ef923b06 Mon Sep 17 00:00:00 2001 From: Andreas Jordan Date: Sat, 12 Sep 2026 15:25:42 +0200 Subject: [PATCH 1/2] New-DbaAzAccessToken - Stop eating the caller loop when the token request fails Stop-Function -Continue runs PowerShell's continue. No loop encloses this call site inside the command, so the continue unwound out of the command and consumed an iteration of whatever loop the caller runs in: a user's foreach silently skipped an element, and Pester's runner corrupted. The escape only bites the non-EnableException path; with EnableException Stop-Function throws before it gets there. Part of #10638 (do New-DbaAzAccessToken) Co-Authored-By: Claude Fable 5.1 --- public/New-DbaAzAccessToken.ps1 | 4 +++- tests/New-DbaAzAccessToken.Tests.ps1 | 29 +++++++++++++++++++++++++++- 2 files changed, 31 insertions(+), 2 deletions(-) diff --git a/public/New-DbaAzAccessToken.ps1 b/public/New-DbaAzAccessToken.ps1 index dcfba2de3fd7..011066950c4b 100644 --- a/public/New-DbaAzAccessToken.ps1 +++ b/public/New-DbaAzAccessToken.ps1 @@ -254,7 +254,9 @@ function New-DbaAzAccessToken { } } } catch { - Stop-Function -Message "Failure" -ErrorRecord $_ -Continue + # No -Continue here: this block has no enclosing loop, so the continue would escape the command + # and eat an iteration of whatever loop the caller runs in (#10638). + Stop-Function -Message "Failure" -ErrorRecord $_ } } } \ No newline at end of file diff --git a/tests/New-DbaAzAccessToken.Tests.ps1 b/tests/New-DbaAzAccessToken.Tests.ps1 index fb4271a5be04..017150d8432e 100644 --- a/tests/New-DbaAzAccessToken.Tests.ps1 +++ b/tests/New-DbaAzAccessToken.Tests.ps1 @@ -28,4 +28,31 @@ Describe $CommandName -Tag UnitTests { Integration test should appear below and are custom to the command you are writing. Read https://github.com/dataplat/dbatools/blob/development/contributing.md#tests for more guidence. -#> \ No newline at end of file +#> +Describe $CommandName -Tag IntegrationTests { + Context "When the service principal cannot be authenticated" { + BeforeAll { + $badPassword = ConvertTo-SecureString -String "dbatoolsci" -AsPlainText -Force + $badCredential = New-Object -TypeName System.Management.Automation.PSCredential -ArgumentList "dbatoolsci", $badPassword + } + + It "Warns without eating an iteration of the caller's loop" { + # The catch used to run Stop-Function -Continue at the end of the process block, where no loop + # encloses it - the continue escaped the command and consumed an iteration of this very loop, so + # the counter stayed at zero (#10638). A tenant that does not exist makes the token request fail. + $loopCount = 0 + foreach ($i in 1..3) { + $splatBadTenant = @{ + Type = "ServicePrincipal" + Tenant = "dbatoolsci.invalid" + Credential = $badCredential + WarningAction = "SilentlyContinue" + } + $null = New-DbaAzAccessToken @splatBadTenant + $loopCount++ + } + $loopCount | Should -Be 3 + ($WarnVar -join " ") | Should -BeLike "*Failure*" + } + } +} From f34cb69dbba6277e9346dfa411584f75991f2240 Mon Sep 17 00:00:00 2001 From: Andreas Jordan Date: Sat, 12 Sep 2026 15:42:54 +0200 Subject: [PATCH 2/2] New-DbaAzAccessToken - Run the escape test on Windows PowerShell only, where the ServicePrincipal path executes (do New-DbaAzAccessToken) Co-Authored-By: Claude Fable 5.1 --- tests/New-DbaAzAccessToken.Tests.ps1 | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/tests/New-DbaAzAccessToken.Tests.ps1 b/tests/New-DbaAzAccessToken.Tests.ps1 index 017150d8432e..c17be29fb8c7 100644 --- a/tests/New-DbaAzAccessToken.Tests.ps1 +++ b/tests/New-DbaAzAccessToken.Tests.ps1 @@ -36,7 +36,9 @@ Describe $CommandName -Tag IntegrationTests { $badCredential = New-Object -TypeName System.Management.Automation.PSCredential -ArgumentList "dbatoolsci", $badPassword } - It "Warns without eating an iteration of the caller's loop" { + # The ServicePrincipal path is the one that reaches the catch: it refuses to run on Core before any + # request is made, so the test runs on Windows PowerShell only, which is what CI runs anyway. + It "Warns without eating an iteration of the caller's loop" -Skip:($PSVersionTable.PSEdition -eq "Core") { # The catch used to run Stop-Function -Continue at the end of the process block, where no loop # encloses it - the continue escaped the command and consumed an iteration of this very loop, so # the counter stayed at zero (#10638). A tenant that does not exist makes the token request fail.