【问题标题】:Copy SQL Server database with PowerShell script使用 PowerShell 脚本复制 SQL Server 数据库
【发布时间】:2018-08-06 14:55:25
【问题描述】:

我想在同一台服务器中复制数据库以使用下面的代码创建一个测试数据库,但它在第一次运行时运行良好,然后发生错误。我认为这是目标数据库名称的问题,因为我更改了目的地的名称也可以。如何在不重命名目的地的情况下继续覆盖目的地数据库。

 Import-Module SQLPS -DisableNameChecking

        #your SQL Server Instance Name
        $SQLInstanceName = "DESKTOP-444"
        $Server  = New-Object -TypeName Microsoft.SqlServer.Management.Smo.Server -ArgumentList $SQLInstanceName

        #provide your database name which you want to copy
        $SourceDBName   = "test"

        #create SMO handle to your database
        $SourceDB = $Server.Databases[$SourceDBName]

        #create a database to hold the copy of your source database
        $CopyDBName = "$($SourceDBName)_copy"
        $CopyDB = New-Object -TypeName Microsoft.SqlServer.Management.SMO.Database -ArgumentList $Server , $CopyDBName

    $CopyDB.Create()

    #Use SMO Transfer Class by specifying source database
    #you can specify properties you want either brought over or excluded, when the copy happens
    $ObjTransfer   = New-Object -TypeName Microsoft.SqlServer.Management.SMO.Transfer -ArgumentList $SourceDB
    $ObjTransfer.CopyAllTables = $true
    $ObjTransfer.Options.WithDependencies = $true
    $ObjTransfer.Options.ContinueScriptingOnError = $true
    $ObjTransfer.DestinationDatabase = $CopyDBName
    $ObjTransfer.DestinationServer = $Server.Name
    $ObjTransfer.DestinationLoginSecure = $true
    $ObjTransfer.CopySchema = $true

    #if you wish to just generate the copy script
    #just script out the transfer
    $ObjTransfer.ScriptTransfer()

    #When you are ready to bring the data and schema over,
    #you can use the TransferData method
    $ObjTransfer.TransferData()

【问题讨论】:

  • 第一次运行后出现什么错误?
  • Exception lors de l'appel de «TransferData» avec «0» 参数:«传输数据时发生错误。有关详细信息,请参阅内部异常。» Au caractère Ligne:22 : 1 + $ObjTransfer.TransferData() + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + CategoryInfo : NotSpecified: (:) [], MethodInvocationException + FullyQualifiedErrorId : TransferException

标签: sql-server powershell


【解决方案1】:

我能够多次运行您的代码而没有任何问题。以下是稍微清理过的版本(结构变化):

Import-Module SQLPS -DisableNameChecking

$SQLInstanceName = "(local)"
$SourceDBName   = "sandbox"
$CopyDBName = "${SourceDBName}_copy"

$Server  = New-Object -TypeName 'Microsoft.SqlServer.Management.Smo.Server' -ArgumentList $SQLInstanceName
$SourceDB = $Server.Databases[$SourceDBName]
$CopyDB = New-Object -TypeName 'Microsoft.SqlServer.Management.SMO.Database' -ArgumentList $Server , $CopyDBName
$CopyDB.Create()

$ObjTransfer   = New-Object -TypeName Microsoft.SqlServer.Management.SMO.Transfer -ArgumentList $SourceDB
$ObjTransfer.CopyAllTables = $true
$ObjTransfer.Options.WithDependencies = $true
$ObjTransfer.Options.ContinueScriptingOnError = $true
$ObjTransfer.DestinationDatabase = $CopyDBName
$ObjTransfer.DestinationServer = $Server.Name
$ObjTransfer.DestinationLoginSecure = $true
$ObjTransfer.CopySchema = $true

$ObjTransfer.ScriptTransfer()
$ObjTransfer.TransferData()

你遇到了什么错误?

我注意到的一件事。如果克隆的数据库已经存在,脚本将失败。您应该在 $CopyDB.Create() 语句周围出现异常,并且在您将对象复制到克隆数据库时可能还会出现另一个异常。

如果数据库存在,我会删除它,或者如果存在则中止脚本执行。

【讨论】:

  • 感谢您的回答,但此错误仍然存​​在 Exception lors de l'appel de «TransferData» avec «0» argument(s): «传输数据时发生错误。有关详细信息,请参阅内部异常。» Au caractère Ligne:22 : 1 + $ObjTransfer.TransferData() + ~~~~~~~~~~~~~~~~~~~~~~~~~~~ + CategoryInfo : NotSpecified: (:) [], MethodInvocationException + FullyQualifiedErrorId : TransferException
【解决方案2】:

编辑

有人告诉我使用模块 SqlServer 而不是模块 SQLPS,因为后者早已被弃用。在我进行更改后,我立即注意到现在可以从 Microsoft.SqlServer.Management.SMO.Transfer 对象创建数据库,而我以前没有管理过该对象。我不明白为什么,甚至可能无关,我只是幸运。 SqlServer包可以通过以下命令安装:

Install-Module -Name SqlServer -AllowClobber

因此,我正在使用工作代码更新我的答案,它比我之前的答案(在这篇文章的底部)更具可读性、更优雅和更高效。

$SQLInstanceName = $env:servername
$SourceDBName = $env:databasename
$SQLUser = $env:adminlogin
$SQLPassword = $env:adminPassword

Import-Module SqlServer -DisableNameChecking
[System.Reflection.Assembly]::LoadWithPartialName("Microsoft.SqlServer.Smo") | Out-Null;

Function IsNullOrEmpty([string]$val){
    if ($val -eq $null -or $val -eq '') { $true }
    else{ $false }
}

If (IsNullOrEmpty($SQLInstanceName)) {
    $SQLInstanceName = $args[0]
}

If (IsNullOrEmpty($SourceDBName)) {
    $SourceDBName = $args[1]
}

If (IsNullOrEmpty($SQLUser)) {
    $SQLUser = $args[2]
}

If (IsNullOrEmpty($SQLPassword)) {
    $SQLPassword = $args[3]
}


Try {
    $Server = New-Object Microsoft.SqlServer.Management.Smo.Server($SQLInstanceName)

    $DestinationDBName = "${SourceDBName}.Staging"
    $SQLSecurePassword = ConvertTo-SecureString $SQLPassword -AsPlainText -Force

    $Server.ConnectionContext.LoginSecure = $false
    $Server.ConnectionContext.set_Login($SQLUser)
    $Server.ConnectionContext.set_SecurePassword($SQLSecurePassword)

    $SourceDB = $Server.Databases[$SourceDBName]
    $ObjTransfer = New-Object Microsoft.SqlServer.Management.SMO.Transfer ($SourceDB)

    $CopyDB = New-Object Microsoft.SqlServer.Management.SMO.Database ($Server, $DestinationDBName)
    $CopyDB.Create()


    # $ObjTransfer.CopyData = $false  - Uncomment this line so that data is not copied across
    $ObjTransfer.CopySchema = $true
    $ObjTransfer.CopyAllTables = $true
    $ObjTransfer.CopyAllDatabaseTriggers = $true
    $ObjTransfer.Options.WithDependencies = $true  
    $ObjTransfer.Options.ContinueScriptingOnError = $true  
    $ObjTransfer.DestinationDatabase = $DestinationDBName  
    $ObjTransfer.DestinationServer = $SQLInstanceName
    $ObjTransfer.DestinationPassword = $SQLPassword
    $ObjTransfer.DestinationLogin = $SQLUser
    $ObjTransfer.DestinationLoginSecure = $false
    $ObjTransfer.TransferData()
}
Catch [System.Exception] {
    # $_ is set to the ErrorRecord of the exception
    if ($_.Exception.InnerException) {
        Write-Error $_.Exception.InnerException.Message
    } else {
        Write-Error $_.Exception.Message
    }

    if($Server.Databases.Name -like $DestinationDBName) {
        Write-Host "Dropping cloned database..."

        # Call drop-db.ps1 to delete the stagingDB
        Invoke-Command { .\drop-db.ps1 $SQLInstanceName $DestinationDBName $SQLUser $SQLPassword }
    }
}
Finally {
    if($Server) {
        $Server.ConnectionContext.Disconnect()
    }
}

我在实现这个时遇到了类似的错误。从字面上尝试了一切,它就是行不通。对我有用的是通过ScriptTransfer 方法生成脚本,创建新数据库,然后通过Invoke-SqlCmd 将脚本应用于新数据库。我分享的代码可以在本地调用,方法是按以下顺序向脚本传递 4 个参数:

  1. 服务器名称
  2. 数据库名称
  3. 登录
  4. 密码

它也可以用在管道上。我通过setting those 4 arguments through a group variable 在 Azure DevOps 上使用它。

我将.Staging 附加到源数据库名称,这就是我给新数据库的名称。如果在此过程中出现问题,我会删除新数据库,以防它已经创建。

$SQLInstanceName = $env:servername
$SourceDBName = $env:databasename
$SQLUser = $env:adminlogin
$SQLPassword = $env:adminPassword

Import-Module SQLPS -DisableNameChecking
[System.Reflection.Assembly]::LoadWithPartialName("Microsoft.SqlServer.Smo") | Out-Null;

Function IsNullOrEmpty([string]$val){
    if ($val -eq $null -or $val -eq '') { $true }
    else{ $false }
}

If (IsNullOrEmpty($SQLInstanceName)) {
    $SQLInstanceName = $args[0]
}

If (IsNullOrEmpty($SourceDBName)) {
    $SourceDBName = $args[1]
}

If (IsNullOrEmpty($SQLUser)) {
    $SQLUser = $args[2]
}

If (IsNullOrEmpty($SQLPassword)) {
    $SQLPassword = $args[3]
}

Try {
    $Server = New-Object Microsoft.SqlServer.Management.Smo.Server($SQLInstanceName)
}
Catch [System.Exception] {
    # $_ is set to the ErrorRecord of the exception
    if ($_.Exception.InnerException) {
        Write-Error $_.Exception.InnerException.Message
    } else {
        Write-Error $_.Exception.Message
    }
}
Finally {

    Try {
        $StagingDBName      = "${SourceDBName}.Staging"
        $SQLSecurePassword  = ConvertTo-SecureString $SQLPassword -AsPlainText -Force

        $Server.ConnectionContext.LoginSecure = $false
        $Server.ConnectionContext.set_Login($SQLUser)
        $Server.ConnectionContext.set_SecurePassword($SQLSecurePassword)

        $CreationScriptOptions = New-Object Microsoft.SqlServer.Management.SMO.ScriptingOptions
        $CreationScriptOptions.ExtendedProperties= $true
        $CreationScriptOptions.DRIAll= $true
        $CreationScriptOptions.Indexes= $true
        $CreationScriptOptions.Triggers= $true            $CreationScriptOptions.ScriptBatchTerminator = $true
        $CreationScriptOptions.IncludeHeaders = $true;
        $CreationScriptOptions.ToFileOnly = $true
        $CreationScriptOptions.IncludeIfNotExists = $true     
        $SourceDB = $Server.Databases[$SourceDBName]
        $ObjTransfer = New-Object Microsoft.SqlServer.Management.SMO.Transfer ($SourceDB)
        $ObjTransfer.options=$CreationScriptOptions # tell the transfer object of our preferences

        $FilePath = Join-Path $PSScriptRoot "$($StagingDBName).sql"
        $ObjTransfer.Options.Filename = $FilePath; 
        $ObjTransfer.ScriptTransfer()

        $CopyDB = New-Object Microsoft.SqlServer.Management.SMO.Database ($Server, $StagingDBName)
        $CopyDB.Create()

        $auth=@{UserName=$SQLUser;Password=$SQLPassword}
        Invoke-SqlCmd -InputFile $FilePath -ServerInstance $Server -Database $StagingDBName @Auth -Verbose
    }
    Catch [System.Exception] {
        # $_ is set to the ErrorRecord of the exception
        if ($_.Exception.InnerException) {
            Write-Error $_.Exception.InnerException.Message
        } else {
            Write-Error $_.Exception.Message
        }

        if($Server.Databases.Name -like $StagingDBName) {
            Write-Host "Dropping staging database..."

            $auth=@{UserName=$SQLUser;Password=$SQLPassword}
            Invoke-SqlCmd -ServerInstance $Server @Auth `
                -Query "IF EXISTS (SELECT name FROM master.dbo.sysdatabases WHERE name ='$($StagingDBName)') `
                            BEGIN `
                                ALTER DATABASE [$($StagingDBName)] SET SINGLE_USER WITH ROLLBACK IMMEDIATE; `
                                DROP DATABASE [$($StagingDBName)]; `
                            END;" `
                -Verbose
        }
    }
    Finally {
        $Server.ConnectionContext.Disconnect()
    }
}

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-01-29
    • 1970-01-01
    • 2023-04-05
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多