@@ -93,6 +93,11 @@ function Copy-DbaDatabase {
9393 Sets source databases to read-only before migration to prevent data changes during the process.
9494 Use this to ensure data consistency when databases must remain accessible at the source during migration.
9595
96+ . PARAMETER SetSourceOffline
97+ Sets source databases offline before migration to prevent any connections during the process.
98+ Use this to ensure complete isolation when databases must be completely inaccessible at the source during migration.
99+ When combined with -Reattach, databases are brought back online after being reattached to the source.
100+
96101 . PARAMETER ReuseSourceFolderStructure
97102 Maintains the exact file path structure from the source instance on the destination.
98103 Use this when destination servers have identical drive layouts or when preserving specific organizational folder structures.
@@ -130,10 +135,6 @@ function Copy-DbaDatabase {
130135 Use this to distinguish migrated databases (e.g., 'DEV_' prefix for development copies).
131136 Cannot be used together with -NewName parameter.
132137
133- . PARAMETER SetSourceOffline
134- Sets source databases to offline status after successful migration.
135- Use this for cutover scenarios where source databases should be unavailable after migration.
136-
137138 . PARAMETER KeepCDC
138139 Preserves Change Data Capture (CDC) configuration and data during migration.
139140 Use this when destination databases need to maintain CDC tracking for auditing or replication.
@@ -258,6 +259,9 @@ function Copy-DbaDatabase {
258259 [parameter (ParameterSetName = " DbBackup" )]
259260 [parameter (ParameterSetName = " DbAttachDetach" )]
260261 [switch ]$SetSourceReadOnly ,
262+ [parameter (ParameterSetName = " DbBackup" )]
263+ [parameter (ParameterSetName = " DbAttachDetach" )]
264+ [switch ]$SetSourceOffline ,
261265 [Alias (" ReuseFolderStructure" )]
262266 [parameter (ParameterSetName = " DbBackup" )]
263267 [parameter (ParameterSetName = " DbAttachDetach" )]
@@ -276,7 +280,6 @@ function Copy-DbaDatabase {
276280 [switch ]$KeepCDC ,
277281 [parameter (ParameterSetName = " DbBackup" )]
278282 [switch ]$KeepReplication ,
279- [switch ]$SetSourceOffline ,
280283 [string ]$NewName ,
281284 [string ]$Prefix ,
282285 [switch ]$Force ,
@@ -1172,6 +1175,7 @@ function Copy-DbaDatabase {
11721175 }
11731176
11741177 $sourceDbReadOnly = $sourceServer.Databases [$dbName ].ReadOnly
1178+ $sourceDbOffline = $sourceServer.Databases [$dbName ].Status -like " *Offline*"
11751179
11761180 if ($SetSourceReadOnly ) {
11771181 If ($Pscmdlet.ShouldProcess ($source , " Set $dbName to read-only" )) {
@@ -1184,6 +1188,18 @@ function Copy-DbaDatabase {
11841188 }
11851189 }
11861190
1191+ if ($SetSourceOffline -and $DetachAttach ) {
1192+ # For DetachAttach, set offline before detach to kill connections
1193+ If ($Pscmdlet.ShouldProcess ($source , " Set $dbName to offline" )) {
1194+ Write-Message - Level Verbose - Message " Setting database to offline."
1195+ try {
1196+ $result = Set-DbaDbState - SqlInstance $sourceServer - Database $dbName - Offline - EnableException - Force
1197+ } catch {
1198+ Stop-Function - Continue - Message " Couldn't set database to offline. Aborting routine for this database" - ErrorRecord $_
1199+ }
1200+ }
1201+ }
1202+
11871203 if ($BackupRestore ) {
11881204 if ($UseLastBackup ) {
11891205 $whatifmsg = " Gathering last backup information for $dbName from $Source and restoring"
@@ -1235,6 +1251,17 @@ function Copy-DbaDatabase {
12351251 $backupCollection += $backupTmpResult
12361252 }
12371253 }
1254+
1255+ # For BackupRestore, set source offline after backup completes but before restore
1256+ if ($SetSourceOffline ) {
1257+ Write-Message - Level Verbose - Message " Setting source database $dbName to offline after backup."
1258+ try {
1259+ $null = Set-DbaDbState - SqlInstance $sourceServer - Database $dbName - Offline - EnableException - Force
1260+ } catch {
1261+ Stop-Function - Continue - Message " Couldn't set database to offline after backup. Aborting routine for this database" - ErrorRecord $_
1262+ }
1263+ }
1264+
12381265 Write-Message - Level Verbose - Message " Reuse = $ReuseSourceFolderStructure ."
12391266 try {
12401267 $msg = $null
@@ -1305,6 +1332,16 @@ function Copy-DbaDatabase {
13051332 }
13061333 }
13071334
1335+ if ($SetSourceOffline ) {
1336+ If ($Pscmdlet.ShouldProcess ($destServer.Name , " Set $dbName to online after source was set to offline" )) {
1337+ try {
1338+ $null = Set-DbaDbState - SqlInstance $destServer - Database $dbName - Online - EnableException - Force
1339+ } catch {
1340+ Stop-Function - Message " Couldn't set $dbName to online on $ ( $destserver.Name ) " - ErrorRecord $_
1341+ }
1342+ }
1343+ }
1344+
13081345 $dbFinish = Get-Date
13091346 if ($NoRecovery -eq $false ) {
13101347 If ($Pscmdlet.ShouldProcess ($destServer.Name , " Setting db owner to $dbowner for $destinationDbName " )) {
@@ -1361,6 +1398,14 @@ function Copy-DbaDatabase {
13611398 Stop-Function - Message " Couldn't set database to read-only" - ErrorRecord $_
13621399 }
13631400 }
1401+
1402+ if ($SetSourceOffline -or $sourceDbOffline ) {
1403+ try {
1404+ $result = Set-DbaDbState - SqlInstance $sourceServer - Database $dbName - Offline - EnableException - Force
1405+ } catch {
1406+ Stop-Function - Message " Couldn't set database to offline" - ErrorRecord $_
1407+ }
1408+ }
13641409 Write-Message - Level Verbose - Message " Successfully reattached $dbName to $source ."
13651410 } else {
13661411 Write-Message - Level Verbose - Message " Could not reattach $dbName to $source ."
@@ -1463,12 +1508,6 @@ function Copy-DbaDatabase {
14631508 $copyDatabaseStatus | Select-DefaultView - Property DateTime, SourceServer, DestinationServer, Name, Type, Status, Notes - TypeName MigrationObject
14641509 }
14651510
1466- if ($SetSourceOffline -and $copyDatabaseStatus.Status -eq " Successful" -and $sourceServer.databases [$dbName ].status -notlike ' *offline*' ) {
1467- if ($Pscmdlet.ShouldProcess ($source , " Setting $dbName offline" )) {
1468- Set-DbaDbState - SqlInstance $sourceServer - Database $dbName - Offline - Force
1469- }
1470- }
1471-
14721511 $dbTotalTime = $dbFinish - $dbStart
14731512 $dbTotalTime = ($dbTotalTime.ToString ().Split(" ." )[0 ])
14741513
0 commit comments