求助:用VBS解析PowerShell PSCustomObject XML并生成多层数组
读取PowerShell导出的PSCustomObject XML并生成多层数组(VBS实现)
需求:读取PowerShell输出的PSCustomObject格式XML,将其中的对象数据转换为多层数组或ArrayList。自行尝试编写VBS代码但在XPath查询节点时失败。
PowerShell输出的XML示例
<Objs Version="1.1.0.1" xmlns="http://schemas.microsoft.com/powershell/2004/04"> <Obj RefId="0"> <TN RefId="0"> <T>Selected.System.String</T> <T>System.Management.Automation.PSCustomObject</T> <T>System.Object</T> </TN> <MS> <I32 N="RefNum">1</I32> <S N="Name">MyVMName</S> <S N="Type">VM</S> <!-- Additional properties --> </MS> </Obj> <!-- Additional objects --> </Objs>
尝试的VBS代码
Set xmlDoc = CreateObject("MSXML2.DOMDocument.6.0") xmlDoc.Async = False ' Load the PowerShell XML content xmlDoc.Load "your_powershell_xml_file.xml" If xmlDoc.ParseError = 0 Then ' Use the namespace in XPath queries xmlDoc.setProperty "SelectionNamespaces", "xmlns:ps='http://schemas.microsoft.com/powershell/2004/04'" ' Select all PSCustomObject elements Set customObjects = xmlDoc.SelectNodes("//ps:Obj[TN/T='System.Management.Automation.PSCustomObject']") ' Iterate through PSCustomObject elements For Each customObject In customObjects ' Access properties within the PSCustomObject RefNum = customObject.SelectSingleNode("MS/I32[@N='RefNum']").Text Name = customObject.SelectSingleNode("MS/S[@N='Name']").Text Type = customObject.SelectSingleNode("MS/S[@N='Type']").Text ' Display the parsed properties WScript.Echo "RefNum: " & RefNum WScript.Echo "Name: " & Name WScript.Echo "Type: " & Type Next Else ' Handle XML parsing error WScript.Echo "Error loading PowerShell XML: " & xmlDoc.ParseError.Reason End If
错误原因
XPath查询中,TN和T元素未添加命名空间前缀ps:,而整个XML文档的所有元素都属于http://schemas.microsoft.com/powershell/2004/04命名空间,导致节点匹配失败。后续读取属性节点时也未添加命名空间前缀,同样会引发错误。
修正后的代码(支持生成ArrayList)
Set xmlDoc = CreateObject("MSXML2.DOMDocument.6.0") xmlDoc.Async = False xmlDoc.SetProperty "SelectionLanguage", "XPath" xmlDoc.SetProperty "SelectionNamespaces", "xmlns:ps='http://schemas.microsoft.com/powershell/2004/04'" ' Load XML文件 xmlDoc.Load "your_powershell_xml_file.xml" If xmlDoc.ParseError = 0 Then ' 创建ArrayList存储所有对象数据 Set objArrayList = CreateObject("System.Collections.ArrayList") ' 正确选择所有PSCustomObject节点(所有元素加ps:前缀) Set customObjects = xmlDoc.SelectNodes("//ps:Obj[ps:TN/ps:T='System.Management.Automation.PSCustomObject']") For Each customObject In customObjects ' 创建数组存储当前对象的属性 Dim objProps() ReDim objProps(2) ' 根据实际属性数量调整,这里示例3个属性 ' 读取属性时添加ps:前缀,同时处理节点不存在的情况 Set refNumNode = customObject.SelectSingleNode("ps:MS/ps:I32[@N='RefNum']") If Not refNumNode Is Nothing Then objProps(0) = refNumNode.Text Else objProps(0) = "" End If Set nameNode = customObject.SelectSingleNode("ps:MS/ps:S[@N='Name']") If Not nameNode Is Nothing Then objProps(1) = nameNode.Text Else objProps(1) = "" End If Set typeNode = customObject.SelectSingleNode("ps:MS/ps:S[@N='Type']") If Not typeNode Is Nothing Then objProps(2) = typeNode.Text Else objProps(2) = "" End If ' 将属性数组加入ArrayList objArrayList.Add objProps ' 输出测试 WScript.Echo "RefNum: " & objProps(0) WScript.Echo "Name: " & objProps(1) WScript.Echo "Type: " & objProps(2) WScript.Echo "-----" Next ' 可选:遍历ArrayList验证结果 WScript.Echo "Total objects parsed: " & objArrayList.Count For Each item In objArrayList WScript.Echo "Item: " & item(0) & ", " & item(1) & ", " & item(2) Next Else WScript.Echo "XML解析错误: " & xmlDoc.ParseError.Reason & " (行号: " & xmlDoc.ParseError.Line & ")" End If
关键修正点
- 所有XPath查询的元素均添加
ps:命名空间前缀,确保节点匹配正确 - 添加
SelectionLanguage属性设置为XPath,避免解析歧义 - 加入
System.Collections.ArrayList实现多层数组存储需求 - 增加节点存在性判断,防止因缺失属性导致脚本崩溃
- 注释清晰,便于扩展更多属性读取逻辑
内容的提问来源于stack exchange,提问作者OldManWithTime
相关产品推荐
相关产品推荐

