You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

多远程系统已安装软件导出至CSV脚本问题排查

嘿,我帮你找出了脚本里的几个核心问题,这才导致它只导出本地数据。咱们一步步来修正,让它能正常抓取远程机器的软件信息:

原脚本的问题分析

  • 没有使用远程计算机名:你在Process块里通过管道拿到的远程机器名是$_,但全程都用了$env:COMPUTERNAME(本地机器名),所以不管txt里写了啥,脚本都只会读取本地数据。
  • 没有远程访问注册表:Get-ItemProperty默认只读取本地注册表,要获取远程机器的软件信息,必须用远程执行的方式。
  • CSV导出会覆盖:每次循环都直接执行Export-CSV,会把之前的结果覆盖掉,最后只能看到最后一次(本地)的数据。
  • 路径硬编码不灵活:输入输出路径都是硬编码的,不方便其他用户修改。

修正后的脚本

Function Export-InstalledSoftware {
    [CmdletBinding()]
    param(
        [Parameter(Mandatory=$true, ValueFromPipeline=$true)]
        [string[]]$ComputerName,
        [string]$OutputPath = "C:\Users\$env:USERNAME\Desktop\SoftwareQuery_$(Get-Date -f yyyy-MM-dd).csv"
    )

    Begin {
        # 初始化数组存储所有结果,避免多次导出覆盖
        $allResults = @()
    }

    Process {
        foreach ($computer in $ComputerName) {
            Write-Host "Processing: $computer"
            # 测试远程机器连通性
            if (Test-Connection -ComputerName $computer -Count 1 -Quiet) {
                try {
                    # 远程执行注册表读取操作,获取软件信息
                    $remoteResults = Invoke-Command -ComputerName $computer -ScriptBlock {
                        Get-ItemProperty -Path HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\*,HKLM:\SOFTWARE\Wow6432Node\Microsoft\Windows\CurrentVersion\Uninstall\* `
                        | Where-Object { $_.DisplayName -ne $null } # 过滤空名称的无效条目
                        | Select-Object @{n='ComputerName';e={$env:COMPUTERNAME}},DisplayName,Publisher,DisplayVersion
                    } -ErrorAction Stop

                    # 将远程结果加入总数组
                    $allResults += $remoteResults
                }
                catch {
                    Write-Warning "Failed to get data from $computer : $_"
                }
            }
            else {
                Write-Warning "Can't ping $computer, skipping this machine..."
            }
        }
    }

    End {
        # 统一排序并导出所有结果到CSV
        $allResults | Sort-Object DisplayName | Export-Csv -Path $OutputPath -NoTypeInformation -Encoding ASCII
        Write-Host "Done! Export file saved to: $OutputPath"
    }
}

# 自定义输入文件路径,用户可以修改这里
$inputFilePath = "C:\Users\$env:USERNAME\Desktop\systems.txt"
Get-Content -Path $inputFilePath | Export-InstalledSoftware

关键改动说明

  1. 参数化路径:把输入文件路径做成变量,输出路径做成可选参数,方便不同用户直接修改,不用动函数内部的代码。
  2. 正确使用远程计算机名:循环里用$computer(来自txt文件的机器名)代替$env:COMPUTERNAME,远程脚本块里的$env:COMPUTERNAME会自动取远程机器的名称,确保CSV里的ComputerName列正确。
  3. 远程执行命令:用Invoke-Command在远程机器上执行注册表读取操作,这样才能拿到真实的远程软件数据(需要目标机器开启WinRM服务,且你有管理员权限)。
  4. 避免CSV覆盖:先把所有结果存到$allResults数组里,最后统一导出,不会出现覆盖问题。
  5. 错误处理:添加try/catch捕获远程执行的错误,用Write-Warning提示,不会因为某一台机器失败导致整个脚本停止。
  6. 过滤无效数据:用Where-Object过滤掉DisplayName为空的条目,避免导出没用的行。

注意事项

  • 要确保远程机器开启了WinRM服务:可以在目标机器上以管理员身份执行Enable-PSRemoting -Force来开启。
  • 你需要有远程机器的管理员权限,才能读取它的注册表信息。
  • 如果不想用Invoke-Command,也可以尝试用Get-CimInstance Win32_Product,但这个命令会触发MSI验证,可能影响远程机器性能,而且有些软件不会被收录,所以远程注册表的方式更可靠。

内容的提问来源于stack exchange,提问作者Bill Hart

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.28 06:37:03