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

PowerShell读取计算机列表导出系统信息时PCName重复写入问题排查

问题分析:PowerShell脚本导出CSV出现重复计算机名称

核心原因

1. 连通性测试逻辑完全失效

脚本中$TstConnect = test-connection $Computer被放在循环外部,此时$Computer尚未从computers.txt读取任何值,导致该变量要么为空,要么保留之前PowerShell会话中的旧计算机值。这会使得后续的在线判断if ($TstConnect.IPV4Address.IPAddressToString[0])完全失效:

  • 如果旧值对应的计算机在线,所有循环都会进入在线分支,即使当前遍历的计算机离线;
  • 当WMI查询失败时,$computerSystem、$computerBIOS等变量会保留上一次循环的有效值,最终导致CSV写入重复的旧计算机信息。

2. 多实例WMI查询未处理

部分WMI类会返回多个实例(例如Win32_Processor对应多核心CPU、Win32_LogicalDisk对应多个本地磁盘、Win32_NetworkAdapterConfiguration对应多网卡),直接将集合对象赋值给CSV属性时,PowerShell会自动将数组元素拆分成多行写入,从而出现重复的PCName(其他属性对应不同实例的值)。

修复方案

1. 修正连通性测试位置

将连通性测试移到循环内部,确保每次遍历都针对当前计算机执行测试:

foreach ($Computer in Get-Content c:\myfolder\computers.txt) {
    $i++
    $p = "{0:N1}" -f ($i * 100 / $t)
    # 移到循环内,每次测试当前计算机
    $TstConnect = Test-Connection $Computer -Count 1 -Quiet -ErrorAction SilentlyContinue
    if ($TstConnect) { 
        # 后续在线分支逻辑...
    }
    # 离线分支逻辑...
}

2. 处理多实例WMI结果

对可能返回多个实例的WMI查询,通过Select-Object -First 1或索引[0]获取单个实例,避免数组导致的多行写入:

# 取第一个CPU实例
$computerCPU = Get-WmiObject Win32_Processor -Computer $Computer | Select-Object -First 1
# 取第一个本地磁盘
$computerHDD = Get-WmiObject Win32_LogicalDisk -ComputerName $Computer -Filter drivetype=3 | Select-Object -First 1
# 取第一个符合条件的以太网网卡
$computerNET = Get-WmiObject -Class Win32_NetworkAdapterConfiguration -ComputerName $Computer | 
    Where-Object { $_.IPAddress -ne $null -and $_.Description -like "*Ethernet*" } |
    Select-Object -First 1

3. 优化变量作用域

在循环内部初始化关键变量,避免上一次循环的值残留:

foreach ($Computer in Get-Content c:\myfolder\computers.txt) {
    # 每次循环初始化变量
    $computerSystem = $null
    $computerBIOS = $null
    $AssetTag = $null
    # ...其他变量初始化
    # 后续逻辑...
}

完整修正后的脚本示例

Set-Location "c:\myfolder"
$ErrorActionPreference = 'SilentlyContinue'
$exportFile = 'c:\myfolder\system-info.csv'

$t = 0
$i = 0
$tab_char = [char]9

#Clear screen & old file
Clear-Host
try {
    $file = [System.IO.File]::Open($exportfile, 'Open', 'Read', 'None')
    $file.Close()
    Write-Host "File $exportfile is not open. Deleting old results file... $exportfile" -BackgroundColor DarkCyan
    Remove-Item $exportFile
} catch {
    Write-Host "File is open or in use by another process. Ending the task." -BackgroundColor DarkRed
    break
}

# Get Totals    
foreach ($Computer in Get-Content c:\myfolder\computers.txt) {
    $t++
}
     
Write-Host "$t total computers " -BackgroundColor DarkCyan

foreach ($Computer in Get-Content c:\myfolder\computers.txt) {
    $i++
    $p = "{0:N1}" -f ($i * 100 / $t)
    # 移到循环内的连通性测试
    $TstConnect = Test-Connection $Computer -Count 1 -Quiet -ErrorAction SilentlyContinue
    
    # 初始化变量,避免残留
    $computerSystem = $null
    $computerBIOS = $null
    $AssetTag = $null
    $computerOS = $null
    $computerCPU = $null
    $computerNET = $null
    $computerIP = $null
    $computerHDD = $null
    $csvObject = $null

    if ($TstConnect) { 
        $computerSystem = Get-WmiObject Win32_ComputerSystem -Computer $Computer
        if ($computerSystem) {
            Write-Host $computerSystem.name "is online, checking $tab_char $i of $t $tab_char $p% complete " -BackgroundColor DarkCyan 
            $computerBIOS = Get-WmiObject Win32_BIOS -Computer $Computer
            $AssetTag = Get-WmiObject -Class Win32_SystemEnclosure -Computer $Computer | Select-Object SMBiosAssetTag
            $computerOS = Get-WmiObject Win32_OperatingSystem -Computer $Computer
            # 取第一个CPU实例
            $computerCPU = Get-WmiObject Win32_Processor -Computer $Computer | Select-Object -First 1
            # 取第一个符合条件的网卡
            $computerNET = Get-WmiObject -Class Win32_NetworkAdapterConfiguration -ComputerName $Computer | 
                Where-Object { $_.IPAddress -ne $null -and $_.Description -like "*Ethernet*" } |
                Select-Object -First 1
            $computerIP = Get-WmiObject -Class Win32_NetworkAdapterConfiguration -Filter IPEnabled=TRUE -ComputerName $computer | Select-Object -Property ipaddress 
            # 取第一个本地磁盘
            $computerHDD = Get-WmiObject Win32_LogicalDisk -ComputerName $Computer -Filter drivetype=3 | Select-Object -First 1

            $csvObject = New-Object PSObject -Property @{
                'PCName' = $computerSystem.Name
                'MACAddress' = $computerNET.MACAddress
                'IPAddress' = ($computerIP.ipaddress)[0]
                'Manuf' = $computerSystem.Manufacturer
                'Model' = $computerSystem.Model
                'AssetTag' = $AssetTag.SMBiosAssetTag
                'SerialNumber' = $computerBIOS.SerialNumber
                'RAM' = "{0:N2}" -f ($computerSystem.TotalPhysicalMemory/1GB)
                'HDDSize' = if ($computerHDD) { "{0:N2}" -f ($computerHDD.Size/1GB) } else { "N/A" }
                'HDDFree' = if ($computerHDD) { "{0:P2}" -f ($computerHDD.FreeSpace/$computerHDD.Size) } else { "N/A" }
                'CPU' = $computerCPU.Name
                'OS' = $computerOS.caption
                'Version' = $computerOS.Version
                'SP' = $computerOS.ServicePackMajorVersion
                'User' = $computerSystem.UserName
                'BootTime' = $computerOS.ConvertToDateTime($computerOS.LastBootUpTime)
            } 
        } else {
            # 处理WMI查询失败的情况
            Write-Host "$Computer is online but WMI access failed... $p% complete" -BackgroundColor DarkYellow
            $csvObject = New-Object PSObject -Property @{
                'PCName' = $Computer
                'Manuf' = "WMI Access Failed"
                'Model' = "WMI Access Failed"
                'SerialNumber' = "WMI Access Failed"
                'AssetTag' = "WMI Access Failed"
                'RAM' = "WMI Access Failed"
                'HDDSize' = "WMI Access Failed"
                'HDDFree' = "WMI Access Failed"
                'CPU' = "WMI Access Failed"
                'OS' = "WMI Access Failed"
                'Version' = "WMI Access Failed"
                'SP' = "WMI Access Failed"
                'User' = "WMI Access Failed"
                'BootTime' = "WMI Access Failed"
                'MACAddress' = "WMI Access Failed"
                'IPAddress' = "WMI Access Failed"
            }
        }
    } else {
        Write-Host "$Computer is not online... $p% complete" -BackgroundColor DarkRed
        $csvObject = New-Object PSObject -Property @{
            'PCName' = $Computer
            'Manuf' = "xxxxx"
            'Model' = "xxx Offline xxx"
            'SerialNumber' = "xxxxx"
            'AssetTag' = "xxxxx"
            'RAM' = "xxxxx"
            'HDDSize' = "xxxxx"
            'HDDFree' = "xxxxx"
            'CPU' = "xxxxx"
            'OS' = "xxxxx"
            'Version' = "xxxxx"
            'SP' = "xxxxx"
            'User' = "xxxxx"
            'BootTime' = "xxxxx"
            'MACAddress' = "xxxxx"
            'IPAddress' = "xxxxx"
        }
    }
    
    if ($csvObject) {
        $csvObject | Select PCName, HDDFree, Manuf, Model, OS, Version, SP, User, BootTime, MACAddress, IPAddress, AssetTag | 
            Export-Csv $exportfile -NoTypeInformation -Append
    }
}

Write-Host "All computers processed. File created at $exportfile"
do {
    $response = Read-Host -Prompt "Do you want to open the file to view it? (Y/N)"
    if ($response -eq "Y") {
        Write-Host "Opening $exportfile..."
        Start-Process -FilePath $exportfile
        break
    } elseif ($response -eq "N") {
        Write-Host "Exiting..."
        break
    } else {
        Write-Host "Invalid input. Please enter Y or N."
    }
} while ($true)

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.16 05:45:03