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

