PowerShell嵌套PSCustomObject数组大小写敏感过滤问题调试求助
问题场景
需要对$objects数组中的嵌套PSCustomObject标签属性,与$filterTags中的值进行大小写敏感匹配过滤,预期仅返回Object2和Object3,但当前代码意外包含了Object4;换用-ccontains后又错误包含了Object1。
原始代码及输出
# Filtering on the following strings. ***Must match case*** $filterTags = @("application","environment") $objects = @( [PSCustomObject]@{ Name = "Object1"; tags = [PSCustomObject]@{ "Application" = "App1"; Environment = "Env1" }}, [PSCustomObject]@{ Name = "Object2"; tags = [PSCustomObject]@{ "Application" = "App2"; environment = "Env2" }}, [PSCustomObject]@{ Name = "Object3"; tags = [PSCustomObject]@{ "application" = "App3"; Environment = "Env3" }}, [PSCustomObject]@{ Name = "Object4"; tags = [PSCustomObject]@{ "Migrate Project" = "Migration1"}} ) $objects | Where-Object { $tagsNames = $_.tags.PSObject.Properties.Name $filterTags | ForEach-Object { $tagsNames -ceq $_ } }
输出结果:
Name tags ---- ---- Object2 @{Application=App2; environment=Env2} Object3 @{application=App3; Environment=Env3} Object4 @{Migrate Project=Migration1}
换用-ccontains的错误尝试
$objects | Where-Object { $_.tags.PSObject.Properties.Name | % {$filterTags -ccontains $_ } }
返回结果包含Object1、Object2、Object3,不符合预期。
问题根源分析
Object4被错误保留的原因
Where-Object的判断逻辑是:只要脚本块返回非空/非False的集合/值,就会保留对象。对Object4来说,$filterTags | ForEach-Object { $tagsNames -ceq $_ }返回两个False,但这是一个非空集合,PowerShell会将其视为True,因此Object4被错误保留。换用
-ccontains后包含Object1的原因
该写法的逻辑是遍历每个标签名,只要有一个标签名存在于$filterTags中就返回True,但此处的变量名可能存在笔误(原代码写的$myTags应为$filterTags),且逻辑未明确要求至少一个完全大小写匹配——实际Object1的标签名是首字母大写的Application/Environment,与$filterTags的小写值不匹配,推测是变量名错误导致逻辑失效。
正确解决方案
核心需求:对象的tags属性中,至少有一个属性名与$filterTags中的任意一项大小写完全匹配,同时排除无匹配项的对象。
方案1:PowerShell 7+ 简洁写法(使用-cin和Test-Any)
$objects | Where-Object { $_.tags.PSObject.Properties.Name | Test-Any { $_ -cin $filterTags } }
方案2:兼容PowerShell 5.1的写法
$objects | Where-Object { # 筛选出大小写完全匹配的标签名 $matchingTags = $_.tags.PSObject.Properties.Name | Where-Object { $_ -cin $filterTags } # 转换为布尔值:非空集合为True,空集合为False [bool]$matchingTags }
验证结果
执行上述代码后,将正确返回Object2和Object3,排除Object1和Object4。
关键知识点
-ceq:大小写敏感的相等比较运算符;-cin:大小写敏感的“包含于”运算符,适合判断单个元素是否在目标数组中。Where-Object脚本块返回值规则:空集合、$null、0、空字符串会被视为False;非空集合、非零数值、非空字符串会被视为True——这是Object4被错误保留的核心原因。
内容的提问来源于stack exchange,提问作者Matthew McDonald

