diff --git a/public/Invoke-DbaDbDecryptObject.ps1 b/public/Invoke-DbaDbDecryptObject.ps1 index 9c34c16ede8..10c7ae76682 100644 --- a/public/Invoke-DbaDbDecryptObject.ps1 +++ b/public/Invoke-DbaDbDecryptObject.ps1 @@ -209,9 +209,12 @@ function Invoke-DbaDbDecryptObject { if ($ExportDestination -and -not (Test-Path $ExportDestination)) { try { # Create the new destination - New-Item -Path $ExportDestination -ItemType Directory -Force | Out-Null + New-Item -Path $ExportDestination -ItemType Directory -Force -ErrorAction Stop | Out-Null } catch { - Stop-Function -Message "Couldn't create destination folder $ExportDestination" -ErrorRecord $_ -Target $instance -Continue + # No -Continue here: the begin block has no enclosing loop, so the continue would escape the command + # and eat an iteration of whatever loop the caller runs in (#10638). The process block is guarded. + Stop-Function -Message "Couldn't create destination folder $ExportDestination" -ErrorRecord $_ -Target $instance + return } } diff --git a/tests/Invoke-DbaDbDecryptObject.Tests.ps1 b/tests/Invoke-DbaDbDecryptObject.Tests.ps1 index 680472f274d..511ed7e03a2 100644 --- a/tests/Invoke-DbaDbDecryptObject.Tests.ps1 +++ b/tests/Invoke-DbaDbDecryptObject.Tests.ps1 @@ -1181,4 +1181,34 @@ Describe $CommandName -Tag IntegrationTests { $contextAfter | Should -Be $contextBefore } } + + Context "When the export destination cannot be created" { + BeforeAll { + # A destination on a drive that does not exist: New-Item -Force on a folder under a file returns + # quietly, a missing drive is what makes it throw on both editions. + $freeDriveLetter = [char[]](90..65) | Where-Object { -not (Test-Path -Path "$([char]$PSItem):\") } | Select-Object -First 1 + $badDestination = "$([char]$freeDriveLetter):\dbatoolsci_nodrive\export" + } + + It "Warns without eating an iteration of the caller's loop" { + # The folder check used to run Stop-Function -Continue in the begin block, where no loop encloses + # it - the continue escaped the command and consumed an iteration of this very loop (#10638). It + # also never fired, because the failing New-Item was not a terminating error, so a folder that could + # not be created was silently ignored. The check fires before any connection is made. + $loopCount = 0 + foreach ($i in 1..3) { + $splatBadFolder = @{ + SqlInstance = $TestConfig.InstanceMulti1 + Database = "dbatoolsci_none" + ObjectName = "dbatoolsci_none" + ExportDestination = $badDestination + WarningAction = "SilentlyContinue" + } + $null = Invoke-DbaDbDecryptObject @splatBadFolder + $loopCount++ + } + $loopCount | Should -Be 3 + ($WarnVar -join " ") | Should -BeLike "*create destination folder $badDestination*" + } + } }