Powershell:在多个SQL Server上创建存储过程

时间:2019-02-13 12:57:54

标签: sql-server powershell sql-server-2014

我不时地下载一些脚本(总是在相同的程序包中包含或多或少的相同文件)。我编写了一个powershell脚本,用于下载master.zip,解压缩,将文件复制到其他位置,然后进行清理。

现在,我想在所有服务器上运行.sql文件,因此服务器上始终具有最新版本。

我写了这个powershell脚本

Function Install-BrentFirstResponderKit
{
    param(
        $server= @("server1","server2")
    )
    $path = "$env:USERPROFILE\AppData\Roaming\Microsoft\SQL Server Management Studio\14.0\Templates\Sql\_Monitoring\Brent"
    $onlyFiles = ("sp_Blitz.sql","sp_BlitzCache.sql","sp_BlitzFirst.sql","sp_BlitzIndex.sql","sp_BlitzLock.sql","sp_BlitzWho.sql", "sp_TEST")
    $files = Get-ChildItem $path\* -Include $onlyFiles

    # Credentials to access SQL-Server
    $credential = Get-Credential -username myadmin -Message "Credentials"
    $username  = $credential.UserName
    $password  = $credential.Password
    $password.MakeReadOnly()
    $creds = New-Object System.Data.SqlClient.SqlCredential($username, $password)

    # Create SQL Connection Object
    $SqlConnection = New-Object System.Data.SqlClient.SqlConnection

    foreach($srv in $server)
    {
        # Open SQL connection
        $SqlConnection.ConnectionString = "Server=$srv; Database=master; Integrated Security=false"
        $SqlConnection.Credential = $creds
        $SqlConnection.Open()

        # Execute SQL Statement 
        $SqlCmd = New-Object System.Data.SqlClient.SqlCommand
        $SqlCmd.CommandTimeout = 0

        foreach($file in $files)
        {
            $SqlCmd.CommandText = Get-Content $file -Raw    
            $SqlCmd.Connection = $SqlConnection
            $sqlcmd.ExecuteScalar()
        }
        $sqlConnection.Close()
    }
}

运行powershell脚本时,出现以下错误:

  

Ausnahme beim Aufrufen von“ ExecuteScalar” mit 0参数:   “'CREATE / ALTER PROCEDURE'必须是查询中的第一条语句   批”。在Zeile:1 Zeichen:1   + $ sqlcmd.ExecuteScalar()   + ~~~~~~~~~~~~~~~~~~~~~~~       + CategoryInfo:未指定:(:) [],MethodInvocationException       + FullyQualifiedErrorId:SqlException

还是这个错误,取决于我运行的文件:

  

Ausnahme beim Aufrufen von“ ExecuteScalar” mit 0参数:   “关键字'ALTER'附近的语法不正确。'CREATE/ ALTER PROCEDURE'   必须是查询批处理中的第一条语句。语法不正确   'GO'。“在Zeile:1 Zeichen:1   + $ sqlcmd.ExecuteScalar()   + ~~~~~~~~~~~~~~~~~~~~~~~       + CategoryInfo:未指定:(:) [],MethodInvocationException       + FullyQualifiedErrorId:SqlException

.sql文件的构建方式都相同:

IF OBJECT_ID('dbo.sp_TEST') IS NULL
    EXEC ('CREATE PROCEDURE dbo.sp_TEST AS RETURN 0;')
GO

ALTER PROCEDURE dbo.sp_TEST
AS
BEGIN
    Select @@Version
END
GO

虽然我了解错误消息并找到了解决方法(手动删除IF块并删除所有GO消息),但这不是我想要的。

如果我必须手动编辑文件(或者可以用$sqlcmd.SelectCommand = $sqlcmd.SelectCommand.Replace(<if-block>,'')编写脚本),也可以直接手动安装它们。

所以,我的问题是,为什么我不能运行以Create / Alter以外的其他开头的脚本?我想念什么?

感谢您的帮助。

PS:我不知道它是否可以与Invoke-SqlCmd一起使用,但是我的服务器位于不同的域中,过去,我在使用Invoke-SqlCmd时遇到了一些问题

@Aaron:如果运行Get-Content $file -Raw,我将得到以下输出结果

  

如果OBJECT_ID('dbo.sp_TEST')为NULL
EXEC(“创建过程”   dbo.sp_TEST AS RETURN 0;')
GO

     

更改过程dbo.sp_TEST
AS
开始
选择@@ Version
END
开始

这正是$sqlcmd.CommandText

的内容

编辑:关于Dan Guzmans的评论,我将代码更改为以下代码,并且现在可以正常工作:

Function Install-BrentFirstResponderKitV2
{
    param(
        [string[]]$server= @("server1","server2")
    )

[System.Reflection.Assembly]::LoadWithPartialName('Microsoft.SqlServer.SMO') | Out-Null

    #alle dateien finden, welche installiert werden sollen
    $path = "$env:USERPROFILE\AppData\Roaming\Microsoft\SQL Server Management Studio\14.0\Templates\Sql\_Monitoring\Brent"
    $onlyFiles = ("sp_Blitz.sql","sp_BlitzCache.sql","sp_BlitzFirst.sql","sp_BlitzIndex.sql","sp_BlitzLock.sql","sp_BlitzWho.sql","sp_TEST.sql")
    $files = Get-ChildItem $path\* -Include $onlyFiles

    # Credentials für den Zugriff auf die SQL Server einlesen
    $credential = Get-Credential -username myadmin -Message "Credentials"

    foreach($srv in $server)
    {
        $x = $sqlConnection = New-Object Microsoft.SqlServer.Management.Smo.Server $srv
        $x.ConnectionContext.LoginSecure = $false
        $x.ConnectionContext.set_Login($credential.username)
        $x.ConnectionContext.set_SecurePassword($credential.password)
        $x.ConnectionContext.Connect()

        foreach($file in $files)
        {
            Invoke-Sqlcmd -Database master -Query $(Get-Content $file -Raw) -ServerInstance $x -Username $credential.UserName -Password $credential.GetNetworkCredential().Password
        }
        $x.ConnectionContext.Disconnect()
    }
}

0 个答案:

没有答案