Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 11 additions & 1 deletion public/Copy-DbaDatabase.ps1
Original file line number Diff line number Diff line change
Expand Up @@ -774,7 +774,17 @@ function Copy-DbaDatabase {
}

if ($Database -contains "master" -or $Database -contains "msdb" -or $Database -contains "tempdb") {
Stop-Function -Message "Migrating system databases is not currently supported." -Continue
# This rejects one input, not the command: a plain Stop-Function sets the interrupt flag that
# Test-FunctionInterrupt reads at the top of this block, which would drop every database piped in
# after this one, and -Continue has no loop to continue here (#10638). So throw under
# -EnableException, otherwise warn, and return from this process invocation only.
$systemDbMessage = "Migrating system databases is not currently supported."
if ($EnableException) {
Stop-Function -Message $systemDbMessage -EnableException $true
} else {
Write-Message -Level Warning -Message $systemDbMessage
}
return
}

try {
Expand Down
87 changes: 87 additions & 0 deletions tests/Copy-DbaDatabase.Tests.ps1
Original file line number Diff line number Diff line change
Expand Up @@ -872,4 +872,91 @@ Describe $CommandName -Tag IntegrationTests {
}
}
}

Context "When a system database is requested" {
BeforeAll {
# We want to run all commands in the BeforeAll block with EnableException to ensure that the test fails if the setup fails.
$PSDefaultParameterValues["*-Dba*:EnableException"] = $true

$afterSystemDb = "dbatoolsci_aftersystem_$(Get-Random)"
$serverAfterSystem = Connect-DbaInstance -SqlInstance $TestConfig.InstanceCopy1
$serverAfterSystem.Query("CREATE DATABASE $afterSystemDb; ALTER DATABASE $afterSystemDb SET AUTO_CLOSE OFF WITH ROLLBACK IMMEDIATE")

# We want to run all commands outside of the BeforeAll block without EnableException to be able to test for specific warnings.
$PSDefaultParameterValues.Remove("*-Dba*:EnableException")
}

AfterAll {
# We want to run all commands in the AfterAll block with EnableException to ensure that the test fails if the cleanup fails.
$PSDefaultParameterValues["*-Dba*:EnableException"] = $true

Remove-DbaDatabase -SqlInstance $TestConfig.InstanceCopy1, $TestConfig.InstanceCopy2 -Database $afterSystemDb -ErrorAction SilentlyContinue

$PSDefaultParameterValues.Remove("*-Dba*:EnableException")
}

It "Copies the database piped in after a system database" {
# A plain Stop-Function used to set the command-wide interrupt flag for the system database, and
# Test-FunctionInterrupt then dropped every database piped in after it.
$splatAfterSystem = @{
Source = $TestConfig.InstanceCopy1
Destination = $TestConfig.InstanceCopy2
BackupRestore = $true
SharedPath = $NetworkPath
WarningAction = "SilentlyContinue"
}
$pipedDatabases = @(Get-DbaDatabase -SqlInstance $TestConfig.InstanceCopy1 -Database master) + @(Get-DbaDatabase -SqlInstance $TestConfig.InstanceCopy1 -Database $afterSystemDb)
$results = $pipedDatabases | Copy-DbaDatabase @splatAfterSystem
($results | Measure-Object).Count | Should -Be 1
$results.Name | Should -Be $afterSystemDb
$results.Status | Should -Be "Successful"
($WarnVar -join " ") | Should -BeLike "*Migrating system databases is not currently supported*"
}

It "Throws for a system database under -EnableException" {
$splatThrow = @{
Source = $TestConfig.InstanceCopy1
Destination = $TestConfig.InstanceCopy2
BackupRestore = $true
SharedPath = $NetworkPath
EnableException = $true
}
# The parameter form: a throw inside the process block of a piped call surfaces in the upstream command,
# whose own output loop catches it (Get-DbaDatabase warns about a modified collection instead).
$systemDbException = $null
$systemDbWarnings = $null
try {
Copy-DbaDatabase @splatThrow -Database master -WarningVariable systemDbWarnings
} catch {
$systemDbException = $PSItem
}
$systemDbException.Exception.Message | Should -BeLike "*Migrating system databases is not currently supported*"
# Stop-Function writes its warning before it throws, as it does for every throw in dbatools; the message is
# not written a second time.
@($systemDbWarnings).Count | Should -Be 1
}

It "Warns without eating an iteration of the caller's loop" {
# The system database check used to run Stop-Function -Continue in 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). The check fires before any connection is made.
$loopCount = 0
foreach ($i in 1..3) {
$splatSystemDb = @{
Source = $TestConfig.InstanceCopy1
Destination = $TestConfig.InstanceCopy2
Database = "master"
BackupRestore = $true
SharedPath = $TestConfig.Temp
WarningAction = "SilentlyContinue"
}
$null = Copy-DbaDatabase @splatSystemDb
$loopCount++
}
$loopCount | Should -Be 3
# The last call warned once, not twice.
@($WarnVar).Count | Should -Be 1
$WarnVar | Should -BeLike "*Migrating system databases is not currently supported*"
}
}
}