Powershell 比较对象输出每项 1 行

Powershell compare-object output 1 line per item

我正在尝试放置比较对象的输出。我是 Powershell 的新手,不幸的是还不知道来龙去脉。

我的命令如下:

Compare-Object -referenceObject $(Get-Content "c:\temp\mek3-first.txt") -differenceObject $(Get-Content "c:\temp\mek3-second.txt") | %{$_.Inputobject} | sort-object | out-file "c:\temp\mek\results.txt"

我的文件内容如下(简单比较Windows服务):

systemname name                                         state   startmode
---------- ----                                         -----   ---------
D7MCYP     AdobeARMservice                              Stopped Auto     
D7MCYP     AdobeFlashPlayerUpdateSvc                    Stopped Manual   
D7MCYP     AeLookupSvc                                  Stopped Manual   

我的比较对象结果如下:

BL3C4V     wudfsvc                                      Stopped Auto
BL3C4V     wudfsvc                                      Stopped Manual   
D7MCYP     AdobeARMservice                              Running Auto     
D7MCYP     AdobeARMservice                              Stopped Auto     

现在,如果有人可以帮助输出以将每个服务器的前 2 列和第 3,4 列的不同值保留到新列 (5,6)。如果我也能拿到头衔就好了。例如:

Server      Service             Before State    Before Mode     After State  After Mode
BL3C4V      wudfsvc             Stopped         Auto            Stopped         Manual
D7MCYP      AdobeARMservice     Running         Auto            Stopped         Auto     

注意:下面的代码是将纯文本数据解析为对象以实现更健壮、灵活处理的练习
然而,理想情况下,处理应该对象而不是纯文本开始, 这就是为什么 PowerShell cmdlets 开始,例如 Get-Service 而不是 外部实用程序 的文本输出更可取。

假设每个输入文件中的所有条目在相应的其他文件中都有一个匹配的服务器+服务名称条目:

$f1, $f2 = "c:\temp\mek3-first.txt", "c:\temp\mek3-second.txt"
Compare-Object (Get-Content $f1) (Get-Content $f2) | ForEach-Object {
    $i = 0; $ht = @{}; $vals = -split $_.InputObject
    foreach($col in 'Server', 'Service', 'State', 'Mode') {
      $ht.$col = $vals[$i++]
    }
    $ht.Before = $_.SideIndicator -eq '<='
    [pscustomobject] $ht
  } | Group-Object Server, Service | ForEach-Object {
      $ndxBefore, $ndxAfter = if ($_.Before) { 0, 1 } else { 1, 0 }
      [pscustomobject] @{
        Server = $_.Group[0].Server
        Service = $_.Group[0].Service
        'State Before' = $_.Group[$ndxBefore].State
        'Mode Before' = $_.Group[$ndxBefore].Mode
        'State After' = $_.Group[$ndxAfter].State
        'Mode After' = $_.Group[$ndxAfter].Mode
      }
    } | Sort-Object Server, Service |
      Format-Table

注:

  • 以上格式化输出以供显示(使用 Format-Table),而不将其发送到文件。
    您可以附加 | Out-File "c:\temp\mek\results.txt" 以将相同的表示形式保存到文件中。

  • 但是注意命令-在Format-Table应用之前-returnsobjects具有单独的属性,因此您可以输出到各种格式的文件,例如使用 Export-Csv

示例输出:

Server Service                   State Before Mode Before State After Mode After
------ -------                   ------------ ----------- ----------- ----------
D7MCYP AdobeFlashPlayerUpdateSvc Stopped      Manual      Stopped     Auto      
D7MCYP AeLookupSvc               Stopped      Manual      Started     Manual    

说明:

使用单个长流水线,使代码简洁且节省内存。
管道分解如下:

  • 比较:

    • Compare-Object 比较由 Get-Content 调用返回的两个输入文件的行数组,并输出 [pscustomobject] 个代表 差异的实例 找到,字符串 属性 .SideIndicator 表示手边的行(可通过 .InputObject 访问)是否对 LHS(第一个输入文件)- <= - 或RHS(第二个输入文件)- >=
  • 转换为自定义对象:

    • 传递给ForEach-Object的脚本块({ ... })针对每个输入对象(表示为$_)执行。

    • -split $_.InputObject 通过空格将手头的 "difference line" 拆分为字段,并将结果字段作为数组存储在 $vals.

    • $ht是一个辅助哈希table,用于将字段值映射到字段名称。

    • $ht.Before 添加一个布尔值条目以指示手头的差异行是否来自 "before file"(第一个输入文件)。

    • [pscustomobject] $ht 转换辅助。 hashtable 到自定义 object 中并输出(通过管道发送)。

  • 分组:

    • Group-Object 用于通过共享 ServerService 属性 值对生成的对象进行分组,从而产生一个 [Microsoft.PowerShell.Commands.GroupInfo] 实例来表示每个分组.
  • 转换为组合自定义对象:

    • 同样,ForEach-Object用于执行每个输入对象处理。

    • [pscustomobject] @{ ... } 用于构造每个组合输出对象,再次使用辅助散列table.

    • $_.Group 包含形成每个组的输入对象 - 在我们的例子中,$_.Group[0]$_.Group[1] 是表示一个转换为对象的输入行给定服务器服务组合。

    • 根据定义,两个输入对象具有相同的 .Server.Service 值,因此盲目地使用 $_.Group[0] 的组合输出对象的值就可以了.

    • 相比之下,* Before* After 属性是适当的输入对象(无论是来自第一个文件还是第二个文件),这就是为什么数组索引 $ndxBefore$ndxAfter 被相应地选择,通过先前添加的 .Before 属性

  • 排序:

    • Sort-Object 按指定的属性对生成的对象进行排序。
  • 输出格式:

    • 输出格式化 cmdlet Format-Table 确保排序的对象显示为 table.