如何正确导出多台服务器的指定应用及其版本信息至Excel?
解决PowerShell远程应用信息导出CSV的问题
你的脚本主要存在两个核心问题,导致导出结果不符合预期,我一步步给你拆解并修正:
问题分析
- CSV文件被重复覆盖:你在
foreach循环里直接调用Export-Csv,每次执行都会清空并覆盖之前的文件内容,最终只会保留最后一台服务器的查询结果。 - 应用名称匹配逻辑失效:
$list是从文件读取的数组(每行对应一个应用名),直接用$_.Name -like "*$list*"不会正确匹配数组里的每个应用——PowerShell会把数组转换成逗号分隔的字符串,导致匹配规则完全错误。 - 额外优化点:
Get-WmiObject是较老旧的命令,建议用Get-CimInstance替代,性能更好且避免Win32_Product自带的MSI自动修复触发;默认Export-Csv会添加类型信息行,会干扰Excel的列解析。
修正后的完整脚本
# 读取目标应用列表和服务器列表 $appList = Get-Content -Path C:\Users\bob\AppList.txt $serverList = Get-Content -Path C:\Users\bob\ServerList.txt # 定义输出路径,先清空原有文件(避免旧内容干扰) $outputPath = "C:\Users\bob\ServerListResults.csv" if (Test-Path $outputPath) { Remove-Item $outputPath } # 遍历每台服务器 foreach ($server in $serverList) { Write-Host "正在查询服务器: $server" try { # 使用Get-CimInstance替代Get-WmiObject,更高效且避免MSI自动修复触发 Get-CimInstance -Namespace ROOT\CIMV2 -Class Win32_Product -ComputerName $server -ErrorAction Stop | # 过滤匹配应用列表的项:检查当前应用名是否匹配列表中任意一个关键词 Where-Object { $currentAppName = $_.Name $appList | Where-Object { $currentAppName -like "*$_*" } } | # 选择需要的属性列 Select-Object Name, Version, PSComputerName | # 追加到CSV文件,-NoTypeInformation去掉类型注释行,-Encoding确保Excel兼容 Export-Csv -Path $outputPath -Append -NoTypeInformation -Encoding UTF8 } catch { Write-Warning "服务器 $server 查询失败: $_" } } Write-Host "查询完成,结果已导出至: $outputPath"
关键改进说明
- 避免文件覆盖:添加
-Append参数让每次循环的结果追加到CSV,而不是覆盖;提前清空旧文件确保结果干净。 - 正确匹配应用:通过嵌套的
Where-Object检查当前应用名称是否匹配$appList中的任意一项,解决数组匹配的逻辑问题。 - 替换为Get-CimInstance:
Win32_Product本身会触发MSI的自动修复检查,可能导致性能变慢甚至意外操作,Get-CimInstance是更安全高效的替代方案。 - 错误处理:添加
Try-Catch捕获服务器不可达、权限不足等错误,避免脚本中断,同时输出警告信息便于排查。 - Excel兼容性优化:
-NoTypeInformation去掉CSV第一行的类型注释,-Encoding UTF8确保中文等特殊字符能被Excel正确识别。
更高效的进阶写法(推荐)
如果不需要返回所有Win32_Product的属性,可以直接在远程服务器端过滤,减少数据传输量:
foreach ($server in $serverList) { Write-Host "正在查询服务器: $server" try { # 逐个查询应用列表中的应用,在远程端直接过滤,提升性能 foreach ($app in $appList) { Get-CimInstance -Namespace ROOT\CIMV2 -Class Win32_Product -ComputerName $server -Filter "Name LIKE '%$app%'" -ErrorAction Stop | Select-Object Name, Version, PSComputerName | Export-Csv -Path $outputPath -Append -NoTypeInformation -Encoding UTF8 } } catch { Write-Warning "服务器 $server 查询失败: $_" } }
这种方式通过-Filter参数在远程服务器端直接完成过滤,不需要把所有应用数据传回本地再处理,在服务器数量较多时性能提升明显。
内容的提问来源于stack exchange,提问作者alfalfa14
相关产品推荐
相关产品推荐

