Skip to content

Copy-DbaDatabase - Stop eating the caller loop when a system database is requested - #10696

Merged
potatoqualitee merged 5 commits into
developmentfrom
fix-copy-dbadatabase-continue-escape
Sep 16, 2026
Merged

potatoqualitee merged 5 commits into
developmentfrom
fix-copy-dbadatabase-continue-escape

Conversation

@andreasjordan

Copy link
Copy Markdown
Collaborator

Part of #10638, the sweep for Stop-Function -Continue outside an enclosing loop. Same shape and same test as #10637.

Problem

Copy-DbaDatabase refuses system databases with Stop-Function -Continue in its process block (Copy-DbaDatabase.ps1:777). No loop encloses that site inside the command, so without -EnableException the continue unwinds out of the command and consumes an iteration of whatever loop the caller runs in. Proven in the lab with the plain-script recipe: three calls with -Database master in a foreach left the loop counter at 0 on development and at 3 with the fix.

What changed

The -Continue is dropped and an explicit return ends the process block for that input, as in #10637. Nothing else changes; the check still fires before any connection is made.

Tests

New context When a system database is requested: three calls in a loop, asserting the loop count and the warning. Through the testing-dbatools harness: green on both editions with the fix (28 passed); the plain-script proof above is the red-on-old.

created by Claude and reviewed by Andreas Jordan

🤖 Generated with Claude Code

… is requested

Stop-Function -Continue runs PowerShell's continue. No loop encloses the
system database check inside the process block, 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 Copy-DbaDatabase)

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>

@potatoqualitee potatoqualitee left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

public/Copy-DbaDatabase.ps1:779-780 still suppresses valid later pipeline inputs after one unsupported system database. Stop-Function without -Continue sets the command-scope interrupt flag; the explicit return ends only the current process invocation, and the next piped database is then rejected by Test-FunctionInterrupt at lines 729-731. For example, piping master followed by an application database warns for master and silently skips the application database. The new test calls the command three separate times, so it does not exercise this single-pipeline path.

Please preserve the warning/error behavior without leaving the command-wide interrupt flag set for this per-input rejection, and add a regression test with a system database followed by a valid database in one pipeline.

andreasjordan and others added 3 commits September 13, 2026 11:33
…bases piped in after it

A plain Stop-Function set the function-scope interrupt flag, so after one system database Test-FunctionInterrupt dropped every later piped database. Throw under -EnableException, otherwise warn, and return from that process invocation only. Adds one-pipeline and -EnableException tests.

(do Copy-DbaDatabase)

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
(do Copy-DbaDatabase)

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
…er form

A throw inside the process block of a piped call surfaces in the upstream command, whose own output loop catches it.

(do Copy-DbaDatabase)

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
@andreasjordan

Copy link
Copy Markdown
Collaborator Author

Confirmed and fixed in 2ecac8b: the plain Stop-Function set the function-scope interrupt variable, so after one system database Test-FunctionInterrupt dropped every database piped in after it.

What changed: the system-database check now throws under -EnableException and otherwise warns and returns from that process invocation only, so the flag is never set for this per-input rejection. -Continue is not an option here: no loop encloses the check in the process block, and the escaping continue was the original #10638 defect.

Tests: the context gained a fixture database on InstanceCopy1 and two tests. master followed by that database in one pipeline copies the database (one result, Successful) and warns for master; the -EnableException form throws the same message. Through the testing-dbatools harness: the file is green on both editions (31/31); against the reviewed head, the pipeline test fails with zero results (the second database is dropped) while the throw test passes there too, as the old code threw as well.

created by Claude and reviewed by Andreas Jordan

potatoqualitee
potatoqualitee previously approved these changes Sep 14, 2026

@potatoqualitee potatoqualitee left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The current head resolves my previous pipeline-control-flow finding, including coverage that a valid database following a system database is still processed. No material defects remain. Reviewed at head 2ecac8b.

Comment thread public/Copy-DbaDatabase.ps1 Outdated
if ($EnableException) {
Stop-Function -Message $systemDbMessage -EnableException $true
}
Write-Message -Level Warning -Message $systemDbMessage

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm not so sure this makes sense. it'll show duplicate if the person has enableexception enabled it'll warn them twice.

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It never warned twice, but I agree the shape suggested it could: under -EnableException, Stop-Function throws before the next line is reached, so the Write-Message after it was dead code on that path. Fixed in c3d4df0 by making it an explicit if/else.

Measured on the lab, pwsh and 5.1: the exception path emits the exception and one warning record (the one Stop-Function itself writes before every throw in dbatools; a console shows only the exception), the warning path emits exactly one warning. Both are asserted now: the throw test runs the command in the test scope with its own warning variable and checks one record, the loop test checks that the last rejected call warned once. The whole file is green on both editions (31/31).

created by Claude and reviewed by Andreas Jordan

…n-or-throw

Under -EnableException the Stop-Function call throws before the line after it runs, so the warning was never written a second time, but the shape read as if it could be. Put the two paths into one if/else. The throw test now runs the command in the test scope with its own warning variable and asserts one warning record next to the exception, the one Stop-Function writes before every throw, and the loop test asserts that the last rejected call warned exactly once.

(do Copy-DbaDatabase)

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>

@potatoqualitee potatoqualitee left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No material defects found.

@potatoqualitee
potatoqualitee merged commit 58e1132 into development Sep 16, 2026
24 checks passed
@potatoqualitee
potatoqualitee deleted the fix-copy-dbadatabase-continue-escape branch September 16, 2026 18:02
@potatoqualitee

Copy link
Copy Markdown
Member

ty 🙇🏼

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants