【问题标题】:AzureSQL Multiple Invoke-SQLCmd Loop and Connection ErrorsAzure SQL 多次调用-SQLCmd 循环和连接错误
【发布时间】:2018-10-22 06:39:49
【问题描述】:

我正在尝试通过 Azure 自动化循环调用多个 AzureSQL 数据库的调用 sqlcmd。循环中的第一项执行,但其余的都失败了:

Invoke-Sqlcmd : 发生与网络相关或特定于实例的错误 在建立与 SQL Server 的连接时。服务器没有 找到或无法访问。验证实例名称是否正确 并且 SQL Server 配置为允许远程连接。 (提供者:命名管道提供者,错误:40 - 无法打开 连接到 SQL Server)

我猜我需要在执行下一个之前从第一个 invoke-sqlcmd 关闭连接,但还没有找到直接的方法来使用 invoke-sqlcmd 完成此操作。这是我的循环:

param(      
# Parameters to Pass to PowerShell Scripts
[parameter(Mandatory=$true)][String] $azureSQLServerName = "myazuresql",        
[parameter(Mandatory=$true)][String] $azureSQLCred = "myazureautosqlcred"        
        )

# DB Name Array
$dbnamearray = @("database1","database2","database3")
$dbnamearray

# Datatable Name
$tabName = "RunbookTable"

#Create Table object
$table = New-Object system.Data.DataTable "$tabName"

#Define Columns
$col1 = New-Object system.Data.DataColumn dbname,([string])

#Add the Columns
$table.columns.add($col1)

# Add Row and Values for dname Column
ForEach ($db in $dbnamearray) 
{
$row = $table.NewRow()
$row.dbname = $db
#Add the row to the table
$table.Rows.Add($row)
}

#Display the table
$table | format-table -AutoSize

# Loop through the datatable using the values per column 
$table | ForEach-Object {

# Set loop variables as these are easier to pass then $_.
$azureSQLDatabaseName = $_.dbname

# Execute SQL Query Against Azure SQL
$azureSQLServerName = $azureSQLServerName + ".database.windows.net"
$Cred = Get-AutomationPSCredential -Name $azureSQLCred
$SQLOutput = $(Invoke-Sqlcmd -ServerInstance $azureSQLServerName -Username $Cred.UserName -Password $Cred.GetNetworkCredential().Password -Database $azureSQLDatabaseName -Query "SELECT * FROM INFORMATION_SCHEMA.TABLES " -QueryTimeout 65535 -ConnectionTimeout 60 -Verbose) 4>&1
Write-Output $SQLOutput
}

【问题讨论】:

  • 先看看这个链接link
  • 我的第一个 sql 命令调用有效。连接可能仍处于打开状态,因此循环中的第二次和后续尝试失败
  • 要控制打开/关闭连接,您应该使用 System.Data.SqlClient 并使用 SqlConnection.Open()SqlConnection.Close()
  • 如何在它们之间调用invoke-sqlcmd?这是 AzureSQL,所以我的 invoke-sqlcmd 需要服务器和数据库名称,所以 connection.open 似乎是双重连接

标签: powershell azure-sql-database azure-automation invoke-sqlcmd


【解决方案1】:

您可以尝试将每个连接设为powershell job。这解决了我前段时间遇到的一个非常相似的问题。 Send-MailMessage closes every 2nd connection when using attachments如果你想阅读解释。基本上,如果您无法使用 .Close() 方法,则可以强制通过终止每次运行的整个会话来关闭连接。在理想情况下,cmdlet 会为您处理所有这些,但并非所有内容都是完美创建的。

# Loop through the datatable using the values per column 
$table | ForEach-Object {

# Set loop variables as these are easier to pass then $_.
$azureSQLDatabaseName = $_.dbname

# Execute SQL Query Against Azure SQL
$azureSQLServerName = $azureSQLServerName + ".database.windows.net"
$Cred = Get-AutomationPSCredential -Name $azureSQLCred

# Pass in the needed parameters via -ArgumentList and start the job.
Start-Job -ScriptBlock { Write-Output $(Invoke-Sqlcmd -ServerInstance $args[0] -Username $args[1].UserName -Password $args[1].GetNetworkCredential().Password -Database $args[0] -Query "SELECT * FROM INFORMATION_SCHEMA.TABLES " -QueryTimeout 65535 -ConnectionTimeout 60 -Verbose) 4>&1 } -ArgumentList $azureSQLServerName, $Cred | Wait-Job | Receive-Job

}

这是未经测试的,因为我没有要连接的服务器,但也许通过一些工作你可以从中获得一些东西。

【讨论】:

  • 我得到一个在模块“SqlServer”中找到“Invoke-Sqlcmd”命令,但无法加载该模块
  • 奇怪的错误,因为这听起来像是执行策略的事情。您可能必须在作业开始时导入模块。所以,-ScriptBlock { Import-Module sqlserver; Write-Output ...
  • 还要确保你的执行策略是通用设置的——比如,只需打开任何旧窗口,看看你是否可以在不进行任何其他更改的情况下执行Invoke-Sqlcmd。这基本上就是这项工作正在做的事情。如果这不起作用,您必须更改执行策略。
  • 谢谢。我将 SQL 版本更新为 21.0.17262 并解决了错误,但是....它仅在循环中的第一项上执行
  • 你能在你的帖子中包含 $table 的内容吗?您是否有可能在第二次迭代中创建与不同服务器的连接?如果是这样,你能独立建立这种联系吗?
【解决方案2】:

我之前在使用 azure sql 数据库时遇到了同样的问题。你可以试试这个

1。创建自动化帐户

New-AzureRmAutomationAccount -ResourceGroupName $resourceGroupName -Name $automationAccountName -Location $location

2。设置要使用的自动化帐户

Set-AzureRmAutomationAccount -Name $automationAccountName -ResourceGroupName $resourceGroupName

3。创建/导入 Runbook

在这里,我们已经准备好运行手册,因此我们将其导入。这是运行手册代码

workflow runbookNameValue
{
    inlinescript
    {
        $MasterDatabaseConnection = New-Object System.Data.SqlClient.SqlConnection
        $MasterDatabaseConnection.ConnectionString = "ConnectionStringValue"

        # Open connection to Master DB
        $MasterDatabaseConnection.Open()

        # Create command
        $MasterDatabaseCommand = New-Object System.Data.SqlClient.SqlCommand
        $MasterDatabaseCommand.Connection = $MasterDatabaseConnection
        $MasterDatabaseCommand.CommandText = "Exec stored procedure"

        # Execute the query
        $MasterDatabaseCommand.ExecuteNonQuery()

        # Close connection to Master DB
        $MasterDatabaseConnection.Close() 
    }
}

4。导入

Import-AzureRMAutomationRunbook -Name $runBookName -Path $scriptPath -ResourceGroupName $resourceGroupName -AutomationAccountName $automationAccountName -Type PowerShell

我希望这会有所帮助。而不是使用 Invoke-Sqlcmd 使用 $MasterDatabaseCommand.ExecuteNonQuery() 就像我在运行手册中提供的那样。它会工作

【讨论】:

  • 我看到了关于这个的博客。感谢您传递它。您能否举例说明 ConnectionStringValue 和 Exec 存储过程中的内容?这对我来说在 ExecuteNonQuery 上失败了
  • connectionString="Server=(mydb.windows.net);Database=mydb;Integrated Security=True;"
【解决方案3】:

您似乎将.database.windows.net 附加到服务器名称inside 循环中。我想这就是为什么它只适用于第一次迭代。

只需移动这一行:

$azureSQLServerName = $azureSQLServerName + ".database.windows.net"

在这一行之前:

$table | ForEach-Object {

【讨论】:

  • 由于 Invoke-SQLcmd 需要服务器实例和数据库名称,我该如何解决这个问题?
  • @kode 你不能,但你绝对应该调查不同迭代之间这些变量的差异。
  • 你是对的。循环正在附加,因此每个循环都添加了一个 database.windows.net。一旦我把它放在正确的地方,它就解决了。
猜你喜欢
  • 2020-07-21
  • 1970-01-01
  • 1970-01-01
  • 2010-10-01
  • 2014-03-13
  • 1970-01-01
  • 2018-01-05
  • 2016-04-25
  • 1970-01-01
相关资源
最近更新 更多