Powershell invoke-sqlcmd 打印错误的输出

Posted

技术标签:

【中文标题】Powershell invoke-sqlcmd 打印错误的输出【英文标题】:Powershell invoke-sqlcmd Printing The Wrong Output 【发布时间】: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) 【参考方案1】:

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

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

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

要改为执行相等比较,请使用-eq,equality operator。

因此,您打算使用$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)" 的内容

【讨论】:

以上是关于Powershell invoke-sqlcmd 打印错误的输出的主要内容,如果未能解决你的问题,请参考以下文章

Powershell invoke-sqlcmd 打印错误的输出

Invoke-sqlcmd 等待恢复完成,然后再进行下一个任务

PowerShell-将CSV导入SQL Server

Invoke-SqlCmd 缩短结果

如何使用 Invoke-Sqlcmd 连接到 SQL Server LocalDB?

确保所有invoke-sqlcmd 命令都发生在同一个事务中?