SMO восстановление базы данных SQL не перезаписывает - PullRequest
3 голосов
/ 07 января 2011

Я пытаюсь восстановить базу данных из файла резервной копии с помощью SMO. Если база данных еще не существует, она работает нормально. Однако, если база данных уже существует, я не получаю ошибок, но база данных не перезаписывается.

Процесс «восстановления» по-прежнему занимает столько же времени, поэтому, похоже, он работает и выполняет восстановление, но в итоге база данных не изменилась.

Я делаю это в Powershell, используя SMO. Код немного длинный, но я включил его ниже. Вы заметите, что я установил $restore.ReplaceDatabase = $true. Кроме того, я использую блок try-catch и сообщаю о любых ошибках (надеюсь), но они не возвращаются.

Есть ли очевидные ошибки? Возможно ли, что я не сообщаю о какой-то ошибке, и она скрыта от меня?

Спасибо за любую помощь или совет, который вы можете дать!

function Invoke-SqlRestore {
    param(
        [string]$backup_file_name,
        [string]$server_name,
        [string]$database_name,
        [switch]$norecovery=$false
    )

    # Get a new connection to the server
    [Microsoft.SqlServer.Management.Smo.Server]$server = New-SMOconnection -server_name $server_name
    Write-Host "Starting restore to $database_name on $server_name."

    Try {
        $backup_device = New-Object("Microsoft.SqlServer.Management.Smo.BackupDeviceItem") ($backup_file_name, "File")

        # Get local paths to the Database and Log file locations
        If ($server.Settings.DefaultFile.Length -eq 0) {$database_path = $server.Information.MasterDBPath }
        Else { $database_path = $server.Settings.DefaultFile}
        If ($server.Settings.DefaultLog.Length -eq 0 ) {$database_log_path = $server.Information.MasterDBLogPath }
        Else { $database_log_path = $server.Settings.DefaultLog}

        # Load up the Restore object settings
        $restore = New-Object Microsoft.SqlServer.Management.Smo.Restore
        $restore.Action = 'Database'
        $restore.Database = $database_name
        $restore.ReplaceDatabase = $true

        if ($norecovery.IsPresent) { $restore.NoRecovery = $true }
        Else { $restore.Norecovery = $false }

        $restore.Devices.Add($backup_device)

        # Get information from the backup file
        $restore_details = $restore.ReadBackupHeader($server)
        $data_files = $restore.ReadFileList($server)

        # Restore all backup files
        ForEach ($data_row in $data_files) {
            $logical_name = $data_row.LogicalName
            $physical_name = Get-FileName -path $data_row.PhysicalName

            $restore_data = New-Object("Microsoft.SqlServer.Management.Smo.RelocateFile")
            $restore_data.LogicalFileName = $logical_name

            if ($data_row.Type -eq "D") {
                # Restore Data file
                $restore_data.PhysicalFileName = $database_path + "\" + $physical_name
            }
            Else {
                # Restore Log file
                $restore_data.PhysicalFileName = $database_log_path + "\" + $physical_name
            }
            [Void]$restore.RelocateFiles.Add($restore_data)
        }

        $restore.SqlRestore($server)

        # If there are two files, assume the next is a Log
        if ($restore_details.Rows.Count -gt 1) {
            $restore.Action = [Microsoft.SqlServer.Management.Smo.RestoreActionType]::Log
            $restore.FileNumber = 2
            $restore.SqlRestore($server)
        }
    }
    Catch {
        $ex = $_.Exception
        Write-Output $ex.message
        $ex = $ex.InnerException
        while ($ex.InnerException) {
            Write-Output $ex.InnerException.message
            $ex = $ex.InnerException
        }
        Throw $ex
    }
    Finally {
        $server.ConnectionContext.Disconnect()
    }
    Write-Host "Restore ended without any errors."
}

Ответы [ 3 ]

4 голосов
/ 17 февраля 2011

У меня та же проблема, я пытаюсь восстановить базу данных из резервной копии, взятой с того же сервера, но с другим именем.Я профилировал процесс восстановления, и он не добавляет 'with move' с разными именами файлов.Вот почему он восстановит базу данных, когда база данных не существует, но потерпит неудачу, когда она существует.Проблема со свойством .PhysicalFileName.

3 голосов
/ 02 ноября 2012

Я делал восстановление SMO и столкнулся с ошибками. Единственный способ диагностики проблемы - запуск профиля SQL во время выполнения моего сценария powershell.

Это показало мне фактический T-SQL, который выполнялся. Затем я скопировал это в запрос и попытался выполнить. Это показало мне реальные ошибки: в моем случае в моей базе данных было несколько файлов данных, которые нужно было переместить.

Прикрепленный скрипт работает для баз данных, которые имеют только один файл данных.

Param
(
[Parameter(Mandatory=$True)][string]$sqlServerName,
[Parameter(Mandatory=$True)][string]$backupFile,
[Parameter(Mandatory=$True)][string]$newDBName
)

       # Load assemblies
        [System.Reflection.Assembly]::LoadWithPartialName("Microsoft.SqlServer.SMO") | Out-Null
        [System.Reflection.Assembly]::LoadWithPartialName("Microsoft.SqlServer.SmoExtended") | Out-Null
        [Reflection.Assembly]::LoadWithPartialName("Microsoft.SqlServer.ConnectionInfo") | Out-Null
        [Reflection.Assembly]::LoadWithPartialName("Microsoft.SqlServer.SmoEnum") | Out-Null
        # Create sql server object

        $server = New-Object ("Microsoft.SqlServer.Management.Smo.Server") $sqlServerName
        # Copy database locally if backup file is on a network share

        Write-Host "Loaded assemblies"

        $backupDirectory = $server.Settings.BackupDirectory
        Write-Host "Backup Directory:" $backupDirectory

        $fullBackupFile = $backupDirectory + "\" + $backupFile

        Write-Host "Copy DB from: " $fullBackupFile


       # Create restore object and specify its settings
        $smoRestore = new-object("Microsoft.SqlServer.Management.Smo.Restore")
        $smoRestore.Database = $newDBName
        $smoRestore.NoRecovery = $false;
        $smoRestore.ReplaceDatabase = $true;
        $smoRestore.Action = "Database" 

        Write-Host "New Database name:" $newDBName

        # Create location to restore from
        $backupDevice = New-Object("Microsoft.SqlServer.Management.Smo.BackupDeviceItem") ($fullBackupFile, "File")
        $smoRestore.Devices.Add($backupDevice)

        # Give empty string a nice name
        $empty = ""

        # Specify new data file (mdf)
        $smoRestoreDataFile = New-Object("Microsoft.SqlServer.Management.Smo.RelocateFile")
        $defaultData = $server.DefaultFile
        if (($defaultData -eq $null) -or ($defaultData -eq $empty))
        {
            $defaultData = $server.MasterDBPath
        }

        Write-Host "defaultData:" $defaultData

        $smoRestoreDataFile.PhysicalFileName = Join-Path -Path $defaultData -ChildPath ($newDBName + "_Data.mdf")

        Write-Host "smoRestoreDataFile.PhysicalFileName:" $smoRestoreDataFile.PhysicalFileName

        # Specify new log file (ldf)
        $smoRestoreLogFile = New-Object("Microsoft.SqlServer.Management.Smo.RelocateFile")
        $defaultLog = $server.DefaultLog
        if (($defaultLog -eq $null) -or ($defaultLog -eq $empty))
        {
            $defaultLog = $server.MasterDBLogPath
        }
        $smoRestoreLogFile.PhysicalFileName = Join-Path -Path $defaultLog -ChildPath ($newDBName + "_Log.ldf")

        Write-Host "smoRestoreLogFile:" $smoRestoreLogFile.PhysicalFileName

        # Get the file list from backup file
        $dbFileList = $smoRestore.ReadFileList($server)

        # The logical file names should be the logical filename stored in the backup media
        $smoRestoreDataFile.LogicalFileName = $dbFileList.Select("Type = 'D'")[0].LogicalName
        $smoRestoreLogFile.LogicalFileName = $dbFileList.Select("Type = 'L'")[0].LogicalName
        # Add the new data and log files to relocate to
        $smoRestore.RelocateFiles.Add($smoRestoreDataFile)
        $smoRestore.RelocateFiles.Add($smoRestoreLogFile)

        # Restore the database
        $smoRestore.SqlRestore($server)

        "Database restore completed successfully"
0 голосов
/ 10 января 2011

Также как если вы делаете это из T-SQL, если что-то использует базу данных, это заблокирует восстановление.Всякий раз, когда мне поручается восстановить базу данных, я предпочитаю сначала отключить ее (с немедленным откатом).Это убивает любые связи с БД.Возможно, вам придется сначала включить его в сети;Я не помню, достаточно ли уместно восстановление, чтобы понять, что перезаписываемые файлы принадлежат базе данных, которую вы восстанавливаете, или нет.Надеюсь, это поможет.

...