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

PowerShell中PSCustomObject动态字段缺失问题解决方法

问题解决:PowerShell多数据源合并时字段丢失问题

问题场景

处理多数据源数据提取:

  • List A($inventory):响应率100%,仅包含Server和PatchTime两个数据点
  • List B(.\facts*):数据点丰富但响应率非100%

当前代码存在问题:当$data数组的第一个对象来自List A时,后续所有对象仅保留2个数据点;若第一个对象来自List B,最终所有对象能保留全部数据点。

问题原因

PowerShell的数组是强类型集合,当向空数组中添加第一个对象时,数组会继承该对象的属性结构。后续添加的对象如果有额外属性,会被自动丢弃以匹配数组的结构。

解决方案

统一所有对象的属性结构,确保每个对象都包含所有需要的字段,缺失的字段赋值为$null即可。

修改后的代码

$list = Get-Content .\list.json -Raw | ConvertFrom-Json
$inventory = $list._meta.hostvars | Get-Member -MemberType NoteProperty

$data = @()
foreach ($server in $inventory.Name) {
    # 初始化所有字段为null,统一结构
    $serverObj = [pscustomobject]@{
        Server                = $server
        PatchTime             = ($list._meta.hostvars.($server)).patchtime
        OSname                = $null
        ServerType            = $null
        DNSdomain             = $null
        PysicalMemory         = $null
        PageFileSize          = $null
        TotalCPUcoreCount     = $null
        Sockets               = $null
        CoresPerSockets       = $null
        HyperthreadingEnabled = $null
        System                = $null
        VolumeName            = $null
        VolumeCapacity        = $null
        IPaddress             = $null
    }

    if (Test-Path -Path .\facts\$server -PathType Leaf) {
        $myJson = Get-Content .\facts\$server -Raw | ConvertFrom-Json
        # 填充List B的字段
        $serverObj.OSname                = "$($myJson.ansible_distribution_file_variety) $($myJson.ansible_distribution_major_version)"
        $serverObj.ServerType            = $myJson.ansible_system
        $serverObj.DNSdomain             = $myJson.ansible_domain
        $serverObj.PysicalMemory         = $myJson.ansible_memtotal_mb
        $serverObj.PageFileSize          = $myJson.ansible_swaptotal_mb
        $serverObj.TotalCPUcoreCount     = $myJson.ansible_processor_vcpus
        $serverObj.Sockets               = $myJson.ansible_processor_count
        $serverObj.CoresPerSockets       = $myJson.ansible_processor_cores
        $serverObj.HyperthreadingEnabled = $myJson.ansible_processor_threads_per_core
        $serverObj.System                = $myJson.ansible_env.SAIDKEY
        $serverObj.VolumeName            = $myJson.ansible_mounts.mount
        $serverObj.VolumeCapacity        = $myJson.ansible_mounts.size_total
        $serverObj.IPaddress             = $myJson.ansible_all_ipv4_addresses
    }

    $data += $serverObj
}

另一种简化方案:使用Select-Object强制保留字段

如果不想提前定义所有字段,可以在添加对象到数组前,用Select-Object指定所有需要的字段,确保结构统一:

$list = Get-Content .\list.json -Raw | ConvertFrom-Json
$inventory = $list._meta.hostvars | Get-Member -MemberType NoteProperty

$data = @()
# 定义所有需要的字段集合
$allFields = @('Server', 'PatchTime', 'OSname', 'ServerType', 'DNSdomain', 'PysicalMemory', 'PageFileSize', 'TotalCPUcoreCount', 'Sockets', 'CoresPerSockets', 'HyperthreadingEnabled', 'System', 'VolumeName', 'VolumeCapacity', 'IPaddress')

foreach ($server in $inventory.Name) {
    if (Test-Path -Path .\facts\$server -PathType Leaf) {
        $myJson = Get-Content .\facts\$server -Raw | ConvertFrom-Json
        $serverObj = [pscustomobject]@{
            Server = $server
            PatchTime = ($list._meta.hostvars.($server)).patchtime            
            OSname = "$($myJson.ansible_distribution_file_variety) $($myJson.ansible_distribution_major_version)"
            ServerType = $myJson.ansible_system
            DNSdomain = $myJson.ansible_domain
            PysicalMemory   = $myJson.ansible_memtotal_mb
            PageFileSize = $myJson.ansible_swaptotal_mb
            TotalCPUcoreCount = $myJson.ansible_processor_vcpus
            Sockets = $myJson.ansible_processor_count
            CoresPerSockets = $myJson.ansible_processor_cores
            HyperthreadingEnabled = $myJson.ansible_processor_threads_per_core
            System = $myJson.ansible_env.SAIDKEY
            VolumeName = $myJson.ansible_mounts.mount
            VolumeCapacity = $myJson.ansible_mounts.size_total
            IPaddress = $myJson.ansible_all_ipv4_addresses
        } | Select-Object $allFields
    }
    else {
        $serverObj = [pscustomobject]@{
            Server = $server
            PatchTime = ($list._meta.hostvars.($server)).patchtime
        } | Select-Object $allFields
    }
    $data += $serverObj
}

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.24 05:38:19