diff --git a/public/Backup-DbaServiceMasterKey.ps1 b/public/Backup-DbaServiceMasterKey.ps1 index 3aaff8e269..ff7df57283 100644 --- a/public/Backup-DbaServiceMasterKey.ps1 +++ b/public/Backup-DbaServiceMasterKey.ps1 @@ -16,11 +16,15 @@ function Backup-DbaServiceMasterKey { For MFA support, please use Connect-DbaInstance. + .PARAMETER KeyCredential + Pass a credential object for the password + .PARAMETER Path The directory to export the key. If no path is specified, the default backup directory for the instance will be used. - .PARAMETER KeyCredential - Pass a credential object for the password + .PARAMETER FileBaseName + Override the default naming convention with a fixed name for the service master key, useful when exporting a single one. + ".key" will be appended to the filename. .PARAMETER SecurePassword The password to encrypt the exported key. This must be a SecureString. @@ -72,13 +76,13 @@ function Backup-DbaServiceMasterKey { [Alias("Password")] [Security.SecureString]$SecurePassword, [string]$Path, + [string]$FileBaseName, [switch]$EnableException ) begin { if ($KeyCredential) { $SecurePassword = $KeyCredential.Password } - $time = Get-Date -Format yyyMMddHHmmss } process { foreach ($instance in $SqlInstance) { @@ -116,16 +120,24 @@ function Backup-DbaServiceMasterKey { $Path = $Path.TrimEnd("\") $Path = $Path.TrimEnd("/") $fileinstance = $instance.ToString().Replace('\', '$') - $filename = Join-DbaPath -SqlInstance $server -Path $Path -ChildPath "$fileinstance-servicemasterkey.key" + $targetBaseName = "$fileinstance-servicemasterkey" + if ($FileBaseName) { + $targetBaseName = $FileBaseName + } + + $exportFileName = Join-DbaPath -SqlInstance $server -Path $Path -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 $Path -ChildPath "$fileinstance-servicemasterkey-$time.key" + if (Test-DbaPath -SqlInstance $server -Path $exportFileName) { + $time = Get-Date -Format yyyyMMddHHmmss + $exportFileName = Join-DbaPath -SqlInstance $server -Path $Path -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 service master key to $filename")) { + if ($Pscmdlet.ShouldProcess($instance, "Backing up service master key to $exportFileName")) { try { - $masterkey.Export($filename, ($SecurePassword | ConvertFrom-SecurePass)) + $masterkey.Export($exportFileName, ($SecurePassword | ConvertFrom-SecurePass)) $status = "Success" } catch { $status = "Failure" @@ -135,7 +147,7 @@ function Backup-DbaServiceMasterKey { 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 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, 'Filename as Path', Status diff --git a/tests/Backup-DbaServiceMasterKey.Tests.ps1 b/tests/Backup-DbaServiceMasterKey.Tests.ps1 index c81c81b578..885e568fde 100644 --- a/tests/Backup-DbaServiceMasterKey.Tests.ps1 +++ b/tests/Backup-DbaServiceMasterKey.Tests.ps1 @@ -15,6 +15,7 @@ Describe "Backup-DbaServiceMasterKey" -Tag "UnitTests" { "KeyCredential", "SecurePassword", "Path", + "FileBaseName", "EnableException", "Confirm", "WhatIf" @@ -36,7 +37,6 @@ Describe "Backup-DbaServiceMasterKey" -Tag "IntegrationTests" { Context "Can backup a service master key" { BeforeAll { $securePassword = ConvertTo-SecureString -String "GoodPass1234!" -AsPlainText -Force - $results = Backup-DbaServiceMasterKey -SqlInstance $TestConfig.instance1 -SecurePassword $securePassword -Confirm:$false } AfterAll { @@ -44,6 +44,14 @@ Describe "Backup-DbaServiceMasterKey" -Tag "IntegrationTests" { } It "backs up the SMK" { + $results = Backup-DbaServiceMasterKey -SqlInstance $TestConfig.instance1 -SecurePassword $securePassword -Confirm:$false + $results.Status | Should -Be "Success" + } + + It "backs up the SMK with a specific filename (see #9483)" { + $random = Get-Random + $results = Backup-DbaServiceMasterKey -SqlInstance $TestConfig.instance1 -SecurePassword $securePassword -FileBaseName "smk($random)" -Confirm:$false + [IO.Path]::GetFileNameWithoutExtension($results.Path) | Should -Be "smk($random)" $results.Status | Should -Be "Success" } }