首页 > 解决方案 > Powershell invoke-sqlcmd 打印错误的输出

问题描述

我有一个按预期运行的 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 中的输出: “可用性组名称为 True”

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

任何帮助将不胜感激。

标签: sql-serverpowershellinvoke-sqlcmd

解决方案


所有的指针都在问题的评论中,但让我系统地分解它:

  • !$null始终 $truePowerShell: !/-not中,逻辑 NOT 运算符强制$null转换为布尔值,并且由于[bool] $nullis $false! $nullis $true

  • $HAGName = !$null,由于使用=赋值运算符,因此赋值$true给变量$HAGName

因此,$null -eq $HAGName这就是您要使用的内容(将$null放在LHS上,以实现稳健性 - 请参阅文档)。

但是,鉴于 PowerShell 的隐式到布尔强制规则(请参阅此答案的底部部分),您可以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通常是使用错误的工具,除非意图是仅写入显示,绕过成功输出流,并且能够将输出发送到其他命令,将其捕获到变量中,或将其重定向到文件。要输出一个值,请单独使用;例如,$value代替Write-Host $value(或使用Write-Output $value,尽管很少需要);看到这个答案

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

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

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

推荐阅读