【问题标题】:Powershell output to csv file horizontally?Powershell水平输出到csv文件?
【发布时间】:2014-09-16 09:35:47
【问题描述】:

我有一个简单的脚本可以让所有应用都安装在 PC 上。

$app32 = Get-ChildItem HKLM:\SOFTWARE\Wow6432Node\Microsoft\Windows\CurrentVersion\Uninstall\
$app64 = Get-ChildItem HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\
$appAll = $app32 + $app64
$appAll | 
ForEach-Object {Get-ItemProperty $_.pspath} |
Select-Object DisplayName,DisplayVersion |
Sort-Object DisplayName |
Export-Csv c:\work\appversion.csv

结果将是垂直的,但我需要循环运行 PC 列表,然后输出到 csv 文件。理想的结果应该是这样的。

  • 选定的应用程序将在 csv 文件中水平列出
  • 所有电脑都将垂直列出。

我为此做了很多研究,但找不到方法。

我现在所做的是将所有内容输出到文本文件,然后执行select-string 以获取匹配的行。这样我丢失了所有列,整行将在一列中。

有什么想法吗?还是有更好的方法?

【问题讨论】:

  • 所以你这里的内容将查询本地注册表。你会运行这个脚本,然后将结果编译到某个地方的文本文件中,还是你会重新编写它来访问远程注册表?
  • 可能会找到大量的软件项目,将 PC 的名称放在水平方向,将软件名称放在垂直位置会更简单
  • @TheMadTechnician 这只是本地注册表查询的示例脚本。我已经准备好远程注册表访问的脚本。我唯一不能做的就是在上面输出.....
  • @Jimbo 是的,这是一个想法,我可以稍后在 excel 中随意切换垂直和水平。但是如何以您的方式填充结果?

标签: powershell csv powershell-2.0 powershell-3.0


【解决方案1】:

最简单的方法是创建一个自定义对象,然后使用 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 

【讨论】:

  • 感谢您的帮助。这需要我一段时间才能完全理解你的概念。会先试试。我不会得到所有软件列表,只会挑选一些需要的软件。
  • 我在答案中添加了一些更详细的解释,以帮助您了解我的所作所为。
猜你喜欢
  • 2014-11-18
  • 2017-12-15
  • 1970-01-01
  • 1970-01-01
  • 2013-01-22
  • 2015-01-17
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多