PowerShell获取域内已安装软件清单无法读取远程设备数据求助
问题成因
- 字段映射错误:你自定义对象的
ComputerName字段错误取了Win32_Product返回的软件名属性,而非当前循环的远程设备名,当远程设备查询失败时,变量会残留本地设备的查询结果,导致所有输出看起来都是本地设备的软件 - 重复且冗余的CIM调用:你循环内三次调用
Get-CimInstance Win32_Product拉取全量软件列表,不仅执行效率极低,还大幅提升了请求超时、调用失败的概率 - 异常捕获逻辑错误:catch块中引用的
$serverName变量未定义,实际循环中存储设备名的变量是$nombre,导致远程设备调用出错时无法正确识别故障设备,错误信息完全失效 - 环境依赖缺失:远程设备默认防火墙会拦截WMI/CIM请求,且运行脚本的账号需要拥有所有目标设备的本地管理员权限,否则CIM调用会直接失败
- Win32_Product本身的缺陷:该类查询会触发系统对所有MSI安装的软件做一致性校验,可能导致软件自动修复、调用超时甚至设备卡死,进一步提升了远程查询失败的概率
修复后的脚本
下面的脚本优化了调用逻辑,修正了字段错误,同时保留原有功能:
# 加载AD模块 Import-Module ActiveDirectory -ErrorAction Stop # 拉取所有域设备 $computers = Get-ADComputer -Filter * $exportPath = 'C:\temp\softin.csv' # 确保导出目录存在 if(-not (Test-Path (Split-Path $exportPath))){ New-Item -Path (Split-Path $exportPath) -ItemType Directory -Force | Out-Null } $Result = foreach ($computer in $computers){ $nombre = $computer.Name # 先检测设备在线 if(!(Test-Connection -ComputerName $nombre -BufferSize 16 -Count 1 -ErrorAction SilentlyContinue -Quiet)) { Write-Host "设备 $nombre 离线,跳过" -ForegroundColor Red continue } try{ # 仅调用一次CIM接口拉取所有软件信息 $allSoft = Get-CimInstance Win32_Product -ComputerName $nombre -ErrorAction Stop # 每个软件生成一条记录,避免属性堆叠 foreach ($soft in $allSoft) { [PsCustomObject] @{ ComputerName = $nombre # 正确填入当前设备名 SoftwareName = $soft.Name PackageName = $soft.PackageName InstallDate = $soft.InstallDate } } } catch { Write-Warning "设备 $nombre 通信失败,跳过:$_" } } # 导出结果 $Result | Export-Csv -Path $exportPath -UseCulture -NoTypeInformation -Encoding UTF8 # 如需弹窗预览可以打开下面的注释 # $Result | Out-GridView
注意事项
- 运行脚本前需要先安装AD域管理模块,且用拥有域设备本地管理员权限的账号执行
- 可通过组策略批量给域设备放开WMI入站防火墙规则,避免CIM调用被拦截
- 如果仅需要查询特定软件(比如你脚本开头写的Adobe Acrobat DC),建议改用远程读取注册表的方式实现,完全避免Win32_Product的副作用,执行效率也会提升数倍
内容的提问来源于stack exchange,提问作者andresgonz21
相关产品推荐
相关产品推荐

