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

如何在PowerShell 7中移除OrderedDictionary的$null和空白键值对?

解决OrderedDictionary空值与空白键值对移除问题

我编写的Remove-NullAndEmptyProperties函数可正常移除Hashtable、PSCustomObject中的$null及空白键值对,但处理[System.Collections.Specialized.OrderedDictionary](即[ordered]@{...})时失效并报错。现需要一个健壮的方案,支持遍历OrderedDictionary并移除其中的$null和空白键值对。

现有函数代码

Function Remove-NullAndEmptyProperties {
    [CmdletBinding()]
    Param(
        # 要移除空值的对象
        [Parameter(ValueFromPipeline,Mandatory,Position=0)]
        $InputObject,
        # 是否保留空字符串(默认移除)
        [Switch]$LeaveEmptyStrings,
        # 额外需要移除的键值(支持对象或其字符串形式)
        [Object[]]$AlsoRemove = @()
    )

    begin {
        $IsNonRefType = {
            param (
                [AllowNull()]
                $Val
            )
            return (($null -ne $Val) -and (-not($Val.GetType().IsValueType)))
        }
    }

    Process {

        try  {

            $IsValidType = (& $IsNonRefType -Val $InputObject)
            if(-not$IsValidType){
                Write-Error "输入对象类型无效。"
                return
            }

            if($InputObject.GetType().name -eq 'Hashtable'){
                $TmpString = $InputObject | ConvertTo-Json -Depth 15
                $TmpString = $TmpString -replace '"\w+?"\s*:\s*null,?'
                if(!$LeaveEmptyStrings){
                    $TmpString = $TmpString -replace '"\w+?"\s*:\s*"\s+"?,?'
                }
                $NewHash = $TmpString | ConvertFrom-Json
                $NewHash
            } else {
                # 处理数组输入的情况
                ForEach ($obj in $InputObject) {
                    $obj | Select-Object -Property (
                        $obj.PSObject.Properties.Name | Where-Object {
                            -not (
                                # 移除null值
                                $null -eq $obj.$_ -or
                                # 未指定保留空字符串时,移除空白字符串
                                (-not $LeaveEmptyStrings.IsPresent -and
                                    [string]::IsNullOrWhiteSpace($obj.$_)) -or
                                # 移除AlsoRemove指定的对象
                                $AlsoRemove.Contains($obj.$_) -or
                                # 移除AlsoRemove指定的字符串形式对象
                                $AlsoRemove.Contains($obj.$_.ToString())
                            )
                        }
                    )
                }
            }
        }
        catch {
            Write-Output "发生终止错误: $($PSItem.ToString())"
            $PSCmdlet.ThrowTerminatingError($PSItem)
        }
    }
}

报错测试用例

$OHash = [ordered]@{
    "Key1" = 'Alpha'
    "Key2" = '  '
    "Key3" = 'Beta'
    "Key4" = $null
    "Key5" = 'Omega'
}

$OHash | Remove-NullAndEmptyProperties

解决方案

原函数的问题在于仅针对Hashtable做了特殊处理,OrderedDictionary被归类到else分支用Select-Object处理,但这种方式不适合字典类型。以下是修改后的健壮函数,单独处理OrderedDictionary,同时优化Hashtable的处理逻辑,避免JSON转换带来的类型丢失、深度限制等问题:

修改后的函数代码

Function Remove-NullAndEmptyProperties {
    [CmdletBinding()]
    Param(
        # 要移除空值的对象
        [Parameter(ValueFromPipeline,Mandatory,Position=0)]
        $InputObject,
        # 是否保留空字符串(默认移除)
        [Switch]$LeaveEmptyStrings,
        # 额外需要移除的键值(支持对象或其字符串形式)
        [Object[]]$AlsoRemove = @()
    )

    Process {
        foreach ($item in $InputObject) {
            try {
                # 值类型直接返回并报错
                if ($null -ne $item -and $item.GetType().IsValueType) {
                    Write-Error "输入对象类型无效。"
                    return
                }

                # 处理OrderedDictionary,保留原有顺序
                if ($item -is [System.Collections.Specialized.OrderedDictionary]) {
                    $newOrderedDict = [ordered]@{}
                    foreach ($key in $item.Keys) {
                        $value = $item[$key]
                        $keep = $true
                        
                        # 判断是否需要移除当前键值对
                        if ($null -eq $value) {
                            $keep = $false
                        }
                        elseif (-not $LeaveEmptyStrings -and [string]::IsNullOrWhiteSpace($value)) {
                            $keep = $false
                        }
                        elseif ($AlsoRemove.Contains($value) -or $AlsoRemove.Contains($value.ToString())) {
                            $keep = $false
                        }

                        if ($keep) {
                            $newOrderedDict[$key] = $value
                        }
                    }
                    $newOrderedDict
                    continue
                }

                # 处理Hashtable
                if ($item -is [Hashtable]) {
                    $newHashtable = @{}
                    foreach ($key in $item.Keys) {
                        $value = $item[$key]
                        $keep = $true
                        
                        if ($null -eq $value) {
                            $keep = $false
                        }
                        elseif (-not $LeaveEmptyStrings -and [string]::IsNullOrWhiteSpace($value)) {
                            $keep = $false
                        }
                        elseif ($AlsoRemove.Contains($value) -or $AlsoRemove.Contains($value.ToString())) {
                            $keep = $false
                        }

                        if ($keep) {
                            $newHashtable[$key] = $value
                        }
                    }
                    $newHashtable
                    continue
                }

                # 处理PSCustomObject及其他带PSObject属性的类型
                if ($item.PSObject.Properties) {
                    $validProps = $item.PSObject.Properties.Name | Where-Object {
                        $value = $item.$_
                        -not (
                            $null -eq $value -or
                            (-not $LeaveEmptyStrings -and [string]::IsNullOrWhiteSpace($value)) -or
                            $AlsoRemove.Contains($value) -or
                            $AlsoRemove.Contains($value.ToString())
                        )
                    }
                    $item | Select-Object -Property $validProps
                    continue
                }

                # 无法处理的类型直接返回原对象
                $item
            }
            catch {
                Write-Error "处理对象时出错: $($_.Exception.Message)"
                $PSCmdlet.ThrowTerminatingError($_)
            }
        }
    }
}

关键改进点

  • 单独识别并处理OrderedDictionary,通过遍历键值对构建新的有序字典,完全保留原顺序
  • 替换Hashtable的JSON转换逻辑为直接遍历,避免类型丢失、深度限制等问题
  • 统一三种类型(OrderedDictionary/Hashtable/PSCustomObject)的判断规则,确保逻辑一致性
  • 优化管道输入数组的处理逻辑,更符合PowerShell管道的使用习惯
  • 增加对无法处理类型的兼容,直接返回原对象

测试验证

运行之前的OrderedDictionary测试用例,会输出移除了空白值(Key2)和null值(Key4)的结果:

Name                           Value
----                           -----
Key1                           Alpha
Key3                           Beta
Key5                           Omega

原有的Hashtable和PSCustomObject处理逻辑保持正常,例如:

# 测试Hashtable
$hash = @{a=1; b=$null; c='   '; d='test'}
$hash | Remove-NullAndEmptyProperties

# 测试PSCustomObject
$obj = [PSCustomObject]@{Name='Alice'; Age=$null; Address='   '; Email='alice@test.com'}
$obj | Remove-NullAndEmptyProperties

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.09 17:57:02