使用 PowerShell 和 SMO 库从 .BAK 文件创建新数据库

Create new database from .BAK file using PowerShell and SMO library

我正在尝试使用 powershell 从 .bak 文件创建一个新的 SQL 服务器数据库。

这是我的脚本:

TRY
{
    [System.Reflection.Assembly]::LoadWithPartialName('Microsoft.SqlServer.SMO') | out-null 
    [System.Reflection.Assembly]::LoadWithPartialName('Microsoft.SqlServer.SmoExtended') | out-null
    $servername = "MyServer\MyServerInstance"
    $datapath= "E:\SQLData\MyNewDataBase"
    $logpath= "E:\SQLLogs\MyNewDataBase"
    $path= "\MyServer\BKPFolder\"
    $server = new-object("Microsoft.SqlServer.Management.Smo.Server") $servername
    $folderitem=Get-ChildItem $path -filter *.bak -rec

    foreach($bkfiles in $folderitem)
    {
        $dbRestore = new-object("Microsoft.SqlServer.Management.Smo.Restore")
        $files = $path+$bkfiles.Name
        $backupFile = $files
        $dbRestore.Devices.AddDevice($backupFile, [Microsoft.SqlServer.Management.Smo.DeviceType]::File)
        $dbRestoreDetails = $dbRestore.ReadBackupHeader($server)
        $dbFileList= $dbRestore.ReadFileList($server)

        foreach ($row in $dbFileList)
        {
             $FileType = $row["Type"].ToUpper()

             If ($FileType.Equals("D")) 
             {
                 $DBLogicalName = $Row["LogicalName"]
             }

             ELSEIf ($FileType.Equals("L")) 
             {
                 $LogLogicalName = $Row["LogicalName"]
             }
        }

        $dbRestoreFile = new-object("Microsoft.SqlServer.Management.Smo.RelocateFile") 
        $dbRestoreLog = new-object("Microsoft.SqlServer.Management.Smo.RelocateFile")

        $dbRestoreFile.LogicalFileName = $DBLogicalName 
        $dbRestoreFile.PhysicalFileName =$datapath +  "\" + $DBLogicalName + ".mdf" 

        $dbRestoreLog.LogicalFileName =   $LogLogicalName 
        $dbRestoreLog.PhysicalFileName =  $logpath +  "\" + $LogLogicalName + ".ldf" 

        $dbRestore.RelocateFiles.Add($dbRestoreFile) 
        $dbRestore.RelocateFiles.Add($dbRestoreLog)                

        $dbRestore.Database = "MyNewDataBase"
        $dbRestore.NoRecovery = $false
        $dbRestore.Action = "DataBase"
        $dbRestore.FileNumber = 1;
        $dbRestore.ReplaceDatabase = $false;

        $dbRestore.SqlRestore($server)  
   }
} catch     {
    "Database restore failed:`n`n " + _.Exception.GetBaseException().Message
}

当我运行这段代码时,我得到这个错误:

Directory lookup for the file "E:\SQLData\MyNewDataBase\OLDDataBase_Data.mdf" failed with the operating system error 2(The system cannot find the file specified.).

File 'OLDDataBase_Data' cannot be restored to 'E:\SQLData\MyNewDataBase\OLDDataBase_Data.mdf'. Use WITH MOVE to identify a valid location for the file.

Problems were identified while planning for the RESTORE statement. Previous messages provide details.
RESTORE DATABASE is terminating abnormally.

我的脚本似乎正在尝试从旧数据库中查找 .mdf.ldf 文件。但是我只有一个来自旧数据库的 .bak 文件。

我错过了什么?

谢谢。

希望这是您需要的:

function Restore-MsSqlDatabase {
<#
.Synopsis
  Restore MSSQL database using Microsoft.SQLServer.Management.Smo.{BackupDeviceItem,Restore,RelocateFile}
.Description
  Restore MSSQL database using Microsoft.SQLServer.Management.Smo.{BackupDeviceItem,Restore,RelocateFile}
.Example
  Restore-MsSqlDatabase -BackupFile 'D:\backups\aateam_20491005.bak' -Verbose
.Example
  Restore-MsSqlDatabase -BackupFile 'D:\backups\aateam_20491005.bak' -SqlHost SQL-SERVER001 -Verbose
#>
  [CmdletBinding()]
  Param(
    [Parameter(Position=0)] [ValidateNotNullOrEmpty()]
    [string]$BackupFile,
    [Parameter(Position=1)] [ValidateNotNullOrEmpty()]
    [string]$SqlHost="localhost"
  )
  Begin{
    Write-Verbose ("$(Get-Date) - INFO - Load assembly for Microsoft.SqlServer.SMO")
    $null=[System.Reflection.Assembly]::LoadWithPartialName("Microsoft.SqlServer.SMO")
    Write-Verbose ("$(Get-Date) - INFO - Load assembly for Microsoft.SqlServer.SMOExtended")
    $null=[System.Reflection.Assembly]::LoadWithPartialName("Microsoft.SqlServer.SMOExtended")
    Write-Verbose ("$(Get-Date) - INFO - New connection object")
    $MsSqlConnection=New-Object Microsoft.SqlServer.Management.Smo.Server $SqlHost
    Write-Verbose ("$(Get-Date) - INFO - Initialize connection")
    $null=$MsSqlConnection.Initialize()
  }
  Process{
    Try{
      Write-Verbose ("$(Get-Date) - INFO - New backup device item")
      $BackupDeviceItem=New-Object Microsoft.SQLServer.Management.Smo.BackupDeviceItem
      $BackupDeviceItem.Name=$backupFile
      $BackupDeviceItem.DeviceType="File"
      Write-Verbose ("$(Get-Date) - INFO - New restore device")
      $RestoreDevice=New-Object Microsoft.SQLServer.Management.Smo.Restore
      $RestoreDevice.Action="Database"
      $RestoreDevice.ReplaceDatabase=$true
      $RestoreDevice.NoRecovery=$false
      Write-Verbose ("$(Get-Date) - INFO - Add backup device item to restore device")
      $RestoreDevice.Devices.Add($BackupDeviceItem)
      Write-Verbose ("$(Get-Date) - INFO - Read backup header")
      $BackupHeader=$RestoreDevice.ReadBackupHeader($MsSqlConnection)
      Write-Verbose ("$(Get-Date) - INFO - Set databse name in restore device")
      $RestoreName=$BackupHeader.Rows[0].DatabaseName
      $RestoreDevice.Database=$RestoreName
      Write-Verbose ("$(Get-Date) - INFO - Read backup file list")
      $FileList=$RestoreDevice.ReadFileList($MsSqlConnection)
      Write-Verbose ("$(Get-Date) - INFO - Relocate mdf,ldf,ndf files")
      ForEach ($File in $FileList) {
        Write-Verbose ("$(Get-Date) - INFO - New relocate device")
        $RelocateFile=New-Object Microsoft.SqlServer.Management.Smo.RelocateFile
        Switch ($File.FileId) {
          1 {
            Write-Verbose ("$(Get-Date) - INFO - New physical path for mdf file")
            $NewPhysicalPath="{0}\{1}.mdf" -f $MsSqlConnection.DefaultFile,$RestoreName
          }
          2 {
            Write-Verbose ("$(Get-Date) - INFO - New physical path for ldf file")
            $NewPhysicalPath="{0}\{1}.ldf" -f $MsSqlConnection.DefaultFile,$RestoreName
          }
          Default {
            Continue
          }
        }
        Write-Verbose ("$(Get-Date) - INFO - Relocate files")
        $RelocateFile.LogicalFileName=$File.LogicalName
        $RelocateFile.PhysicalFileName=$NewPhysicalPath
        $null=$RestoreDevice.RelocateFiles.Add($RelocateFile)
      }
      Write-Verbose ("$(Get-Date) - INFO - Test if database already exists")
      If($MsSqlConnection.Databases[$RestoreName]){
        Write-Verbose ("$(Get-Date) - INFO - Kill all processes connected to database")
        $MsSqlConnection.KillAllProcesses($RestoreName)
        Write-Verbose ("$(Get-Date) - INFO - Set database offline")
        $MsSqlConnection.Databases[$RestoreName].SetOffline()
      }
      Else{
        Write-Verbose ("$(Get-Date) - INFO - Databse currently not present in SQL instance")
      }
      Write-Verbose ("$(Get-Date) - INFO - Restore device")
      $RestoreDevice.SQLRestore($MsSqlConnection)
      $MsSqlConnection.Databases.Refresh()
      Write-Verbose ("$(Get-Date) - INFO - Set database online")
      $MsSqlConnection.Databases[$RestoreName].SetOnline()
    }
    Catch{
      Write-Verbose ("$(Get-Date) - ERROR - {0}" -f $_.Exception.Message)
    }
    Finally{}
  }
  End{}
}

然后做:

Get-Help -Name Restore-MsSqlDatabase -Examples

经过大量的研究和尝试,我终于恢复了我的数据库。 这对我有用:

[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                              

    #Define o novo local dos arquivos de mdf e ldf
    $RelocateData = New-Object Microsoft.SqlServer.Management.Smo.RelocateFile("OldDataBase_Data", "E:\SQLData\MyNewDataBase_DATA.mdf")
    $RelocateLog = New-Object Microsoft.SqlServer.Management.Smo.RelocateFile("OldDataBase_Log", "E:\SQLLogs\MyNewDataBase_LOG.ldf")

    #Executa a restauração
    Restore-SqlDatabase -ServerInstance "MyServer\MyServerInstance" -Database "MyNewDataBase" -BackupFile "\BackupFolder\OldDataBase.bak" -RelocateFile @($RelocateData,$RelocateLog) -NoRecovery
    Restore-SqlDatabase -ServerInstance "MyServer\MyServerInstance" -Database "MyNewDataBase" -BackupFile "\BackupFolder\OldDataBase.trn" -RestoreAction Log -NoRecovery