无法通过Get-Properties获取XML属性值,求递归提取XML属性至对象方案
PowerShell递归提取XML嵌套属性到对象
需求
在PowerShell中处理XML变量时,需要递归提取所有嵌套的System.Xml.XmlElement类型子属性的字符串值,并将所有属性扁平化后赋值到一个对象中。例如:
$xml.object1 # 包含子属性,类型为System.Xml.XmlElement $xml.object2 # 包含子属性,类型为System.Xml.XmlElement $xml.object3 # 类型为字符串 $xml.object4 # 类型为字符串
需要提取object1和object2的所有多层嵌套子属性值,比如$xml.object1.object11.object111.object1111这类层级结构的值。
尝试过的方法及问题
使用Do/Until循环遇到实现困难后,转而使用Get-Properties,但无法通过其输出获取属性值,尝试了多种写法均无效:
get-properties -object $xml -pathname object1 | select -first 1 | foreach-object { #attempt1 $p = $xml.$_ $p #attempt2 $string = $_ | out-string $xml.$string } get-properties -object $xml | select -first 1 | foreach-object { #attempt3 $split = $_ -split ('$_.') | select -last 1 | out-string $xml.$split #attempt4 [string]$string = $_ $split = $string -split ('$_.') | select -last 1 $xml.$split #attempt5 $string = $_ | out-string $split = $string -split ('$_.') | select -last 1 $xml.$split }
由于对象基类型为System.Object,无法确定如何转换为字符串以获取属性值。
处理的XML示例片段(gpresult生成)
<OneX xmlns="http://www.microsoft.com/networking/OneX/v1"> <cacheUserData>true</cacheUserData> <heldPeriod>1</heldPeriod> <authPeriod>18</authPeriod> <startPeriod>5</startPeriod> <maxStart>3</maxStart> <maxAuthFailures>1</maxAuthFailures> <authMode>machineOrUser</authMode> <singleSignOn> <type>postLogon</type> <maxDelay>10</maxDelay> <allowAdditionalDialogs>false</allowAdditionalDialogs> <userBasedVirtualLan>false</userBasedVirtualLan> </singleSignOn> <EAPConfig> <EapHostConfig xmlns="http://www.microsoft.com/provisioning/EapHostConfig"> <EapMethod> <Type xmlns="http://www.microsoft.com/provisioning/EapCommon">25</Type> <VendorId xmlns="http://www.microsoft.com/provisioning/EapCommon">0</VendorId> <VendorType xmlns="http://www.microsoft.com/provisioning/EapCommon">0</VendorType> <AuthorId xmlns="http://www.microsoft.com/provisioning/EapCommon">0</AuthorId> </EapMethod> <Config xmlns="http://www.microsoft.com/provisioning/EapHostConfig"> <Eap xmlns="http://www.microsoft.com/provisioning/BaseEapConnectionPropertiesV1"> <Type>25</Type> <EapType xmlns="http://www.microsoft.com/provisioning/MsPeapConnectionPropertiesV1"> <ServerValidation> <DisableUserPromptForServerValidation>false</DisableUserPromptForServerValidation> <ServerNames> </ServerNames> </ServerValidation> <FastReconnect>true</FastReconnect> <InnerEapOptional>false</InnerEapOptional> <Eap xmlns="http://www.microsoft.com/provisioning/BaseEapConnectionPropertiesV1"> <Type>26</Type> <EapType xmlns="http://www.microsoft.com/provisioning/MsChapV2ConnectionPropertiesV1"> <UseWinLogonCredentials>true</UseWinLogonCredentials> </EapType> </Eap> <EnableQuarantineChecks>false</EnableQuarantineChecks> <RequireCryptoBinding>false</RequireCryptoBinding> <PeapExtensions> <PerformServerValidation xmlns="http://www.microsoft.com/provisioning/MsPeapConnectionPropertiesV2">true</PerformServerValidation> <AcceptServerName xmlns="http://www.microsoft.com/provisioning/MsPeapConnectionPropertiesV2">false</AcceptServerName> </PeapExtensions> </EapType> </Eap> </Config> </EapHostConfig> </EAPConfig> </OneX>
明确需求细节
- 将所有属性及子属性扁平化处理(无嵌套结构)
- 过滤掉xmlns命名空间链接
- 若属性名为
type,使用“父节点名称 Type”作为属性名
解决方案
参考TheMadTechnician的脚本修改后,实现代码如下:
select-xml -xml $onex -XPath '//*'|?{$_.node.'#text'}|%{ $ThisNode = $_.Node $PathArr = do{ $ThisNode.Name $ThisNode = $ThisNode.psbase.parentnode }until(!$ThisNode.psbase.parentnode) [array]::Reverse($PathArr) $PathString = $PathArr -join '.' if ($pathstring -like "*.OneX*") { $selectlast1 = $pathstring -split ('OneX.') | select -Last 1 if ($selectlast1 -like "*type") { [string]$n = ($selectlast1.split('.') | select -Last 2) -join (' ') } else { [string]$n = $selectlast1.split('.') | select -Last 1 } [string]$v = $_.node.'#Text' $onexobj | Add-Member -MemberType NoteProperty -Name $n -Value $v } }
内容的提问来源于stack exchange,提问作者takeitback86
相关产品推荐
相关产品推荐

