powershell - 将 Powershell 中命令的字符串输出解析为对象数组
问题描述
我有一个命令行工具,可以输出有关系统上一系列包的信息块。
每个包由一对换行符分隔,给定包的每个属性由一个换行符分隔。
我正在尝试使用 Powershell 的 ConvertFrom-String 命令行开关来生成适当的输出,但我不知道如何编写模板文件。
来自 cmd 的示例(缩短)输出:
Architecture: windows_all
CompatibilityVersion: 0
Depends: system-windows-x86 (>= 20.5.0) | system-windows-x64 (>= 20.5.0)
DisplayName: NI Package Manager Deployment Support
DisplayVersion: 20.5.0
Essential: yes
Filename: ni-package-manager-deployment-support_20.5.0.49152-0+f0_windows_all.nipkg
Package: ni-package-manager-deployment-support
Plugin: wininst
Provides: ni-package-manager-deployment-support (= 20.5.0.49152-0+f0)
Size: 82809748
Version: 20.5.0.49152-0+f0
Architecture: windows_all
CompatibilityVersion: 0
Depends: system-windows-x86 (>= 20.6.0) | system-windows-x64 (>= 20.6.0)
DisplayName: NI Package Manager Deployment Support
DisplayVersion: 20.6.0
Essential: yes
Filename: ni-package-manager-deployment-support_20.6.0.49316-0+f164_windows_all.nipkg
Package: ni-package-manager-deployment-support
Plugin: wininst
Provides: ni-package-manager-deployment-support (= 20.6.0.49316-0+f164)
Size: 83414756
Version: 20.6.0.49316-0+f164
Architecture: windows_x64
CompatibilityVersion: 0
Depends: system-windows-x64 (>= 20.7.0)
DisplayName: NI Package Manager Deployment Support
DisplayVersion: 20.7.0
Essential: yes
Eula: eula-ni-standard
Filename: ni-package-manager-deployment-support_20.7.0.49347-0+f195_windows_x64.nipkg
OsRequires: >= 10
Package: ni-package-manager-deployment-support
Plugin: wininst
Provides: ni-package-manager-deployment-support (= 20.7.0.49347-0+f195)
Size: 83882240
Version: 20.7.0.49347-0+f195
Architecture: windows_x64
CompatibilityVersion: 170006
Conflicts: e2cfc358-ea97-42b7-8400-4dc41fbda64a (< 17.0.0)
Depends: ni-mdfsupport (>= 17.0.0),ni-metauninstaller (>= 17.0.0)
DisplayName: NI-Cabled PCIe
DisplayVersion: 17.3.0
Eula: eula-ni-standard,
Filename: ../../../../pool/ni-c/ni-cabled-pcie_17.3.0.49152-0+f0_windows_x64.nipkg
Homepage: http://www.ni.com
Package: ni-cabled-pcie
Plugin: wininst
Provides: 6a17ed9f-8c3a-4d81-91ad-7af5a7cb8f51 (= 17.30.49152),e2cfc358-ea97-42b7-8400-4dc41fbda64a (= 17.30.49152),ni-cabled-pcie (= 17.3.0.49152-0+f0)
Recommends: ni-certificates (>= 2.0.0)
Replaces: e2cfc358-ea97-42b7-8400-4dc41fbda64a (< 17.0.0)
Size: 1358368
Version: 17.3.0.49152-0+f0
Architecture: windows_x64
CompatibilityVersion: 210000
Conflicts: e2cfc358-ea97-42b7-8400-4dc41fbda64a (< 17.0.0)
Depends: ni-mdfsupport (>= 21.0.0),ni-metauninstaller (>= 21.0.0)
DisplayName: NI-Cabled PCIe
DisplayVersion: 21.0.0
Eula: eula-ni-standard
Filename: ../../../../../pool/ni-c/ni-cabled-pcie/21.0.0/21.0.0.49344-0+f192/ni-cabled-pcie_21.0.0.49344-0+f192_windows_x64.nipkg
OsRequires: >= 10
Package: ni-cabled-pcie
Plugin: wininst
Provides: 6a17ed9f-8c3a-4d81-91ad-7af5a7cb8f51 (= 21.00.49344),e2cfc358-ea97-42b7-8400-4dc41fbda64a (= 21.00.49344),ni-cabled-pcie (= 21.0.0.49344-0+f192)
Recommends: ni-certificates (>= 21.0.0)
Replaces: e2cfc358-ea97-42b7-8400-4dc41fbda64a (< 17.0.0)
Section: Infrastructure
Size: 1514650
UserVisible: no
Version: 21.0.0.49344-0+f192
我从上面删除了一些字段,但仍然可以看到包并不都有相同的字段,例如,有些有一个OsRequires
,有些没有。有些定义UserVisible
,有些则没有。
我想提取至少具有CompatibilityVersion
, Conflicts
, Depends
, Package
, Provides
, amdReplaces
属性的对象数组,但是能够获得“完整”集将是理想的。
我最初对模板文件的尝试如下(仅捕获几个属性):
{Object*:
{Architecture: windows_x86}
{CompatibilityVersion: 0}
{Version: 17.3.0.49152-0+f0}
}
{Object*:
{Architecture: windows_all}
{CompatibilityVersion: 0}
{Version: 20.0.0.49152-0+f0}
}
{Object*:
{Architecture: windows_x64}
{CompatibilityVersion: 190601}
{Version: 21.0.0.49344-0+f192}
}
我应该将我的属性集合分组到外部元素中吗?如果是这样,这是正确的方法吗?
当我在模板中没有“版本”属性的情况下运行它时,我得到以下信息(对于输入的一个子集,即只有“ni-cabled-pcie”匹配的包):
nipkg info ni-cabled-pcie | ConvertFrom-String -TemplateFile .\PackageInfoTemplate2.txt
Object
------
{@{CompatibilityVersion= 170006}}
Description: NI-Cabled PCIe
LanguageSupport: en
Package: ni-cabled-pcie
Section: Infrastructure
{@{CompatibilityVersion= 190006}}
Description: NI-Cabled PCIe
MD5sum: ac911971f7579d9ec6644a1fc6fb518a
Package: ni-cabled-pcie
Section: Infrastructure
{@{CompatibilityVersion= 200003}}
Description: NI-Cabled PCIe
{@{CompatibilityVersion= 6102}}
Package: ni-cabled-pcie
Section: Infrastructure
{@{CompatibilityVersion= 210000}}
Description: NI-Cabled PCIe
{@{CompatibilityVersion= 4}}
{@{CompatibilityVersion= 10}}
Package: ni-cabled-pcie
Section: Infrastructure
这看起来有点前途无量,但添加版本标签会让我看到“ConvertFrom-String 似乎无法使用您提供的模板解析您的数据。” 信息。
除此之外,该命令的输出仍然是一个字符串数组,每行一个 - 我想获得一个具有每个对象多个属性的对象数组,以便我可以有意义地,例如,将它们通过管道传输到Format-Table
.
编辑:
按照@Theo 给出的解决方案,我发现了简化示例的问题。一些软件包有重复的(通过不区分大小写)键,这会中断ConvertFrom-StringData
呼叫。
一个有效的替代品如下所示:
$data2 = $cmdOutput -replace '(?<!:.*):', '=' -split '(\r?\n){4,}' |
Where-Object { $_ -match '\S' } | ForEach-Object {
# convert the resulting data into Hashtables and cast to PsCustomObject
$o = new-object -typename PSObject;
$_.split([Environment]::NewLine) | Where-Object { $_ -match '\S' } | ForEach-Object {
$o | Add-Member -NotePropertyName $_.split('=')[0] -NotePropertyValue $_.split('=')[1] -Force
}; $o
}
这里的-Force
参数处理重复的参数(每种情况下的值都相同),但它似乎是一个不整洁的解决方案。
我该如何处理这种情况?(或者使用New-Object
和迭代添加每个属性是适当的解决方案)?
带有重复键的输入的小复制here-string:
$c1 = @'
Architecture= windows_x64
MD5Sum= 09e5ccbd2dd2bede51d0ff8e2077d415
MD5sum= 09e5ccbd2dd2bede51d0ff8e2077d415
'@
$c1 | ConvertFrom-StringData
解决方案
我会将捕获的输出拆分为双换行符上的数据块,并用于ConvertFrom-StringData
将它们解析为哈希表。然后将这些 Hashtable 转换为 PsCustomObjects 并运行循环以使所有对象具有相同的属性。
对于演示,我将 Here-String 与您的示例输出一起使用。您可能会
$cmdOutput = nipkg info ni-cabled-pcie | Out-String
在多行字符串中捕获输出。
$cmdOutput = @"
Architecture: windows_all
CompatibilityVersion: 0
Depends: system-windows-x86 (>= 20.5.0) | system-windows-x64 (>= 20.5.0)
DisplayName: NI Package Manager Deployment Support
DisplayVersion: 20.5.0
Essential: yes
Filename: ni-package-manager-deployment-support_20.5.0.49152-0+f0_windows_all.nipkg
Package: ni-package-manager-deployment-support
Plugin: wininst
Provides: ni-package-manager-deployment-support (= 20.5.0.49152-0+f0)
Size: 82809748
Version: 20.5.0.49152-0+f0
Architecture: windows_all
CompatibilityVersion: 0
Depends: system-windows-x86 (>= 20.6.0) | system-windows-x64 (>= 20.6.0)
DisplayName: NI Package Manager Deployment Support
DisplayVersion: 20.6.0
Essential: yes
Filename: ni-package-manager-deployment-support_20.6.0.49316-0+f164_windows_all.nipkg
Package: ni-package-manager-deployment-support
Plugin: wininst
Provides: ni-package-manager-deployment-support (= 20.6.0.49316-0+f164)
Size: 83414756
Version: 20.6.0.49316-0+f164
Architecture: windows_x64
CompatibilityVersion: 0
Depends: system-windows-x64 (>= 20.7.0)
DisplayName: NI Package Manager Deployment Support
DisplayVersion: 20.7.0
Essential: yes
Eula: eula-ni-standard
Filename: ni-package-manager-deployment-support_20.7.0.49347-0+f195_windows_x64.nipkg
OsRequires: >= 10
Package: ni-package-manager-deployment-support
Plugin: wininst
Provides: ni-package-manager-deployment-support (= 20.7.0.49347-0+f195)
Size: 83882240
Version: 20.7.0.49347-0+f195
Architecture: windows_x64
CompatibilityVersion: 170006
Conflicts: e2cfc358-ea97-42b7-8400-4dc41fbda64a (< 17.0.0)
Depends: ni-mdfsupport (>= 17.0.0),ni-metauninstaller (>= 17.0.0)
DisplayName: NI-Cabled PCIe
DisplayVersion: 17.3.0
Eula: eula-ni-standard,
Filename: ../../../../pool/ni-c/ni-cabled-pcie_17.3.0.49152-0+f0_windows_x64.nipkg
Homepage: http://www.ni.com
Package: ni-cabled-pcie
Plugin: wininst
Provides: 6a17ed9f-8c3a-4d81-91ad-7af5a7cb8f51 (= 17.30.49152),e2cfc358-ea97-42b7-8400-4dc41fbda64a (= 17.30.49152),ni-cabled-pcie (= 17.3.0.49152-0+f0)
Recommends: ni-certificates (>= 2.0.0)
Replaces: e2cfc358-ea97-42b7-8400-4dc41fbda64a (< 17.0.0)
Size: 1358368
Version: 17.3.0.49152-0+f0
Architecture: windows_x64
CompatibilityVersion: 210000
Conflicts: e2cfc358-ea97-42b7-8400-4dc41fbda64a (< 17.0.0)
Depends: ni-mdfsupport (>= 21.0.0),ni-metauninstaller (>= 21.0.0)
DisplayName: NI-Cabled PCIe
DisplayVersion: 21.0.0
Eula: eula-ni-standard
Filename: ../../../../../pool/ni-c/ni-cabled-pcie/21.0.0/21.0.0.49344-0+f192/ni-cabled-pcie_21.0.0.49344-0+f192_windows_x64.nipkg
OsRequires: >= 10
Package: ni-cabled-pcie
Plugin: wininst
Provides: 6a17ed9f-8c3a-4d81-91ad-7af5a7cb8f51 (= 21.00.49344),e2cfc358-ea97-42b7-8400-4dc41fbda64a (= 21.00.49344),ni-cabled-pcie (= 21.0.0.49344-0+f192)
Recommends: ni-certificates (>= 21.0.0)
Replaces: e2cfc358-ea97-42b7-8400-4dc41fbda64a (< 17.0.0)
Section: Infrastructure
Size: 1514650
UserVisible: no
Version: 21.0.0.49344-0+f192
"@
# replace the first colon (:) into an equal sign, split on the double newlines,
# filter only data blocks that are not empty or whitespace-only and loop through
$data = $cmdOutput -replace '(?<!:.*):', '=' -split '(\r?\n){2,}' |
Where-Object { $_ -match '\S' } | ForEach-Object {
# convert the resulting data into Hashtables and cast to PsCustomObject
[PsCustomObject]($_ | ConvertFrom-StringData)
}
# next, complete the objects in the data array to all have the same properties
$properties = $data | ForEach-Object {($_.PSObject.Properties).Name} | Sort-Object -Unique
# update the items in the collection to contain all properties
$result = foreach($item in $data) {
$item | Select-Object $properties
}
现在,如果您通过管道$result
传递到Format-*
or Out-GridView
,则所有属性都存在于数组中的每个项目中。例如,当您将结果数据保存到 CSV 文件或转换为 JSON 时,所有属性也会出现
-replace
仅第一个冒号的正则表达式详细信息:
(?<! Assert that it is impossible to match the regex below with the match ending at this position (negative lookbehind)
: Match the character “:” literally
. Match any single character
* Between zero and unlimited times, as many times as possible, giving back as needed (greedy)
)
: Match the character “:” literally
我从您的评论中收集并编辑数据可以具有重复的属性名称,唯一的区别是属性名称的大小写(值相等)。不幸的是,ConvertFrom-StringData 似乎不喜欢那样。
我建议自己构建哈希表,从而克服有问题的 ConvertFrom-StringData,这也使我们不必先将冒号替换为等号。
尝试:
$data = $cmdOutput -split '(\r?\n){4,}' | Where-Object { $_ -match '\S' } | ForEach-Object {
# convert the resulting data into Hashtables and cast to PsCustomObject
$lines = ($_ -split '\r?\n') | Where-Object { $_ -match '\S' }
$hash = @{}
foreach ($line in $lines) {
$name, $value = ($line -split ':', 2).Trim()
# now just overwrite the property if already present without error or add a new one.
$hash[$name] = $value
}
[PsCustomObject] $hash
}
推荐阅读
- python - 如何将元组值存储为python变量
- haskell - 即使有类型约束也无法匹配类型错误
- angular - 如何禁用更漂亮的设置创建新的> html标签行?
- python - PySpark - 广播火花数据帧
- javascript - 在 Vue 中绑定组件属性
- php - 5 折交叉验证给出了 SVM 中的反向学习曲线
- android - 即使应用程序处于后台/退出状态,如何让 CameraManager.AvailabilityCallback 持续存在
- c# - 在特定类的方法中调用另一个类的属性导致溢出错误。
- java - 对每个选项卡的 recyclerview 项目进行分类
- python - 使用 python 正则表达式从字符串中单独提取子字符串