Summary
When Restore-DbaDatabase is given backup files that contain a differential or log backup but no full backup to anchor the chain, it warns and returns nothing - even with -EnableException, which promises "enables you to catch exceptions with your own try/catch". A caller that relies on the exception (for example a test fixture, or any script that restores and then works with the database) continues as if the restore had happened.
Repro (measured on SQL03\SQL2019, dbatools development)
$PSDefaultParameterValues["*-Dba*:EnableException"] = $true
# db restored from any full backup, then:
$full = Backup-DbaDatabase -SqlInstance $server -Database $db -Type Full -Path $dir -FilePath "full.bak"
$diff = Backup-DbaDatabase -SqlInstance $server -Database $db -Type Diff -Path $dir -FilePath "diff.bak"
$log = Backup-DbaDatabase -SqlInstance $server -Database $db -Type Log -Path $dir -FilePath "log.trn"
# no full in the set - warns, does not throw, returns nothing:
Restore-DbaDatabase -SqlInstance $server -Path $diff.BackupPath, $log.BackupPath -DatabaseName $db -WithReplace
# WARNING: [Select-DbaBackupInformation] Fullname property not found. This could mean that a full backup
# could not be found or the command must be re-run with the -Continue switch.
Mechanism
Select-DbaBackupInformation correctly calls Stop-Function when it cannot find a full backup (public/Select-DbaBackupInformation.ps1, the two "Fullname property not found" sites). But the splat that Restore-DbaDatabase builds for the call (public/Restore-DbaDatabase.ps1, around line 857) does not pass EnableException on, so inside Select-DbaBackupInformation the stop degrades to a warning, control returns, and Restore-DbaDatabase proceeds with an empty $FilteredBackupHistory to a successful-looking no-op.
Real-world impact
This is exactly how Get-DbaDbRestoreHistory.Tests.ps1 was flaky for years: its fixture restored diff+log without the full, which only worked because the default backup file name has minute resolution and the full and diff usually share one file. On a minute boundary the restore silently did nothing and six tests failed downstream (fixed on the test side in #10620).
Suggested direction
Pass EnableException = $EnableException in the Select-DbaBackupInformation splat, and check the other internal *-DbaBackupInformation calls in the same pipeline (Get-, Format-, Test-) for the same gap. Whether an empty selection after a warning should also stop the non-exception path is a behavior question worth deciding at the same time.
Created by Claude and reviewed by Andreas Jordan.
Summary
When
Restore-DbaDatabaseis given backup files that contain a differential or log backup but no full backup to anchor the chain, it warns and returns nothing - even with-EnableException, which promises "enables you to catch exceptions with your own try/catch". A caller that relies on the exception (for example a test fixture, or any script that restores and then works with the database) continues as if the restore had happened.Repro (measured on SQL03\SQL2019, dbatools development)
Mechanism
Select-DbaBackupInformationcorrectly callsStop-Functionwhen it cannot find a full backup (public/Select-DbaBackupInformation.ps1, the two "Fullname property not found" sites). But the splat thatRestore-DbaDatabasebuilds for the call (public/Restore-DbaDatabase.ps1, around line 857) does not passEnableExceptionon, so insideSelect-DbaBackupInformationthe stop degrades to a warning, control returns, andRestore-DbaDatabaseproceeds with an empty$FilteredBackupHistoryto a successful-looking no-op.Real-world impact
This is exactly how
Get-DbaDbRestoreHistory.Tests.ps1was flaky for years: its fixture restored diff+log without the full, which only worked because the default backup file name has minute resolution and the full and diff usually share one file. On a minute boundary the restore silently did nothing and six tests failed downstream (fixed on the test side in #10620).Suggested direction
Pass
EnableException = $EnableExceptionin theSelect-DbaBackupInformationsplat, and check the other internal*-DbaBackupInformationcalls in the same pipeline (Get-,Format-,Test-) for the same gap. Whether an empty selection after a warning should also stop the non-exception path is a behavior question worth deciding at the same time.Created by Claude and reviewed by Andreas Jordan.