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

递归移除PSObject转JSON空列表的PowerShell函数优化求助

处理PSObject转JSON时移除空列表的递归函数优化

问题描述

我构建了一个PSObject,转换为JSON后包含大量空列表,需要移除这些空列表以作为API更新数据的HTTP请求体。尝试编写递归处理函数,但遇到两个问题:仅对象的最后一项接近预期目标,且部分属性在递归调用后未被正确移除。现有函数会解析原PSObject属性,针对add、remove节点递归调用,手动排查并通过Select-Object移除空属性,但效果不佳。

原始JSON示例

{"add": {"windows": {"files": [], "directories": []}, "Applications": [{"processfile": {"sha2": "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa", "name": "Aurelien test.exe"}}], "Certificates": [], "webdomains": [], "ips_hosts": [], "Extensions": {"names": [], "scheduled": false, "features": []}, "linux": {"files": [], "directories": []}, "mac": {"files": [], "directories": []}}, "remove": {"Applications": [], "Certificates": [], "webdomains": [], "ips_hosts": [], "Extensions": {"names": [], "scheduled": false, "features": []}, "windows": {"files": [], "directories": []}, "linux": {"files": [], "directories": []}, "mac": {"files": [], "directories": []}}}

预期JSON结果

{"add": {"Applications": [{"processfile": {"sha2": "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa", "name": "Aurelien test.exe"}}]}}

现有函数代码

function Optimize-SepCloudAllowListPolicyObject {
 [CmdletBinding()]
 param (
     [Parameter(Mandatory = $true, ValueFromPipeline = $true)]
     [PSObject]
     $obj
 )

 process {
     $AllProperties = $obj | Get-Member -MemberType NoteProperty | Select-Object -ExpandProperty Name
     foreach ($property in $AllProperties) {
         switch ($property) {
             { $_ -in @("add", "remove") } {
                 Optimize-SepCloudAllowListPolicyObject $obj.$property
             }
             "applications" {
                 if ($obj.$property.processfile.count -eq 0) {
                     $obj = $obj | Select-Object -ExcludeProperty $property
                 }
             }
             "webdomains" {
                 if ($obj.$property.count -eq 0) {
                     $obj = $obj | Select-Object -ExcludeProperty $property
                 }
             }
             "certificates" {
                 if ($obj.$property.count -eq 0) {
                     $obj = $obj | Select-Object -ExcludeProperty $property
                 }
             }
             "ips_hosts" {
                 if ($obj.$property.count -eq 0) {
                     $obj = $obj | Select-Object -ExcludeProperty $property
                 }
             }
             "extensions" {
                 if ($obj.$property.names.count -eq 0) {
                     $obj = $obj | Select-Object -ExcludeProperty $property
                 }
             }
             "linux" {
                 if ($obj.$property.linux.files.count -eq 0) {
                     $obj.$property = $obj.$property | Select-Object -ExcludeProperty "files"
                 }
                 if ($obj.$property.linux.directories.count -eq 0) {
                     $obj.$property = $obj.$property | Select-Object -ExcludeProperty "directories"
                 }
             }
             "windows" {
                 if ($obj.$property.windows.files.count -eq 0) {
                     $obj.$property = $obj.$property | Select-Object -ExcludeProperty "files"
                 }
                 if ($obj.$property.windows.directories.count -eq 0) {
                     $obj.$property = $obj.$property | Select-Object -ExcludeProperty "directories"
                 }
             }
             "mac" {
                 if ($obj.$property.mac.files.count -eq 0) {
                     $obj.$property = $obj.$property | Select-Object -ExcludeProperty "files"
                 }
                 if ($obj.$property.mac.directories.count -eq 0) {
                     $obj.$property = $obj.$property | Select-Object -ExcludeProperty "directories"
                 }
             }
             Default {}
         }
     }

     return $obj
 }
}

优化指引与改进后的函数

现有函数的核心问题

  1. 递归调用未赋值:处理add/remove节点时,仅调用递归函数但未将返回的处理结果赋值回原属性,导致递归处理的修改未被保留。
  2. 大小写不匹配:原始对象属性为Applications(首字母大写),但函数中判断的是小写applications,对应逻辑完全未触发。
  3. 嵌套属性访问错误:例如$obj.$property.linux.files,$obj.$property已经是linux对象,无需再嵌套linux访问,导致判断逻辑失效。
  4. 未处理空对象:当子属性被全部移除后(如windows的files和directories都为空被移除),windows会变成空对象,但现有函数未进一步移除这类空对象;同理remove节点所有子属性为空时,未被整体移除。
  5. 硬编码属性判断:每个属性单独写判断逻辑,扩展性差且容易遗漏。

改进后的函数

function Optimize-SepCloudAllowListPolicyObject {
    [CmdletBinding()]
    param (
        [Parameter(Mandatory = $true, ValueFromPipeline = $true)]
        [PSObject]$obj
    )

    process {
        # 创建新对象存储处理后的结果,避免修改原对象导致的遍历问题
        $processedObj = [PSCustomObject]@{}
        $allProperties = $obj | Get-Member -MemberType NoteProperty | Select-Object -ExpandProperty Name

        foreach ($property in $allProperties) {
            $value = $obj.$property

            # 递归处理嵌套对象
            if ($value -is [PSObject]) {
                $processedValue = Optimize-SepCloudAllowListPolicyObject $value
                # 若处理后的值为空(无属性),则跳过添加该属性
                if (-not [string]::IsNullOrEmpty($processedValue | Get-Member -MemberType NoteProperty -ErrorAction SilentlyContinue)) {
                    $processedObj | Add-Member -MemberType NoteProperty -Name $property -Value $processedValue
                }
            }
            # 处理数组:仅保留非空数组
            elseif ($value -is [array]) {
                if ($value.Count -gt 0) {
                    $processedObj | Add-Member -MemberType NoteProperty -Name $property -Value $value
                }
            }
            # 处理其他类型(如布尔值):直接保留,如需移除特定值可在此添加判断
            else {
                $processedObj | Add-Member -MemberType NoteProperty -Name $property -Value $value
            }
        }

        # 返回处理后的对象,若为空则返回$null(上层会自动移除该属性)
        if ($processedObj | Get-Member -MemberType NoteProperty -ErrorAction SilentlyContinue) {
            return $processedObj
        }
        else {
            return $null
        }
    }
}

关键优化点说明

  1. 递归赋值与结果保留:递归处理嵌套对象后,将返回的有效结果添加到新对象中,确保修改被保留。
  2. 通用空值过滤:统一判断数组是否为空、对象是否无属性,自动跳过空内容,无需硬编码每个属性。
  3. 避免原对象修改问题:创建新对象存储处理结果,避免遍历原对象时修改属性导致的遍历异常。
  4. 自动移除空父节点:如果处理后的子对象为空,则不添加到父对象中,最终自动移除空的remove节点、空的windows/linux等节点。
  5. 灵活扩展:如需移除特定值(如false),可在非数组/对象的处理分支中添加判断逻辑。

测试验证

将原始JSON转换为PSObject后调用优化函数,再转JSON即可得到预期结果:

# 原始JSON转PSObject
$originalObj = '{"add": {"windows": {"files": [], "directories": []}, "Applications": [{"processfile": {"sha2": "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa", "name": "Aurelien test.exe"}}], "Certificates": [], "webdomains": [], "ips_hosts": [], "Extensions": {"names": [], "scheduled": false, "features": []}, "linux": {"files": [], "directories": []}, "mac": {"files": [], "directories": []}}, "remove": {"Applications": [], "Certificates": [], "webdomains": [], "ips_hosts": [], "Extensions": {"names": [], "scheduled": false, "features": []}, "windows": {"files": [], "directories": []}, "linux": {"files": [], "directories": []}, "mac": {"files": [], "directories": []}}}' | ConvertFrom-Json

# 处理对象
$optimizedObj = Optimize-SepCloudAllowListPolicyObject $originalObj

# 转换为JSON
$optimizedObj | ConvertTo-Json -Depth 10

输出结果与预期完全一致。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.12 21:48:11