在SQL Server中还原数据库失败

时间:2011-04-27 09:20:55

标签: .net sql sql-server powershell

我编写了一个PowerShell脚本来使用lite速度控制台备份我的数据库。

在此过程中,将从相关的xml文件中读取各种配置。

现在我想恢复它们,所以我再次使用lite速度恢复它。

但它给我一个错误

  

RESTORE DATABASE异常终止   数据库“AK4432_JIM1”的日志尾部尚未出现   备份。使用BACKUP LOG WITH   NORECOVERY备份日志,如果它   包含你不想失去的工作。   使用WITH REPLACE或WITH STOPAT   RESTORE语句的子句   只是覆盖了内容   日志中。

它说必须备份日志。

备份日志会引发此错误(我为什么要备份日志?)

  

“'C:\ Users \ ak4432 \ Desktop \ PS \ Backup2'附近的语法错误。
  关键字'with'附近的语法不正确。如果这种说法很常见   表表达式,xmlnamespaces子句或更改跟踪   context子句,前一个语句必须以a结尾   分号“。
  在C:\ Users \ ak4432 \ Desktop \ PS \ BackUpAndRollBackScript.ps1:49   焦炭:29
      + $ cmd.ExecuteNonQuery<<<< ()
          + CategoryInfo:未指定:(:) [],
  MethodInvocationException
          + FullyQualifiedErrorId:DotNetMethodException

DB的恢复模型是Full或BULK_LOGGED

我附上我的.ps脚本供您参考

function Get-ScriptDirectory
{
  $Invocation = (Get-Variable MyInvocation -Scope 1).Value
  Split-Path $Invocation.MyCommand.Path
}

function SendEmail($to, $subject, $body, $from, $attachLogFilePath,$attachErrorFilePath) 
{
  $to= "egalitarian@xyz.com"
  send-mailmessage -from $from  -to $to -subject $subject -body $body  -smtpServer "zsserver3.zs.local" -Attachments $attachLogFilePath,$attachErrorFilePath
}

function PutDbOffline($connectionString,$databaseName,$logFilePath,$dbBackUpFolder,$serverName,$processName, $processPath, $processArguments, $onError, $backup)
{
  # connect to Db and then get the DB offline 
  $connection = new-object System.Data.SqlClient.SqlConnection($connectionString)
  $connection.open()
  $sqlQuery = "USE MASTER; EXEC sp_dboption N`'" + $databaseName + "`' , N`'offline`', N`'true`'"
  $cmd = new-object "System.Data.SqlClient.SqlCommand" ($sqlQuery, $connection)
  $cmd.ExecuteNonQuery()
  $connection.close()
}

function Restore($connectionString,$databaseName,$logFilePath,$dbBackUpFolder,$serverName,$processName, $processPath, $processArguments, $onError, $backup)
{
   $combinedProcessPath= Join-Path $processPath $processName

   #dump the output to a log file
   $logFileName =  $processName + $databaseName
   $logFileName+= "_"
   $logFileName += "{0:MMddyyyy-HH mm}" -f (Get-Date) 
   $combinedLogFilePath = Join-Path ($logFilePath) ($logFileName)
   $combinedErrorLogFilePath = $combinedLogFilePath + "_error"
   $dbBackUpFile = $databaseName + ".BAK"
   $databaseBackUpPath = Join-Path ($dbBackUpFolder) ($dbBackUpFile)

   $processArguments =  "" 

   if($backup -eq "Yes")
   {
        $connection = new-object System.Data.SqlClient.SqlConnection($connectionString)
        $connection.open()

        $sqlQuery = "BACKUP LOG " + $databaseName + " TO N `'" + $dbBackUpFolder + "`'  WITH NORECOVERY ;" 
        $cmd = new-object "System.Data.SqlClient.SqlCommand" ($sqlQuery, $connection)
        $cmd.ExecuteNonQuery()
        $connection.close()
        $processArguments = " -S " + $serverName + " -T -B Database -D " + $databaseName + " -F `""+ $databaseBackUpPath + "`"" 
   }
   else
   {
      #  PutDbOffline $connectionString $databaseName $logFilePath $dbBackUpFolder $serverName $processName, $processPath $processArguments $onError  $backup

        $processArguments = " -S " + $serverName +  " -R  DataBase -D " + $databaseName + " -F `"" + $databaseBackUpPath + "`"" 
   }

   $process = Start-Process -PassThru -Filepath $combinedProcessPath -WorkingDirectory $processPath -ArgumentList $processArguments -RedirectStandardOutput $combinedLogFilePath -RedirectStandardError $combinedErrorLogFilePath -wait -NoNewWindow

   if ($process.ExitCode -ne 0)
   {
       $mailSubject = "[02SS Back Up Status] " + $processName + " failed on "  + $serverName
       $body = "Process Failed, Exited with Code - " + $process.ExitCode + ". See attached files for details."  

       if($onError -eq "Break")
       {
          $body = $body + " Breaking from the power shell script."
          SendEmail "" $mailSubject $body "O2SSConversion@zsassociates.com" $combinedLogFilePath  $combinedErrorLogFilePath 
          return  "FAILED"
       }
       else
       {                
          SendEmail "" $mailSubject $body "O2SSConversion@zsassociates.com" $combinedLogFilePath  $combinedErrorLogFilePath 
       }
    }
    else
    {
       $mailSubject = "[02SS Back Up Status] " + $processName + " ran successfully on "  + $serverName
       $body = "Process Successful, Exited with Code - " + $process.ExitCode + ". See attached files for details."  
       SendEmail "" $mailSubject $body "O2SSConversion@zsassociates.com" $combinedLogFilePath  $combinedErrorLogFilePath 
    }
}


# Load the XML FILE 
$sourceFile = Join-Path (Get-ScriptDirectory) ("BackUpAndRollBackConfiguration.xml")
$xDoc = new-Object System.Xml.XmlDocument
$xDoc.Load($sourceFile)

# Get settings to connect to DB  
$serverName = $xDoc.selectSingleNode("/configuration/appSettings/ServerName").get_InnerXml()
$databaseName = $xDoc.selectSingleNode("/configuration/appSettings/Database").get_InnerXml()
$userName = $xDoc.selectSingleNode("/configuration/appSettings/UserName").get_InnerXml()
$password = $xDoc.selectSingleNode("/configuration/appSettings/Password").get_InnerXml()
$logFilePath = $xDoc.selectSingleNode("/configuration/appSettings/logFilePath").get_InnerXml()
$dbBackUpFolder = $xDoc.selectSingleNode("/configuration/appSettings/DatabaseBackUpFolder").get_InnerXml()
#Create connection string
$connectionString = "server=" + $serverName + ";Database=" + $databaseName +";uid=" + $userName + ";pwd=" + $password

#Get Settings to decide whether its a RollBack or BackUp
$backup = $xDoc.selectSingleNode("/configuration/appSettings/BackUp").get_InnerXml()

#Declare an array to hold DB names .. Being populated later
$dbIdentifiers =@()

# Get the Process Parameter from File

$processName=""
$processPath=""
$processArguments=""
$onError = ""

$processes = $xDoc.selectnodes("/configuration/processes/process")
foreach ($process in $processes) {

    $processName=$process.selectSingleNode("processName").get_InnerXml()
    $processPath=$process.selectSingleNode("processPath").get_InnerXml()
    $processArguments=$process.selectSingleNode("processArguments").get_InnerXml()
    $onError = $process.selectSingleNode("OnError").get_InnerXml()    

}


if($backup -eq "No")
{
$returnType = Restore $connectionString $databaseName $logFilePath $dbBackUpFolder $serverName $processName $processPath $processArguments $onError $backup
if ($returnType -eq "FAILED")
{
break
}
}

#Migrate the Master Db And Scn Dbs Now

# Connect to Db and then get the SCN Db Identifier

            $Table = new-object System.Data.DataTable
            $sqlConn = new-object System.Data.SqlClient.SqlConnection($connectionString)
            $sqlConn.open()
            $adapter = new-object System.Data.SqlClient.SqlDataAdapter("SELECT DBIDENTIFIER FROM SCENARIOS",$sqlConn)
            $adapter.Fill($Table)
            $sqlConn.close()
            # Populate the db Identifer Array to include  master Db and SCN Db.
            if($backup -eq "Yes")
            {
              $dbIdentifiers += , $databaseName
            }
            foreach ($row in $Table) 
            {
             $dbIdentifiers+= , $row.DBIDENTIFIER
            }


            foreach ($dbIdentifier in $dbIdentifiers) {
            if($processPath)
            {

            $returnType =  Restore $connectionString $dbIdentifier $logFilePath $dbBackUpFolder $serverName $processName $processPath $processArguments $onError $backup
            if ($returnType -eq "FAILED")
            {
                break
            }
            }
}

有人可以帮助我解决问题,因为我的思绪现在已经停止了工作

2 个答案:

答案 0 :(得分:1)

  

它说必须备份日志。 (我为什么要备份日志?)

这是一项安全功能。 SQL Server认为您使用同一数据库的过去备份覆盖实时生产数据库,因此它希望您首先备份日志尾部以捕获自上次事务日志备份以来发生的任何事务。

这是instructions from Microsoft on backing up the tail of the log.

您也可以通过首先删除数据库然后恢复,或者在恢复中使用WITH REPLACE来避免这种情况,这会告诉SQL Server您完全覆盖了该数据库。

答案 1 :(得分:0)

如果要备份到文件,请使用正确的语法:

BACKUP LOG dbname TO DISK='path\to\filename' WITH NORECOVERY

但是,如果您不再需要当前数据,则实际上不需要备份日志(这就是错误消息所说的内容)。您只需要向WITH REPLACE提供RESTORE选项,它将替换现有的日志和数据文件。