最简单的方法是创建一个自定义对象,然后使用 Add-Member 将每个软件标题添加到它作为 NoteProperty。将所有这些对象(每台计算机一个)收集到一个数组中,然后输出到 CSV。您将遇到的问题是您将拥有很多(我的意思是很多)软件标题,并且在输出 CSV 时只考虑第一个条目的属性列表,因此需要做一些额外的工作。
你说你有你的脚本来从远程机器上拿东西,但不要给我们,所以我会用你确实给我们的东西。我过滤了 MS 更新和修补程序,但您显然可以删除或忽略它。
$app32 = Get-ChildItem HKLM:\SOFTWARE\Wow6432Node\Microsoft\Windows\CurrentVersion\Uninstall\
$app64 = Get-ChildItem HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\
$appAll = $app32 + $app64
$AllComputers = @()
ForEach($CompName in (GC C:\ListOfComputers.txt)){
$Computer = [PSCustomObject]@{"PC Name"=$CompName}
$appAll |
ForEach-Object {Get-ItemProperty $_.pspath} |
?{!($_.displayname -match "(?:Update|Hotfix) for Microsoft") -and !([string]::IsNullOrEmpty($_.DisplayName))}|
Select-Object DisplayName,DisplayVersion |
Sort-Object DisplayName|
%{
Add-Member -InputObject $Computer -NotePropertyName $_.DisplayName -NotePropertyValue $_.DisplayVersion
}
$AllComputers+=$Computer
}
#Make sure first computer has properties for all possible software titles
$AllComputers|
%{
$_|GM -MemberType Properties|select -expand Name
}|
Select -Unique|
?{$_ -notin ($AllComputers[0]|gm -MemberType Properties|select -Expand Name)}|
%{
Add-Member -InputObject $AllComputers[0] -NotePropertyName $_ -NotePropertyValue ""
}
#Output to file
$AllComputers|Export-Csv $NewFilePath -NoTypeInformation
编辑:为了尝试解释它,它的作用是为每台计算机创建一个具有 1 个属性的 PSCustomObject:PC 名称。它将该属性的值设置为当前正在运行的任何计算机。
然后它会像您已经在做的那样获取所有注册表值,并为每个注册表值添加另一个属性到它为该计算机创建的 PSCustomObject。属性名称是软件的标题,值是软件版本。因此,在您假设的第一台 PC 之后,您将有一个看起来像这样的对象:
PC Name : PC 1
MS Office : 2013
Adobe : 9
7-Zip : 5.2
VNC : 7
PowerShell : 4.5
将该对象添加到数组中,然后对每台计算机进行冲洗和重复。当你完成时,你有一个数组,它的输出就像你想要的那样。您将该数组通过管道传输到 Format-Table 并得到:
PC Name MS Office Adobe 7-Zip VNC PowerShell
------- --------- ----- ----- --- ----------
PC 1 2013 9 5.2 7 4.5
PC 2 2007 11 5.2 7 4.5
PC 3 2013 11 5.2 7 2
PC 4 2013 9 5.2 7 3
问题是它只显示数组中第一项具有的属性。因此,假设 PC 1 没有安装 7-Zip。现在您在数组中的第一项看起来像这样:
PC Name : PC 1
MS Office : 2013
Adobe : 9
VNC : 7
PowerShell : 4.5
由于当您将数组通过管道传输到 Format-Table 时它没有 7-Zip 属性,您最终会得到:
PC Name MS Office Adobe VNC PowerShell
------- --------- ----- --- ----------
PC 1 2013 9 7 4.5
PC 2 2007 11 7 4.5
PC 3 2013 11 7 2
PC 4 2013 9 7 3
现在这并不好,因为我们想查看所有机器上所有标题的版本号,因此第一条记录需要为任何机器上的每个软件标题都有一个属性,无论它是否安装在第一台电脑。为了实现这一点,我们通过将数组传递给 ForEach(我使用 % 别名)循环来循环遍历数组:
$AllComputers|
%{
在该 ForEach 循环中,我们获取当前计算机并执行 Get-Member(使用 GM 别名),并仅选择作为属性的成员(不包括可能在对象上的方法或事件),并展开 Name of每个属性。
$_|GM -MemberType Properties|select -expand Name
现在请记住,我们的属性名称是软件标题,值是每个标题的版本,但我们只需要名称,因此这为我们提供了每台计算机上每个软件标题的列表。因此,我们从那里通过管道传输到 Select -Unique 以消除重复项,并继续通过管道传输到 Where 子句(别名?使用)以过滤掉第一台计算机已经存在的任何属性:
Select -Unique|
?{$_ -notin ($AllComputers[0]|gm -MemberType Properties|select -Expand Name)}|
这是通过获取第一台计算机的属性名称来完成的(即第二行 () 中的所有内容),然后测试所有计算机中所有属性的大列表中的每个属性是否已经在该计算机的属性列表中。它跳过已经存在的那些,并且对于每个新的,它进入另一个 ForEach 循环并执行 Add-Member 以将每个属性添加到第一台计算机,并且只使用“”值,因为该计算机没有安装它。
所以现在第一个条目具有所有可能的软件标题的属性,当我们将数组通过管道传输到 FT(Format-Table 的缩写)时,我们得到:
PC Name MS Office Adobe VNC PowerShell 7-Zip
------- --------- ----- --- ---------- -----
PC 1 2013 9 7 4.5
PC 2 2007 11 7 4.5 5.2
PC 3 2013 11 7 2 5.2
PC 4 2013 9 7 3 5.2