【问题标题】:Powershell invoke-sqlcmd Printing The Wrong OutputPowershell invoke-sqlcmd 打印错误的输出
【发布时间】:2021-12-17 07:25:52
【问题描述】:

我有一个按预期运行的 SQL 查询,但是当我尝试在 PowerShell 'Invoke-SqlCmd' 模块中使用它时,输出的结果与查询数据库时不同。我注意到关于这个模块有很多问题,但我找不到适用于我的情况的问题。

查询:

    $SQLServer = "localhost"
    $query = "SELECT Groups.[Name] AS AGname FROM sys.dm_hadr_availability_group_states States INNER JOIN master.sys.availability_groups Groups ON States.group_id = Groups.group_id WHERE primary_replica = @@Servername"

    $HAGName = Invoke-Sqlcmd  -query $query -ServerInstance $SQLServer -Database 'database' 

    if ($HAGName = !$null) {
        
        write-host "Availability group name is $HAGName"
        exit 0
    }
    else {

        write-host "Failed to retrieve High Availability group name = [$HAGName]"
        exit 1
    }

PowerShell 中的输出: 'Availability group name is True'

就像我提到的,当直接查询 SQL Server 时,我得到了正确的输出。我尝试使用“OutputAs”开关,但没有帮助。

任何帮助将不胜感激。

【问题讨论】:

  • 如果没有返回行,您似乎更不理解Invoke-SqlCmd 返回NULL;那不是真的。如果$query 的值是SELECT name FROM sys.databases WHERE 1 = 0;,那么$HAGName = !$null 仍然是TRUE。
  • 请注意,您所做的是作业,我认为您的意思是$HAGName -ne $null,但Larnu 的评论仍然适用。
  • @Larnu,无论如何我都不是一个 SQL 人,这是我从公司的高级 DBA 那里得到的查询,所以我倾向于认为它应该是可靠的。您能否详细说明您认为命令失败的原因?
  • -not $nullTrue 并且您将其分配给变量 $HAGName 正如其他人之前评论的那样。将if ($HAGName = !$null) { 替换为if ($null -ne $HAGName) {

标签: sql-server powershell invoke-sqlcmd


【解决方案1】:

所有的指针都在问题的cmet中,但让我系统地分解一下:

  • !$null 总是 $true 在 PowerShell 中:! / -notlogical NOT operator$null 强制转换为布尔值,并且因为 [bool] $null$false , ! $null$true

  • $HAGName = !$null,由于使用了=assignment operator,因此将$true赋值给变量$HAGName

因此,您打算使用$null -eq $HAGName(将$null 放在LHS 上,以确保稳健性 - 请参阅the docs)。

但是,鉴于 PowerShell 的隐式到布尔强制规则(请参阅 this answer 的底部部分),您可以在这种情况下简化为 if ($HAGName) { ... }

因此,更多 PowerShell 惯用的代码重新表述是:

$SQLServer = 'localhost'
$query = 'SELECT Groups.[Name] AS AGname FROM sys.dm_hadr_availability_group_states States INNER JOIN master.sys.availability_groups Groups ON States.group_id = Groups.group_id WHERE primary_replica = @@Servername'

$HAGName = Invoke-Sqlcmd -Query $query -ServerInstance $SQLServer -Database database

if ($HAGName) {
    Write-Verbose -Verbose "Availability group name is: "
    # Output the System.Data.DataRow instance as-is,
    # which also results in proper for-display formatting.
    # If you just want the value of the .AGname property (column), use
    #  $HAGName.AGname instead.
    $HAGName 
    exit 0
}
else {
    Write-Warning "Failed to retrieve High Availability group name."
    exit 1
}

注意:

  • 成功案例隐式将结果输出到成功输出流

    • Write-Host is typically the wrong tool to use,除非意图是仅写入显示器,绕过成功输出流,并能够将输出发送到其他命令,将其捕获到变量中或重定向它到一个文件。要输出一个值,请单独使用它;例如,$value 而不是 Write-Host $value(或使用 Write-Output $value,尽管这很少需要);见this answer

    • 我使用了Write-Verbose 调用(默认情况下它的输出是安静的,这里我使用-Verbose 来强制它显示)来提供可选补充/状态信息。

    • $HAGName 现在(隐式地)输出Invoke-SqlCmd 调用返回的[System.Data.DataRow] 实例原样,这也会导致正确的显示格式 - 这样的实例不 在可扩展(内插字符串)中使用时有意义地字符串化;他们无济于事地字符串化到他们的类型名称,即逐字逐句System.Data.DataRow

      • 但是,如果您访问行的特定属性(列),则其值可能有意义地字符串化,具体取决于数据类型;在您的情况下:`"可用性组名称是 $($HAGName.AGname)"
      • 要在字符串中包含常用的显示格式 - 使用类似 "Availability group name is $($HAGName | Out-String)" 的内容

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2018-07-15
    • 1970-01-01
    • 2019-06-21
    • 2016-01-15
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多