Skip to content

Commit b0403f5

Browse files
Start-DbaMigration: Enhance handling of dedicated admin connections (#10162)
1 parent b82f01e commit b0403f5

3 files changed

Lines changed: 66 additions & 5 deletions

File tree

.github/scripts/gh-actions.ps1

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,7 @@ Describe "Integration Tests" -Tag "IntegrationTests" {
3535
$params = @{
3636
MasterKeyPassword = $cred.Password
3737
BackupRestore = $true
38-
Exclude = "LinkedServers", "Credentials", "DataCollector", "EndPoints", "PolicyManagement", "ResourceGovernor", "BackupDevices"
38+
Exclude = "DatabaseMail", "LinkedServers", "Credentials", "DataCollector", "EndPoints", "PolicyManagement", "ResourceGovernor", "BackupDevices"
3939
}
4040
# something is up with docker on actions, adjust accordingly for the cert test
4141
$initialcertcount = (Get-DbaDbCertificate -SqlInstance localhost:14333 -Database master).Count

public/Start-DbaMigration.ps1

Lines changed: 63 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,11 @@ function Start-DbaMigration {
5252
Specifies credentials to connect to the destination SQL Server instance(s). Use when the current Windows account lacks sufficient permissions.
5353
Accepts PowerShell credential objects created with Get-Credential for SQL Authentication or alternative Windows accounts.
5454
55+
.PARAMETER Credential
56+
Login to the target OS using alternative credentials. Accepts credential objects (Get-Credential)
57+
58+
Only used when passwords are being exported, as it requires access to the Windows OS via PowerShell remoting to decrypt the passwords.
59+
5560
.PARAMETER BackupRestore
5661
Uses backup and restore method to migrate databases instead of detach/attach. Creates copy-only backups to preserve existing backup chains.
5762
Requires either -SharedPath for new backups or -UseLastBackup to restore from existing backup files.
@@ -152,6 +157,10 @@ function Start-DbaMigration {
152157
Required when migrating databases with encrypted objects or certificates that need master key protection.
153158
Must be provided as a SecureString object for security.
154159
160+
.PARAMETER ExcludePassword
161+
Copies credentials, linked servers, and other objects without the actual password values.
162+
Use this in security-conscious environments where password decryption is restricted or when passwords should be manually reset after migration.
163+
155164
.PARAMETER Force
156165
Overwrites existing objects on the destination server without prompting for confirmation.
157166
For databases: drops existing databases with matching names before restoring.
@@ -242,6 +251,7 @@ function Start-DbaMigration {
242251
param (
243252
[DbaInstanceParameter]$Source,
244253
[DbaInstanceParameter[]]$Destination,
254+
[PSCredential]$Credential,
245255
[switch]$DetachAttach,
246256
[switch]$Reattach,
247257
[switch]$BackupRestore,
@@ -264,6 +274,7 @@ function Start-DbaMigration {
264274
[switch]$KeepCDC,
265275
[switch]$KeepReplication,
266276
[switch]$Continue,
277+
[switch]$ExcludePassword,
267278
[switch]$Force,
268279
[string]$AzureCredential,
269280
[Security.SecureString]$MasterKeyPassword,
@@ -348,7 +359,40 @@ function Start-DbaMigration {
348359
}
349360

350361
try {
351-
$sourceserver = Connect-DbaInstance -SqlInstance $Source -SqlCredential $SourceSqlCredential
362+
# Do we need a dedicated admin connection to the source for password retrieval?
363+
# If not all of the three are excluded, we do
364+
$dacNeeded = $Exclude -notcontains 'Credentials' -or $Exclude -notcontains 'DatabaseMail' -or $Exclude -notcontains 'LinkedServers'
365+
# If passwords are excluded, we don't need a DAC
366+
if ($ExcludePassword) { $dacNeeded = $false }
367+
368+
# Do we have a dedicated admin connection already?
369+
$dacConnected = $Source.Type -eq 'Server' -and $Source.InputObject.Name -match '^ADMIN:'
370+
371+
$dacOpened = $false
372+
if ($dacNeeded) {
373+
if ($dacConnected) {
374+
Write-Message -Level Verbose -Message "Reusing dedicated admin connection for password retrieval."
375+
$sourceServerDac = $Source.InputObject
376+
# Reconnect without DAC for Copy-DbaDatabase
377+
Write-Message -Level Verbose -Message "Opening additional normal connection for all commands that don't require DAC."
378+
$sourceServer = Connect-DbaInstance -SqlInstance $Source.FullName -SqlCredential $SourceSqlCredential
379+
} else {
380+
Write-Message -Level Verbose -Message "Opening dedicated admin connection for password retrieval."
381+
$sourceServerDac = Connect-DbaInstance -SqlInstance $Source -SqlCredential $SourceSqlCredential -DedicatedAdminConnection -WarningAction SilentlyContinue
382+
$dacOpened = $true
383+
Write-Message -Level Verbose -Message "Opening or reusing additional normal connection for all commands that don't require DAC."
384+
$sourceServer = Connect-DbaInstance -SqlInstance $Source -SqlCredential $SourceSqlCredential
385+
}
386+
} else {
387+
if ($dacConnected) {
388+
# Reconnect without DAC for Copy-DbaDatabase
389+
Write-Message -Level Verbose -Message "Opening additional normal connection for all commands that don't require DAC."
390+
$sourceServer = Connect-DbaInstance -SqlInstance $Source.FullName -SqlCredential $SourceSqlCredential
391+
} else {
392+
Write-Message -Level Verbose -Message "Opening or reusing normal connection for all commands that don't require DAC."
393+
$sourceServer = Connect-DbaInstance -SqlInstance $Source -SqlCredential $SourceSqlCredential
394+
}
395+
}
352396
} catch {
353397
Stop-Function -Message "Failure" -Category ConnectionError -ErrorRecord $_ -Target $Source
354398
return
@@ -382,13 +426,21 @@ function Start-DbaMigration {
382426
if ($Exclude -notcontains 'Credentials') {
383427
Write-ProgressHelper -StepNumber ($stepCounter++) -Message "Migrating SQL credentials"
384428
Write-Message -Level Verbose -Message "Migrating SQL credentials"
385-
Copy-DbaCredential -Source $sourceserver -Destination $Destination -DestinationSqlCredential $DestinationSqlCredential -Force:$Force
429+
if ($dacNeeded) {
430+
Copy-DbaCredential -Source $sourceServerDac -Destination $Destination -DestinationSqlCredential $DestinationSqlCredential -Credential $Credential -ExcludePassword:$ExcludePassword -Force:$Force
431+
} else {
432+
Copy-DbaCredential -Source $sourceserver -Destination $Destination -DestinationSqlCredential $DestinationSqlCredential -Credential $Credential -ExcludePassword:$ExcludePassword -Force:$Force
433+
}
386434
}
387435

388436
if ($Exclude -notcontains 'DatabaseMail') {
389437
Write-ProgressHelper -StepNumber ($stepCounter++) -Message "Migrating database mail"
390438
Write-Message -Level Verbose -Message "Migrating database mail"
391-
Copy-DbaDbMail -Source $sourceserver -Destination $Destination -DestinationSqlCredential $DestinationSqlCredential -Force:$Force
439+
if ($dacNeeded) {
440+
Copy-DbaDbMail -Source $sourceServerDac -Destination $Destination -DestinationSqlCredential $DestinationSqlCredential -Credential $Credential -ExcludePassword:$ExcludePassword -Force:$Force
441+
} else {
442+
Copy-DbaDbMail -Source $sourceserver -Destination $Destination -DestinationSqlCredential $DestinationSqlCredential -Credential $Credential -ExcludePassword:$ExcludePassword -Force:$Force
443+
}
392444
}
393445

394446
if ($Exclude -notcontains 'CentralManagementServer') {
@@ -474,7 +526,11 @@ function Start-DbaMigration {
474526
if ($Exclude -notcontains 'LinkedServers') {
475527
Write-ProgressHelper -StepNumber ($stepCounter++) -Message "Migrating linked servers"
476528
Write-Message -Level Verbose -Message "Migrating linked servers"
477-
Copy-DbaLinkedServer -Source $sourceserver -Destination $Destination -DestinationSqlCredential $DestinationSqlCredential -Force:$Force
529+
if ($dacNeeded) {
530+
Copy-DbaLinkedServer -Source $sourceServerDac -Destination $Destination -DestinationSqlCredential $DestinationSqlCredential -Credential $Credential -ExcludePassword:$ExcludePassword -Force:$Force
531+
} else {
532+
Copy-DbaLinkedServer -Source $sourceserver -Destination $Destination -DestinationSqlCredential $DestinationSqlCredential -Credential $Credential -ExcludePassword:$ExcludePassword -Force:$Force
533+
}
478534
}
479535

480536
if ($Exclude -notcontains 'DataCollector') {
@@ -547,6 +603,9 @@ function Start-DbaMigration {
547603
}
548604
}
549605
end {
606+
if ($dacOpened) {
607+
$null = $sourceServerDac | Disconnect-DbaInstance -WhatIf:$false
608+
}
550609
if (Test-FunctionInterrupt) { return }
551610
$totaltime = ($elapsed.Elapsed.toString().Split(".")[0])
552611
Write-Message -Level Verbose -Message "SQL Server migration complete."

tests/Start-DbaMigration.Tests.ps1

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ Describe $CommandName -Tag UnitTests {
1313
$expectedParameters += @(
1414
"Source",
1515
"Destination",
16+
"Credential",
1617
"DetachAttach",
1718
"Reattach",
1819
"BackupRestore",
@@ -33,6 +34,7 @@ Describe $CommandName -Tag UnitTests {
3334
"KeepCDC",
3435
"KeepReplication",
3536
"Continue",
37+
"ExcludePassword",
3638
"Force",
3739
"AzureCredential",
3840
"MasterKeyPassword",

0 commit comments

Comments
 (0)