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
相关产品推荐
相关产品推荐

