2011-01-07 24 views
3

我試圖使用SMO從備份文件還原數據庫。如果數據庫不存在,那麼它工作正常。但是,如果數據庫已經存在,那麼我不會發生錯誤,但數據庫不會被覆蓋。SQL數據庫的SMO還原不會覆蓋

「恢復」過程仍然需要很長時間,所以看起來它正在工作並進行恢復,但最終數據庫並沒有改變。

我在使用SMO的PowerShell中執行此操作。代碼有點長,但我已經將其包含在下面。你會注意到我確實設置了$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." 
} 
+0

我不熟悉SMO,但是我發現這個(http://www.sqldbatips.com/showarticle.asp?ID=40)用於恢復的示例代碼。也許比較你的代碼與此。我注意到你說的是「$ true」而不是「true」......不知道這是否是問題所在。 – IamIC

+1

$ true是布爾值true的正確PowerShell表示形式。 –

回答

4

我有同樣的問題,我試圖恢復從同一臺服務器採取的數據庫,但使用不同的名稱。 我已經對配置文件進行了配置,並且不會將'with move'添加到不同的文件名中。這就是爲什麼當數據庫不存在時它會恢復數據庫,但是當它失敗時會失敗。 .PhysicalFileName屬性存在問題。

0

就像如果你從T-SQL做到這一點,如果有什麼使用數據庫,那麼這將阻止恢復。無論何時我負責恢復數據庫,我都希望首先使其脫機(立即回滾)。這殺死了任何連接到數據庫。您可能必須先將其重新在線;我不記得恢復是否足夠聰明,可以意識到您覆蓋的文件屬於您正在恢復的數據庫。希望這可以幫助。

+0

感謝您的建議。我曾考慮過它正在使用,sp_who2在任何時候都沒有透露數據庫中的其他人。服務器僅由與我坐在同一個房間內的幾位開發人員使用,所以我能夠排除這一點。儘管如此,我已經添加了代碼以使數據庫脫機。 –

3

我正在做SMO恢復並出現錯誤。我發現診斷問題的唯一方法是在執行我的powershell腳本期間運行SQL配置文件。

這給我看到了正在執行的實際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"