【问题标题】:SMO restore of SQL database doesn't overwriteSQL 数据库的 SMO 还原不会覆盖
【发布时间】:2011-01-07 15:49:27
【问题描述】:

我正在尝试使用 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."
}

【问题讨论】:

  • 我不熟悉 SMO,但我发现了这个 (sqldbatips.com/showarticle.asp?ID=40) 用于进行恢复的示例代码。也许将您的代码与此进行比较。我注意到你说的是“$true”而不是“true”......不确定这是否是问题所在。
  • $true 是布尔 true 的正确 PowerShell 表示形式。

标签: sql-server-2008 powershell smo database-restore


【解决方案1】:

我遇到了同样的问题,我正在尝试从同一服务器但名称不同的备份中恢复数据库。 我已经分析了恢复过程,它没有添加具有不同文件名的“with move”。这就是为什么它会在数据库不存在时恢复数据库,但当它存在时失败。 .PhysicalFileName 属性存在问题。

【讨论】:

    【解决方案2】:

    我正在执行 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"
    

    【讨论】:

      【解决方案3】:

      就像您从 T-SQL 执行此操作一样,如果有东西在使用数据库,那么这将阻止还原。每当我的任务是恢复数据库时,我喜欢先将其脱机(立即回滚)。这会杀死与数据库的任何连接。您可能必须先将其重新设置为在线;我不记得恢复是否足够聪明,可以意识到您正在覆盖的文件是否属于您正在恢复的数据库。希望这会有所帮助。

      【讨论】:

      • 感谢您的建议。我曾想过它正在使用中,并且 sp_who2 在任何时候都没有透露数据库中的任何其他人。该服务器仅由与我坐在同一个房间的几个开发人员使用,因此我能够排除这种情况。我添加了代码以使数据库脱机以防万一。
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2020-02-09
      • 2020-02-25
      • 2011-03-29
      • 1970-01-01
      • 2017-09-26
      • 1970-01-01
      • 2018-06-02
      相关资源
      最近更新 更多