简体   繁体   English

"如何使用 Powershell 将 cmd 行输出解析\/管道传输到对象"

[英]How to parse/pipe cmd line output using Powershell to an object

I have an *.exe that outputs this data when I run this PowerShell command:我有一个 *.exe 在运行此 PowerShell 命令时输出此数据:

& $myExe list

Where $myExe is something like C:\\Temp\\MyExe.exe and list is an argument.其中$myExe类似于C:\\Temp\\MyExe.exelist是一个参数。

List of Runbook ID on the system: 



List of services installed on the system: 

ALMService   Version: 7.0.4542.16189
AOSService   Version: 7.0.4542.16189
BIService    Version: 7.0.4542.16189
DevToolsService  Version: 7.0.4542.16189
DIXFService  Version: 7.0.4542.16189
MROneBox     Version: 7.1.1541.3036
PayrollTaxModule     Version: 7.1.1541.3036
PerfSDK  Version: 7.0.4542.16189
ReportingService     Version: 7.0.4542.16189
RetailCloudPos   Version: 7.1.1541.3036
RetailHQConfiguration    Version: 7.1.1541.3036
RetailSDK    Version: 7.1.1541.3036
RetailSelfService    Version: 7.1.1541.3036
RetailServer     Version: 7.1.1541.3036
RetailStorefront     Version: 7.1.1541.3036
SCMSelfService   Version: 7.1.1541.3036

The data I'm looking for is the first column of the table, but it has things like List of Runbook ID... at the top.我要查找的数据是表格的第一列,但它在顶部有诸如List of Runbook ID...类的内容。 Is there a good way in PowerShell to parse this data so I can get just the table data? PowerShell 中是否有解析这些数据的好方法,以便我可以只获取表数据?

BenH's helpful answer works well with your particular input and he makes a good point in general: when you call external utilities (command-line applications), all you get back are lines of text , unlike with PowerShell-native commands that pass objects around. BenH的有用答案非常适合您的特定输入,并且总的来说很不错:当您调用外部实用程序 (命令行应用程序)时,返回的只是文本行 ,而与传递对象的 PowerShell本机命令不同。

Parsing strings (text) will always be more brittle than dealing with objects (which is why PowerShell's fundamental object orientation represents a great evolutionary leap in shell design). 解析字符串 (文本)总是比处理对象更加脆弱 (这就是为什么PowerShell的基本面向对象代表了Shell设计方面的巨大飞跃)。

That said, if you can make certain assumptions about the formatting of the strings you receive, PowerShell offers great tools to help even with that : 就是说, 如果您可以对接收到的字符串的格式做出某些假设,那么PowerShell将提供出色的工具来帮助您

Imagine a function Select-Column that selects whitespace-separated fields (column values) by index from each input line (vaguely akin to awk ): 想象一下一个Select-Column函数 ,该函数通过索引从每条输入行(大概类似于awk )中按索引选择用空格分隔的字段(列值):

@'
List of Runbook ID on the system: 



List of services installed on the system: 

ALMService   Version: 7.0.4542.16189
AOSService   Version: 7.0.4542.16189
BIService    Version: 7.0.4542.16189
DevToolsService  Version: 7.0.4542.16189
DIXFService  Version: 7.0.4542.16189
MROneBox     Version: 7.1.1541.3036
PayrollTaxModule     Version: 7.1.1541.3036
PerfSDK  Version: 7.0.4542.16189
ReportingService     Version: 7.0.4542.16189
RetailCloudPos   Version: 7.1.1541.3036
RetailHQConfiguration    Version: 7.1.1541.3036
RetailSDK    Version: 7.1.1541.3036
RetailSelfService    Version: 7.1.1541.3036
RetailServer     Version: 7.1.1541.3036
RetailStorefront     Version: 7.1.1541.3036
SCMSelfService   Version: 7.1.1541.3036
'@ -split '\r?\n' | 
  Select-Column -Index 0 -RequiredCount 3

The above, due to selecting the 1st column ( -Index 0 - multiple indices supported) from only those lines that have exactly 3 fields ( -RequiredCount 3 ), would yield: 上面的代码,由于仅从那些正好具有3个字段( -RequiredCount 3 )的行中选择第一列( -Index 0支持多个索引),将产生:

ALMService
AOSService
BIService
DevToolsService
DIXFService
MROneBox
PayrollTaxModule
PerfSDK
ReportingService
RetailCloudPos
RetailHQConfiguration
RetailSDK
RetailSelfService
RetailServer
RetailStorefront
SCMSelfService

Select-Column source code: Select-Column源代码:

Note that if you specify multiple ( 0 -based) column indices, the output fields are tab -separated by default, which you can change with the -OutFieldSeparator parameter. 请注意,如果您指定多个(基于0的)列索引,则默认情况下,输出字段以制表符- -OutFieldSeparator ,您可以使用-OutFieldSeparator参数进行更改。

Function Select-Column {
  [cmdletbinding(PositionalBinding=$False)]
  param(
    [Parameter(ValueFromPipeline, Mandatory)]
    $InputObject,

    [Parameter(Mandatory, Position=0)]
    [int[]] $Index,

    [Parameter(Position=1)]
    [int] $RequiredCount,

    [Parameter(Position=2)]
    [string] $OutFieldSeparator = "`t"

  )

  process {
    if (($fields = -split $InputObject) -and ($RequiredCount -eq 0 -or $RequiredCount -eq $fields.Count)) {
      $fields[$Index] -join $OutFieldSeparator
    }
  }

}

You could save the output in a variable, use Where-Object to filter just the lines that have Version in it, then remove all the unwanted characters with a -replace regex. 您可以将输出保存在变量中,使用Where-Object过滤其中包含Version的行,然后使用-replace regex删除所有不需要的字符。

$myExeOutput = & $myExe list
$myExeOutput |
    Where-Object {$_ -match 'Version:'} |
    ForEach-Object {
        $_ -replace '\s+Version:.*$',''
    }

@mklement0 This is brilliant! @mklement0 这太棒了! I used it to parse the output of "winrm get winrm/config/service" (which is a mess) to check whether or not Basic Authentication is allowed.我用它来解析“winrm get winrm/config/service”的输出(这是一团糟),以检查是否允许基本身份验证。 I called your function with:我用以下方法调用了您的函数:

$cmd = "winrm get winrm/config/service"
$keys = @(Invoke-Expression $cmd | Select-Column -Index 0 -RequiredCount 4)
$values = @(Invoke-Expression $cmd | Select-Column -Index 2 -RequiredCount 4)
foreach ($key in $keys) {
    Write-Host "$($key) = $($values)" -ForegroundColor Green
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM