From 978b97c5e285d4ded46102f9fa6e941cc9adb4d6 Mon Sep 17 00:00:00 2001 From: Simone Bizzotto Date: Mon, 24 Feb 2025 14:25:32 +0100 Subject: [PATCH] Backup-DbaDbMasterKey, add FileBaseName (#9599) --- public/Backup-DbaDbMasterKey.ps1 | 39 ++++++++++++++++----------- tests/Backup-DbaDbMasterKey.Tests.ps1 | 29 ++++++++++++++++---- 2 files changed, 48 insertions(+), 20 deletions(-) diff --git a/public/Backup-DbaDbMasterKey.ps1 b/public/Backup-DbaDbMasterKey.ps1 index 1c1ac00bb1..66f3d3d85f 100644 --- a/public/Backup-DbaDbMasterKey.ps1 +++ b/public/Backup-DbaDbMasterKey.ps1 @@ -16,20 +16,24 @@ function Backup-DbaDbMasterKey { For MFA support, please use Connect-DbaInstance. + .PARAMETER Credential + Pass a credential object for the password + .PARAMETER Database Backup master key from specific database(s). .PARAMETER ExcludeDatabase The database(s) to exclude - this list is auto-populated from the server. + .PARAMETER SecurePassword + The password to encrypt the exported key. This must be a SecureString. + .PARAMETER Path The directory to export the key. If no path is specified, the default backup directory for the instance will be used. - .PARAMETER Credential - Pass a credential object for the password - - .PARAMETER SecurePassword - The password to encrypt the exported key. This must be a SecureString. + .PARAMETER FileBaseName + Override the default naming convention with a fixed name for the database master key, useful when exporting a single one. + ".key" will be appended to the filename. .PARAMETER InputObject Database object piped in from Get-DbaDatabase @@ -82,6 +86,7 @@ function Backup-DbaDbMasterKey { [Alias("Password")] [Security.SecureString]$SecurePassword, [string]$Path, + [string]$FileBaseName, [parameter(ValueFromPipeline)] [Microsoft.SqlServer.Management.Smo.Database[]]$InputObject, [switch]$EnableException @@ -90,7 +95,6 @@ function Backup-DbaDbMasterKey { if ($Credential) { $SecurePassword = $Credential.Password } - $time = Get-Date -Format yyyMMddHHmmss } process { foreach ($instance in $SqlInstance) { @@ -144,31 +148,36 @@ function Backup-DbaDbMasterKey { } $fileinstance = $instance.ToString().Replace('\', '$') - $filename = Join-DbaPath -SqlInstance $server -Path $actualPath -ChildPath "$fileinstance-$dbname-masterkey.key" + $targetBaseName = "$fileinstance-$dbname-masterkey" + if ($FileBaseName) { + $targetBaseName = $FileBaseName + } + + $exportFileName = Join-DbaPath -SqlInstance $server -Path $actualPath -ChildPath "$targetBaseName.key" # if the base file name exists, then default to old style of appending a timestamp - if (Test-DbaPath -SqlInstance $server -Path $filename) { - $filename = Join-DbaPath -SqlInstance $server -Path $actualPath -ChildPath "$fileinstance-$dbname-masterkey-$time.key" + if (Test-DbaPath -SqlInstance $server -Path $exportFileName) { + $time = Get-Date -Format yyyMMddHHmmss + $exportFileName = Join-DbaPath -SqlInstance $server -Path $actualPath -ChildPath "$targetBaseName-$time.key" + # Sleep for a second to avoid another export in the same second + Start-Sleep -Seconds 1 } - if ($Pscmdlet.ShouldProcess($instance, "Backing up master key to $filename")) { + if ($Pscmdlet.ShouldProcess($instance, "Backing up master key to $exportFileName")) { try { - $masterkey.Export($filename, ($SecurePassword | ConvertFrom-SecurePass)) + $masterkey.Export($exportFileName, ($SecurePassword | ConvertFrom-SecurePass)) $status = "Success" } catch { $status = "Failure" Write-Message -Level Warning -Message "Backup failure: $($_.Exception.InnerException)" } - # Sleep for a second to avoid another export in the same second - Start-Sleep -Seconds 1 - Add-Member -Force -InputObject $masterkey -MemberType NoteProperty -Name ComputerName -value $server.ComputerName Add-Member -Force -InputObject $masterkey -MemberType NoteProperty -Name InstanceName -value $server.ServiceName Add-Member -Force -InputObject $masterkey -MemberType NoteProperty -Name SqlInstance -value $server.DomainInstanceName Add-Member -Force -InputObject $masterkey -MemberType NoteProperty -Name Database -value $dbName Add-Member -Force -InputObject $masterkey -MemberType NoteProperty -Name DatabaseID -value $db.ID - Add-Member -Force -InputObject $masterkey -MemberType NoteProperty -Name Filename -value $filename + Add-Member -Force -InputObject $masterkey -MemberType NoteProperty -Name Filename -value $exportFileName Add-Member -Force -InputObject $masterkey -MemberType NoteProperty -Name Status -value $status Select-DefaultView -InputObject $masterkey -Property ComputerName, InstanceName, SqlInstance, Database, 'Filename as Path', Status diff --git a/tests/Backup-DbaDbMasterKey.Tests.ps1 b/tests/Backup-DbaDbMasterKey.Tests.ps1 index 28a23ddbb9..83de988e6d 100644 --- a/tests/Backup-DbaDbMasterKey.Tests.ps1 +++ b/tests/Backup-DbaDbMasterKey.Tests.ps1 @@ -17,6 +17,7 @@ Describe "Backup-DbaDbMasterKey" -Tag "UnitTests" { "ExcludeDatabase", "SecurePassword", "Path", + "FileBaseName", "InputObject", "EnableException", "WhatIf", @@ -45,27 +46,45 @@ Describe "Backup-DbaDbMasterKey" -Tag "IntegrationTests" { if (-not (Get-DbaDbMasterKey -SqlInstance $instance -Database $database)) { $null = New-DbaDbMasterKey -SqlInstance $instance -Database $database -Password $password -Confirm:$false } + } + + AfterAll { + Get-DbaDbMasterKey -SqlInstance $instance -Database $database | Remove-DbaDbMasterKey -Confirm:$false + } + It "Backs up the database master key" { $splatBackup = @{ SqlInstance = $instance Database = $database SecurePassword = $password Confirm = $false } - } + $results = Backup-DbaDbMasterKey @splatBackup + $results | Should -Not -BeNullOrEmpty + $results.Database | Should -Be $database + $results.Status | Should -Be "Success" + $results.DatabaseID | Should -Be (Get-DbaDatabase -SqlInstance $instance -Database $database).ID - AfterAll { - Get-DbaDbMasterKey -SqlInstance $instance -Database $database | Remove-DbaDbMasterKey -Confirm:$false + $null = Remove-Item -Path $results.Path -ErrorAction SilentlyContinue -Confirm:$false } - It "Backs up the database master key" { + It "Backs up the database master key with a specific filename (see #9484)" { + $random = Get-Random + $splatBackup = @{ + SqlInstance = $instance + Database = $database + SecurePassword = $password + FileBaseName = "dbatoolscli_dbmasterkey_$random" + Confirm = $false + } $results = Backup-DbaDbMasterKey @splatBackup $results | Should -Not -BeNullOrEmpty $results.Database | Should -Be $database $results.Status | Should -Be "Success" $results.DatabaseID | Should -Be (Get-DbaDatabase -SqlInstance $instance -Database $database).ID - + [IO.Path]::GetFileNameWithoutExtension($results.Path) | Should -Be "dbatoolscli_dbmasterkey_$random" $null = Remove-Item -Path $results.Path -ErrorAction SilentlyContinue -Confirm:$false } + } }