PowerShell 5.1 在这个简单的示例中我没有得到预期的输出

Rod*_*Rod 2 powershell

$res = Invoke-Sqlcmd -Query "select * from customer" -ServerInstance "(localdb)\MSSQLLocalDB" -Database "Database1" -OutputAs DataTables

$res | Where-Object FirstName -eq "John"
$res.Where({$_.FirstName -eq "John"})
Run Code Online (Sandbox Code Playgroud)

这是输出:

Id FirstName City   
-- --------- ----   
 1 John      Augusta
 1 John      Augusta
Run Code Online (Sandbox Code Playgroud)

我期待这个:

Id FirstName City   
-- --------- ----   
 1 John      Augusta

Id FirstName City   
-- --------- ----   
 1 John      Augusta
Run Code Online (Sandbox Code Playgroud)

mkl*_*nt0 5

基于有用的评论:

行为是设计使然

  • 给定脚本或单个交互式提交的命令行输出的对象全部发送到单个管道的成功输出流。

  • 当管道的输出既未捕获也未重定向时,PowerShell 会将用于显示的输出格式应用于给定管道的成功输出流中的所有输出对象,并且如果第一个输出对象隐式选择表格格式,则相同类型的所有后续对象被格式化为打印到主机(显示器、终端)的同一表格的一部分。

    • 如果后续对象属于不同类型并且它们也是[pscustomobject]实例,但具有不同的属性集,则事情会变得棘手 - 请参阅此答案以获取更多信息。

如果您想单独格式化给定命令的输出,您有三个基本选项,如果您还想选择稍后以编程方式处理输出,而不仅仅是格式化它以供显示,则所有这些选项都不是最佳选择

  • 使用以下命令将输出直接发送到主机Out-Host

    $res | Where-Object FirstName -eq "John" | Out-Host     
    
    Run Code Online (Sandbox Code Playgroud)
    • 会绕过成功输出流,这意味着无法捕获或重定向此输出。
  • 使用Format-*cmdlet,例如显式Format-Table

    $res | Where-Object FirstName -eq "John" | Format-Table
    
    Run Code Online (Sandbox Code Playgroud)
    • 这会将表示格式化指令的对象而不是原始对象发送到成功输出流,主机作为默认输出目标)正确呈现该输出流,但这些对象对于进一步的编程处理没有意义。
  • 使用Out-String(可能在调用 cmdlet 之前Format-*选择格式类型和/或控制格式的细节):

    $res | Where-Object FirstName -eq "John" | Out-String
    
    Run Code Online (Sandbox Code Playgroud)
    • 这会将单个多行字符串发送到成功输出流,其中包含与您在主机中看到的Out-Host[1]相同的表示形式,并且由于字符串始终按原样呈现,因此您将看到相同的主机输出;在编程处理中,这些字符串比 cmdlet 输出的格式化指令对象更有意义Format-*,但与原始输出对象相比仍然造成信息丢失。

[1] 不幸的是,Out-String总是在该表示形式后附加一个尾随换行符这种有问题的行为是GitHub 问题 #14444的主题。正如zett42指出的,使用Out-String -Stream避免了这个问题,尽管代价是将多行字符串表示的行单独发送到输出流;为了避免这种情况,您可以使用(... | Out-String -Stream) -join "`n"