如何使用Powershell Restore-SqlDatabase cmdlet可靠地覆盖现有数据库

时间:2015-04-27 06:44:35

标签: sql powershell sql-server-2012

我有这个cmdlet来恢复数据库,如果没有使用现有数据库的话,它可以正常工作。

Restore-SqlDatabase -ServerInstance $databaseServerInstance -Database $database -BackupFile $backupLocation -ReplaceDatabase

但是当数据库正在使用时,覆盖失败:

  

System.Data.SqlClient.SqlError:无法获取独占访问权限   因为数据库正在使用中

我无法弄清楚是否有一种简单的方法(通过参数)来覆盖它并终止连接或将数据库置于单用户模式。有这样的事吗?或者我是否必须切换到SMO来执行比基本恢复更复杂的事情?

我现在正在使用SMO API的解决方法首先删除数据库,但如果可能的话,我希望简化这个。

$srv = new-object Microsoft.SqlServer.Management.Smo.Server($databaseServerInstance)

# If the database exists then drop it otherwise Restore-SqlDatabase may fail if connections are open to it
if ($srv.Databases[$database] -ne $null)
{
    $srv.KillAllProcesses($database)
    $srv.KillDatabase($database)
}


Restore-SqlDatabase -ServerInstance $databaseServerInstance -Database $database -BackupFile $backupLocation -ReplaceDatabase

3 个答案:

答案 0 :(得分:5)

我正在使用Invoke-SqlCmd。 Invoke-SqlCmd是sqlps模块的一部分,您可以从here下载

Push-Location; 
Import-Module sqlps -DisableNameChecking; 
Pop-Location

$serverPath = "SQLSERVER:\SQL\localhost\Default"
$databaseName = "YOUR_DATABASE"
$restoreFrom = join-path (Get-Location) "$databaseName-before.bak"

$databasePath = join-path $serverPath "Databases\$databaseName"
if(Test-Path $databasePath)
{
    Invoke-SqlCmd "USE [master]; ALTER DATABASE [$databaseName] SET  SINGLE_USER WITH ROLLBACK IMMEDIATE; DROP DATABASE [$databaseName]"
}

Restore-SqlDatabase -Path $serverPath -Database $databaseName -BackupFile $restoreFrom

您可以在此处找到有关如何使用Invoke-SqlCmd的更多信息:

Effectively Using Invoke-SqlCmd

SQL SERVER – FIX – The term ‘Invoke-Sqlcmd’ is not recognized as the name of a cmdlet

答案 1 :(得分:0)

多年后我遇到了同样的问题,但想留在 SMO。解决方案是使用 MS 页面 here 上记录的 TerminationClause Enum。 终止枚举用于行:

$db.alter(1)

并使用:

0 --> (default) FailOnOpenTransactions
1 --> RollbackTransactionsImmediately

完整的解决方案如下所示:

$Instance = 'localhost'
$dbName = 'DB_I_Want_To_Restore'

$server = New-Object ('Microsoft.SqlServer.Management.Smo.Server') ($Instance)
$db = $server.Databases | ? {$_.Name -eq $dbName}

$db.useraccess = 'Single'
$server.KillAllProcesses($db)
$db.alter(1)                                      

Restore-SqlDatabase -ServerInstance $Instance -Database $dbName -BackupFile 'location_of_your_backup_file'

答案 2 :(得分:-1)

将数据库设置为single user mode并回滚任何现有事务。这是通过像这样的Tsql语句完成的,

ALTER DATABASE MyDatabase SET SINGLE_USER WITH ROLLBACK IMMEDIATE;

正如您已经在使用它,为什么不在执行还原之前删除数据库?

USE master; -- or some other db than the one you are going to drop
DROP DATABASE MyDatabase;

另一种方法是restore the database使用WITH REPLACE选项。