Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
20 changes: 16 additions & 4 deletions public/Invoke-DbaAdvancedRestore.ps1
Original file line number Diff line number Diff line change
Expand Up @@ -122,15 +122,20 @@ function Invoke-DbaAdvancedRestore {
Provides more granular control than timestamp-based recovery for critical business operations.

.PARAMETER StopBefore
Stops the restore operation just before the specified StopMark rather than after it.
Use this when you need to exclude a particular marked transaction from the restored database.
Only effective when used in combination with the StopMark parameter for mark-based recovery scenarios.
Stops the restore operation just before the specified StopMark or StopAtLsn rather than after it.
Use this when you need to exclude a particular marked transaction or LSN from the restored database.
Only effective when used in combination with the StopMark or StopAtLsn parameter.

.PARAMETER StopAfterDate
DateTime value specifying that only StopMark occurrences after this date should be considered for restore termination.
Use this when the same mark name appears multiple times in your transaction log backups.
Ensures the restore stops at the correct instance of the mark when identical mark names exist at different times.

.PARAMETER StopAtLsn
Log Sequence Number (LSN) in the transaction log at which to stop the restore operation.
Use this for precise point-in-time recovery to an exact LSN, which provides more granular control than timestamp-based recovery.
The LSN value can be obtained from sys.fn_dblog, backup headers, or error logs. Combine with -StopBefore to stop just before the specified LSN.

.PARAMETER Checksum
Enables backup checksum verification during restore operations. Forces the restore to verify backup checksums and fail if checksums are not present.
Use this to ensure backup files contain checksums and validate them during restore, following backup best practices.
Expand Down Expand Up @@ -245,6 +250,7 @@ function Invoke-DbaAdvancedRestore {
[switch]$StopBefore,
[string]$StopMark,
[datetime]$StopAfterDate,
[string]$StopAtLsn,
[switch]$Checksum,
[switch]$Restart,
[switch]$EnableException
Expand Down Expand Up @@ -329,7 +335,13 @@ function Invoke-DbaAdvancedRestore {
} else {
$restore.NoRecovery = $False
}
if (-not [string]::IsNullOrEmpty($StopMark)) {
if (-not [string]::IsNullOrEmpty($StopAtLsn)) {
if ($StopBefore -eq $True) {
$restore.StopBeforeMarkName = "lsn:$StopAtLsn"
} else {
$restore.StopAtMarkName = "lsn:$StopAtLsn"
}
} elseif (-not [string]::IsNullOrEmpty($StopMark)) {
if ($StopBefore -eq $True) {
$restore.StopBeforeMarkName = $StopMark
if ($null -ne $StopAfterDate) {
Expand Down
21 changes: 19 additions & 2 deletions public/Restore-DbaDatabase.ps1
Original file line number Diff line number Diff line change
Expand Up @@ -166,7 +166,7 @@ function Restore-DbaDatabase {
Use this for log shipping secondary servers or when you need read-only access during restore operations.
The directory must exist and be writable by the SQL Server service account for undo file creation.

.PARAMETER StorageCredential
.PARAMETER StorageCredential
Specifies the SQL Server credential name for authenticating to Azure blob storage or S3-compatible object storage during restore operations.
Use this when restoring from Azure blob storage or S3 backups that require authentication.
For Azure: The credential must contain valid Azure storage account keys or SAS tokens.
Expand Down Expand Up @@ -240,11 +240,16 @@ function Restore-DbaDatabase {
Marked point in the transaction log to stop the restore at (Mark is created via BEGIN TRANSACTION (https://docs.microsoft.com/en-us/sql/t-sql/language-elements/begin-transaction-transact-sql?view=sql-server-ver15)).

.PARAMETER StopBefore
Switch to indicate the restore should stop before StopMark occurs, default is to stop when mark is created.
Switch to indicate the restore should stop before StopMark or StopAtLsn occurs, default is to stop when mark/LSN is reached.

.PARAMETER StopAfterDate
By default the restore will stop at the first occurence of StopMark found in the chain, passing a datetime where will cause it to stop the first StopMark atfer that datetime.

.PARAMETER StopAtLsn
Log Sequence Number (LSN) in the transaction log at which to stop the restore operation.
Use this for precise point-in-time recovery to an exact LSN, which provides more granular control than timestamp-based recovery.
The LSN value can be obtained from sys.fn_dblog, backup headers, or error logs. Combine with -StopBefore to stop just before the specified LSN.

.PARAMETER Checksum
Enables backup checksum verification during restore operations. Forces the restore to verify backup checksums and fail if checksums are not present.
Use this to ensure backup files contain checksums and validate them during restore, following backup best practices.
Expand Down Expand Up @@ -435,6 +440,16 @@ function Restore-DbaDatabase {

Restores the backups from \\ServerName\ShareName\File as database, stops before the first 'OvernightStart' mark that occurs after '21:00 10/05/2020'.

.EXAMPLE
PS C:\> Restore-DbaDatabase -SqlInstance server1 -Path \\ServerName\ShareName\File -DatabaseName database -StopAtLsn '00000030:00000f28:0001'

Restores the backups from \\ServerName\ShareName\File as database, stopping when the specified LSN is reached.

.EXAMPLE
PS C:\> Restore-DbaDatabase -SqlInstance server1 -Path \\ServerName\ShareName\File -DatabaseName database -StopAtLsn '00000030:00000f28:0001' -StopBefore

Restores the backups from \\ServerName\ShareName\File as database, stopping just before the specified LSN is reached.

Note that Date time needs to be specified in your local SQL Server culture

.EXAMPLE
Expand Down Expand Up @@ -522,6 +537,7 @@ function Restore-DbaDatabase {
[switch]$StopBefore,
[string]$StopMark,
[datetime]$StopAfterDate = (Get-Date '01/01/1971'),
[string]$StopAtLsn,
[int]$StatementTimeout = 0,
[parameter(ParameterSetName = "Restore")][parameter(ParameterSetName = "RestorePage")][switch]$Checksum,
[parameter(ParameterSetName = "Restore")][parameter(ParameterSetName = "RestorePage")][switch]$Restart
Expand Down Expand Up @@ -916,6 +932,7 @@ function Restore-DbaDatabase {
StopMark = $StopMark
StopAfterDate = $StopAfterDate
StopBefore = $StopBefore
StopAtLsn = $StopAtLsn
ExecuteAs = $ExecuteAs
Checksum = $Checksum
Restart = $Restart
Expand Down
1 change: 1 addition & 0 deletions tests/Invoke-DbaAdvancedRestore.Tests.ps1
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@ Describe $CommandName -Tag UnitTests {
"StopAfterDate",
"Checksum",
"Restart",
"StopAtLsn",
"EnableException"
)
Compare-Object -ReferenceObject $expectedParameters -DifferenceObject $hasParameters | Should -BeNullOrEmpty
Expand Down
20 changes: 18 additions & 2 deletions tests/Restore-DbaDatabase.Tests.ps1
Original file line number Diff line number Diff line change
Expand Up @@ -64,7 +64,8 @@ Describe $CommandName -Tag UnitTests {
"ExecuteAs",
"Checksum",
"Restart",
"NoXpDirRecurse"
"NoXpDirRecurse",
"StopAtLsn"
)
Compare-Object -ReferenceObject $expectedParameters -DifferenceObject $hasParameters | Should -BeNullOrEmpty
}
Expand Down Expand Up @@ -901,7 +902,7 @@ use master
}


Context -Skip "Test restoring with StopAt and StopAfterDate" {
Context -Skip "Test restoring with StopAt, StopAtLsn and StopAfterDate" {
BeforeAll {
$null = Get-DbaDatabase -SqlInstance $TestConfig.InstanceSingle -ExcludeSystem -EnableException | Remove-DbaDatabase -EnableException
}
Expand All @@ -913,6 +914,21 @@ use master
$sqlOut.ms | Should -Be 29876
$null = Remove-DbaDatabase -SqlInstance $TestConfig.InstanceSingle -Database StopAt2
}

It "Should have stoped at lsn" {
$dbName = "TestStopAtLsn_$(Get-Random)"
$null = New-DbaDatabase -SqlInstance $TestConfig.InstanceSingle -Name $dbName
$fullBackup = Backup-DbaDatabase -SqlInstance $TestConfig.InstanceSingle -Database $dbName -Path $backupPath
Invoke-DbaQuery -SqlInstance $TestConfig.InstanceSingle -Database $dbName -Query "CREATE TABLE Test (id int IDENTITY)"
1..5 | ForEach-Object -Process { Invoke-DbaQuery -SqlInstance $TestConfig.InstanceSingle -Database $dbName -Query "INSERT INTO Test DEFAULT VALUES" }
$lsn = Invoke-DbaQuery -SqlInstance $TestConfig.InstanceSingle -Database $dbName -Query "SELECT MAX([Current LSN]) FROM sys.fn_dblog(NULL, NULL)" -As SingleValue
1..5 | ForEach-Object -Process { Invoke-DbaQuery -SqlInstance $TestConfig.InstanceSingle -Database $dbName -Query "INSERT INTO Test DEFAULT VALUES" }
$logBackup = Backup-DbaDatabase -SqlInstance $TestConfig.InstanceSingle -Database $dbName -Path $backupPath -Type Log
$null = Restore-DbaDatabase -SqlInstance $TestConfig.InstanceSingle -Path $fullBackup.Path, $logBackup.Path -DatabaseName $dbName -StopAtLsn "0x$lsn" -WithReplace
$id = Invoke-DbaQuery -SqlInstance $TestConfig.InstanceSingle -Database $dbName -Query "SELECT MAX(id) FROM Test" -As SingleValue
$id | Should -Be 5
$null = Remove-DbaDatabase -SqlInstance $TestConfig.InstanceSingle -Database $dbName
}
}


Expand Down
Loading