从 PowerShell select-object 结果中删除列名称
Remove column name from PowerShell select-object results
总的来说,我的目标是获取远程计算机列表的 VNC 版本以及卸载 GUID,以便我可以从某些计算机远程卸载 VNC 查看器。我使用了 Get-WmiObject -Class Win32_Product 但这非常慢。
我有以下脚本,但在结果中它包含 select-object 参数的名称。
$computers = Get-Content -Path "C:\Computers.txt"
$Results = @()
ForEach ($Computer in $Computers) {
$Results += New-Object PSObject -Property @{
"ComputerName" = $Computer
"Name" = Invoke-Command -ComputerName $Computer -ScriptBlock { Get-ItemProperty HKLM:\Software\Microsoft\Windows\CurrentVersion\Uninstall\* } `
| Where-Object -FilterScript {$_.DisplayName -like "VNC V*"} | select-object DisplayName
"DisplayVersion" = Invoke-Command -ComputerName $Computer -ScriptBlock { Get-ItemProperty HKLM:\Software\Microsoft\Windows\CurrentVersion\Uninstall\* } `
| Where-Object -FilterScript {$_.DisplayName -like "VNC V*"} | select-object DisplayVersion
"ModifyPath" = Invoke-Command -ComputerName $Computer -ScriptBlock { Get-ItemProperty HKLM:\Software\Microsoft\Windows\CurrentVersion\Uninstall\* } `
| Where-Object -FilterScript {$_.DisplayName -like "VNC V*"} | select-object ModifyPath
"Vendor" = Invoke-Command -ComputerName $Computer -ScriptBlock { Get-ItemProperty HKLM:\Software\Microsoft\Windows\CurrentVersion\Uninstall\* } `
| Where-Object -FilterScript {$_.DisplayName -like "VNC V*"} | select-object Publisher
}
}
$Results | Select-Object ComputerName,Name,DisplayVersion,ModifyPath,Vendor | Sort-Object ComputerName | Export-Csv C:\VNC.csv -notype ;
我的结果是这样的:
ComputerName : ComputerName
姓名 :@{DisplayName=VNC Viewer 5.2.3}
显示版本 :@{DisplayVersion=5.2.3}
修改路径 :@{ModifyPath=MsiExec.exe /I{18B1E36F-0DA3-4FDA-BC57-DD815B0DF3B2}}
供应商 :@{Publisher=RealVNC Ltd}
我希望它看起来像这样:
ComputerName : ComputerName
名称 :VNC 查看器 5.2.3
显示版本 :5.2.3
修改路径 :MsiExec.exe /I{18B1E36F-0DA3-4FDA-BC57-DD815B0DF3B2}
供应商 :RealVNC Ltd
这可能吗,还是我对这个脚本的处理完全错误?我还没有想出一种方法来 运行 这个 Invoke-Command 的多个参数,并且仍然以任何其他方式在单独的列中输出结果。
此脚本有效,但需要 100 台计算机永远使用:
if (Test-Path C:\VNCInstalled.csv) {Remove-Item C:\VNCInstalled.csv}
if (Test-Path C:\Computers.txt) {Remove-Item C:\Computers.txt}
$DirSearcher = New-Object System.DirectoryServices.DirectorySearcher([adsi]'')
$DirSearcher.Filter = '(&(objectClass=Computer)(!(cn=*esx*)) (!(cn=*slng*)) (!(cn=*dcen*)) )'
$DirSearcher.FindAll().GetEnumerator() | sort-object { $_.Properties.name } `
| ForEach-Object { $_.Properties.name }`
| Out-File -FilePath C:\Computers.txt
Get-Content -Path c:\Computers.txt `
| ForEach-Object {Get-WmiObject -Class Win32_Product -ComputerName $_} `
| Where-Object -FilterScript {$_.Name -like "VNC V*"} `
| select-object @{Name="ComputerName";Expression={$_.PSComputerName}},
Name,
@{Name="InstallLocation";Expression={$_.PackageCache}},
Vendor,
Version,
@{Name="GUID";Expression={$_.IdentifyingNumber}} `
| Sort-Object ComputerName `
| Export-CSV -path c:\VNCInstalled.csv -notype
Change all of your Select-Object
commands to Select-Object
-ExpandProperty PropertyName
, to discard the property name / column header.
这是我三年前给出的答案,我认为这是一个非常糟糕的答案。让我现在做得更好。
为什么您当前的代码很慢
您当前的代码从 AD 中枚举所有机器并将它们放在一个名为 Computers.txt
的文件中。简单,你做的很好。
接下来,您的代码将执行此操作:
Get-Content -Path c:\Computers.txt |
ForEach-Object {Get-WmiObject -Class Win32_Product -ComputerName $_} `
| Where-Object -FilterScript {$_.Name -like "VNC V*"} [...]
这可以概括为'For each computer, request the full Win32_product table, and then after that, filter down to apps named VNC.'这非常性能影响,原因有几个。
即使在快速的现代计算机上,查询 Win32_Product 也需要 30 秒或更长时间,因为 returns 每个 应用程序都已安装. (在我的新虚拟机上,只安装了几个应用程序就花了一分多钟!)
查询 Win32_Product 也有这个有趣的怪癖,这使得它需要更长的时间,引用自 Win32_Product Class
[ 上的 MSDN 文档=63=]
Warning Win32_Product is not query optimized. Queries such as "select * from Win32_Product where (name like 'Sniffer%')" require WMI to use the MSI provider to enumerate all of the installed products and then parse the full list sequentially to handle the “where” clause. This process also initiates a consistency check of packages installed, verifying and repairing the install. With an account with only user privileges, as the user account may not have access to quite a few locations, may cause delay in application launch and an event 11708 stating an installation failure. For more information, see KB Article 794524.
总而言之,查询 Win32_Product 很慢,并且它还会触发对每个应用程序的一致性检查,并且我们还编写了此查询以在过滤之前检索每个应用程序。这些加起来是一个过程,每台电脑可能需要大约 3 分钟,并且将连续运行(一个接一个)并持续很长时间。
如何修复
可以在两个地方可靠地检索软件信息:
- 如果你的设备上安装了SCCM/ConfigMgr,它会添加你可以查询的Win32_AddRemoveProgram WMI Class,这是Win32_Product的超快速版本
- 如果没有,我们可以随时从注册表中检索信息。
这里有一个简短的片段,可以在计算机上安装 VLC 等应用程序(我没有像你一样的 VNC,所以我正在到期)
Get-ItemProperty HKLM:\Software\Wow6432Node\Microsoft\Windows\CurrentVersion\Uninstall\* | Where-object DisplayName -like "VLC*" |Select-Object DisplayName, DisplayVersion, Publisher, InstallDate,UninstallString
DisplayName : VLC media player
DisplayVersion : 3.0.8
Publisher : VideoLAN
InstallDate :
UninstallString : "C:\Program Files (x86)\VideoLAN\VLC\uninstall.exe"
这个操作快多了,只有400毫秒左右。遗憾的是,我们无法通过注册表获得更快的速度,因为它有一个非常奇怪的 PowerShell 提供程序,它没有实现 -Filter
参数,所以我们必须检索所有程序,然后过滤到我们想要的选择。
正在更新您的脚本以改用此函数
我冒昧地重写了您的脚本以使用这种方法,并对其进行了一些重组以提高可读性。
$results = New-object System.Collections.ArrayList
$computers = Get-Content -Path c:\Computers.txt
foreach ($computer in $computers){
#get VNC entries from remote computers registry
$VNCKeys = Invoke-Command -ComputerName $computer -ScriptBlock {
Get-ItemProperty HKLM:\Software\Wow6432Node\Microsoft\Windows\CurrentVersion\Uninstall\* |
Where-object DisplayName -like "VNC V*" |
Select-Object DisplayName, DisplayVersion, Publisher, UninstallString, @{Name=‘ComputerName‘;Expression={$computer}}
}#end of remote command
if ($VNCKeys -ne $null){
forEach($VNCKey in $VNCKeys){
[void]$results.Add($VNCKey)
}
}
}
$results | Sort-Object ComputerName | Export-CSV -path c:\VNCInstalled.csv -NoTypeInformation
总的来说,我的目标是获取远程计算机列表的 VNC 版本以及卸载 GUID,以便我可以从某些计算机远程卸载 VNC 查看器。我使用了 Get-WmiObject -Class Win32_Product 但这非常慢。
我有以下脚本,但在结果中它包含 select-object 参数的名称。
$computers = Get-Content -Path "C:\Computers.txt"
$Results = @()
ForEach ($Computer in $Computers) {
$Results += New-Object PSObject -Property @{
"ComputerName" = $Computer
"Name" = Invoke-Command -ComputerName $Computer -ScriptBlock { Get-ItemProperty HKLM:\Software\Microsoft\Windows\CurrentVersion\Uninstall\* } `
| Where-Object -FilterScript {$_.DisplayName -like "VNC V*"} | select-object DisplayName
"DisplayVersion" = Invoke-Command -ComputerName $Computer -ScriptBlock { Get-ItemProperty HKLM:\Software\Microsoft\Windows\CurrentVersion\Uninstall\* } `
| Where-Object -FilterScript {$_.DisplayName -like "VNC V*"} | select-object DisplayVersion
"ModifyPath" = Invoke-Command -ComputerName $Computer -ScriptBlock { Get-ItemProperty HKLM:\Software\Microsoft\Windows\CurrentVersion\Uninstall\* } `
| Where-Object -FilterScript {$_.DisplayName -like "VNC V*"} | select-object ModifyPath
"Vendor" = Invoke-Command -ComputerName $Computer -ScriptBlock { Get-ItemProperty HKLM:\Software\Microsoft\Windows\CurrentVersion\Uninstall\* } `
| Where-Object -FilterScript {$_.DisplayName -like "VNC V*"} | select-object Publisher
}
}
$Results | Select-Object ComputerName,Name,DisplayVersion,ModifyPath,Vendor | Sort-Object ComputerName | Export-Csv C:\VNC.csv -notype ;
我的结果是这样的:
ComputerName : ComputerName
姓名 :@{DisplayName=VNC Viewer 5.2.3}
显示版本 :@{DisplayVersion=5.2.3}
修改路径 :@{ModifyPath=MsiExec.exe /I{18B1E36F-0DA3-4FDA-BC57-DD815B0DF3B2}}
供应商 :@{Publisher=RealVNC Ltd}
我希望它看起来像这样:
ComputerName : ComputerName
名称 :VNC 查看器 5.2.3
显示版本 :5.2.3
修改路径 :MsiExec.exe /I{18B1E36F-0DA3-4FDA-BC57-DD815B0DF3B2}
供应商 :RealVNC Ltd
这可能吗,还是我对这个脚本的处理完全错误?我还没有想出一种方法来 运行 这个 Invoke-Command 的多个参数,并且仍然以任何其他方式在单独的列中输出结果。
此脚本有效,但需要 100 台计算机永远使用:
if (Test-Path C:\VNCInstalled.csv) {Remove-Item C:\VNCInstalled.csv}
if (Test-Path C:\Computers.txt) {Remove-Item C:\Computers.txt}
$DirSearcher = New-Object System.DirectoryServices.DirectorySearcher([adsi]'')
$DirSearcher.Filter = '(&(objectClass=Computer)(!(cn=*esx*)) (!(cn=*slng*)) (!(cn=*dcen*)) )'
$DirSearcher.FindAll().GetEnumerator() | sort-object { $_.Properties.name } `
| ForEach-Object { $_.Properties.name }`
| Out-File -FilePath C:\Computers.txt
Get-Content -Path c:\Computers.txt `
| ForEach-Object {Get-WmiObject -Class Win32_Product -ComputerName $_} `
| Where-Object -FilterScript {$_.Name -like "VNC V*"} `
| select-object @{Name="ComputerName";Expression={$_.PSComputerName}},
Name,
@{Name="InstallLocation";Expression={$_.PackageCache}},
Vendor,
Version,
@{Name="GUID";Expression={$_.IdentifyingNumber}} `
| Sort-Object ComputerName `
| Export-CSV -path c:\VNCInstalled.csv -notype
Change all of your
Select-Object
commands toSelect-Object -ExpandProperty PropertyName
, to discard the property name / column header.
这是我三年前给出的答案,我认为这是一个非常糟糕的答案。让我现在做得更好。
为什么您当前的代码很慢
您当前的代码从 AD 中枚举所有机器并将它们放在一个名为 Computers.txt
的文件中。简单,你做的很好。
接下来,您的代码将执行此操作:
Get-Content -Path c:\Computers.txt |
ForEach-Object {Get-WmiObject -Class Win32_Product -ComputerName $_} `
| Where-Object -FilterScript {$_.Name -like "VNC V*"} [...]
这可以概括为'For each computer, request the full Win32_product table, and then after that, filter down to apps named VNC.'这非常性能影响,原因有几个。
即使在快速的现代计算机上,查询 Win32_Product 也需要 30 秒或更长时间,因为 returns 每个 应用程序都已安装. (在我的新虚拟机上,只安装了几个应用程序就花了一分多钟!)
查询 Win32_Product 也有这个有趣的怪癖,这使得它需要更长的时间,引用自 Win32_Product Class
[ 上的 MSDN 文档=63=]
Warning Win32_Product is not query optimized. Queries such as "select * from Win32_Product where (name like 'Sniffer%')" require WMI to use the MSI provider to enumerate all of the installed products and then parse the full list sequentially to handle the “where” clause. This process also initiates a consistency check of packages installed, verifying and repairing the install. With an account with only user privileges, as the user account may not have access to quite a few locations, may cause delay in application launch and an event 11708 stating an installation failure. For more information, see KB Article 794524.
总而言之,查询 Win32_Product 很慢,并且它还会触发对每个应用程序的一致性检查,并且我们还编写了此查询以在过滤之前检索每个应用程序。这些加起来是一个过程,每台电脑可能需要大约 3 分钟,并且将连续运行(一个接一个)并持续很长时间。
如何修复
可以在两个地方可靠地检索软件信息:
- 如果你的设备上安装了SCCM/ConfigMgr,它会添加你可以查询的Win32_AddRemoveProgram WMI Class,这是Win32_Product的超快速版本
- 如果没有,我们可以随时从注册表中检索信息。
这里有一个简短的片段,可以在计算机上安装 VLC 等应用程序(我没有像你一样的 VNC,所以我正在到期)
Get-ItemProperty HKLM:\Software\Wow6432Node\Microsoft\Windows\CurrentVersion\Uninstall\* | Where-object DisplayName -like "VLC*" |Select-Object DisplayName, DisplayVersion, Publisher, InstallDate,UninstallString
DisplayName : VLC media player
DisplayVersion : 3.0.8
Publisher : VideoLAN
InstallDate :
UninstallString : "C:\Program Files (x86)\VideoLAN\VLC\uninstall.exe"
这个操作快多了,只有400毫秒左右。遗憾的是,我们无法通过注册表获得更快的速度,因为它有一个非常奇怪的 PowerShell 提供程序,它没有实现 -Filter
参数,所以我们必须检索所有程序,然后过滤到我们想要的选择。
正在更新您的脚本以改用此函数
我冒昧地重写了您的脚本以使用这种方法,并对其进行了一些重组以提高可读性。
$results = New-object System.Collections.ArrayList
$computers = Get-Content -Path c:\Computers.txt
foreach ($computer in $computers){
#get VNC entries from remote computers registry
$VNCKeys = Invoke-Command -ComputerName $computer -ScriptBlock {
Get-ItemProperty HKLM:\Software\Wow6432Node\Microsoft\Windows\CurrentVersion\Uninstall\* |
Where-object DisplayName -like "VNC V*" |
Select-Object DisplayName, DisplayVersion, Publisher, UninstallString, @{Name=‘ComputerName‘;Expression={$computer}}
}#end of remote command
if ($VNCKeys -ne $null){
forEach($VNCKey in $VNCKeys){
[void]$results.Add($VNCKey)
}
}
}
$results | Sort-Object ComputerName | Export-CSV -path c:\VNCInstalled.csv -NoTypeInformation