PowerShell:如何将XML转为PSObject并将重复子节点转为数组?
XML转PSObject:处理重复子节点问题
我已经花了一天时间解决这个问题,还是没法构建出优雅且可用的解决方案。
背景
我正在开发一款通用应用安装脚本,既可以配合应用部署软件使用,也能让现场管理员直接操作,目的是保证所有应用部署一致,同时大幅简化部署流程。为了让配置文件尽可能容易创建,我选用了XML格式。但PowerShell和XML交互的体验不太好,所以我打算把配置文件转换成PSObject。这个方案在XML子节点不重复时运行完美,但遇到子节点重复的情况就出问题了。
问题
我需要把同名的XML子节点分组为数组对象(比如:$Result | Add-Member -MemberType:'NoteProperty' -Name:($tXML.name) -Value:$(PSObject数组),也就是把两个Installer节点转成PSObject数组)。我已经能识别到父节点是SystemObject类型(在下面的XML里,Installer和Uninstaller都属于这种情况),但没法按照预期格式把子节点添加成可用的数组。
现有Convert-XMLtoPSObject函数代码
Function Convert-XMLtoPSObject { Param ( $XML ) New-Variable -Name:'Result' -Value:(New-Object -TypeName:'PSCustomObject') $xml | Get-Member -MemberType:'Property' | Where-Object { $_.MemberType -EQ 'Property' } | ForEach-Object -Process:{ $tXML = $_ Switch -Regex ($_.Definition) { '^\bstring\b.*$' { $Result | Add-Member -MemberType:'NoteProperty' -Name:($tXML.Name) -Value:($XML.($tXML.Name)) } '^\bSystem\.Object\b\[] (?!#comment).*$' { Write-Host "SystemObject Baby!" } '^\bSystem.Xml.XmlElement\b.*$' { $Result | Add-Member -MemberType:'NoteProperty' -Name:($tXML.Name) -Value:( Convert-XMLtoPSObject -XML:($XML.($tXML.Name)) ) } '^\bSystem\.Object\b\[] (#comment).*$' { <# Do Nothing #> } Default { Write-Host "Unrecognized Type: $($tXML.Name)='$($tXML.Definition)'" } } } $Result }
配置文件install.xml代码
<AppInstall> <GlobalConfig> <Directory>{$ConfigDir}</Directory> <!-- [String] Install flags to append to all installers. --> <InstallFlags></InstallFlags> <!-- [ScriptBlock] PowerShell script used to test if this AppInstaller should run. --> <!-- Note: Should return True of False --> <FilterScript></FilterScript> </GlobalConfig> <Uninstallers> <Uninstaller> <ID>0</ID> <!-- [String] Search String to try to find in registry --> <SearchString></SearchString> <!-- [string] How to search for search string. --> <!-- Options: Simple, Regex, Exact--> <SearchType></SearchType> <!-- [String] Attempts to uninstall installers of specific architectures. --> <!-- Options: x64, x32, Both --> <Architecture></Architecture> <!-- [String] Flags to add to uninstaller. --> <Flags></Flags> <!-- [Bool] Attempt to extract the uninstaller path. --> <URLExtraction></URLExtraction> </Uninstaller> <Uninstaller> <ID>0</ID> <!-- [String] Search String to try to find in registry --> <SearchString></SearchString> <!-- [string] How to search for search string. --> <!-- Options: Simple, Regex, Exact--> <SearchType></SearchType> <!-- [String] Attempts to uninstall installers of specific architectures. --> <!-- Options: x64, x32, Both --> <Architecture></Architecture> <!-- [String] Flags to add to uninstaller. --> <Flags></Flags> <!-- [Bool] Attempt to extract the uninstaller path. --> <URLExtraction></URLExtraction> </Uninstaller> </Uninstallers> <Installers> <Installer> <!-- [Int] Order in which installer functions will run. --> <ID>0</ID> <!-- [String] What OS architecture the installer will run under. --> <!-- Options: x64, x32, Both --> <Architecture>x64</Architecture> <!-- [String] What flags should be added to the installer. --> <Flags>/QN</Flags> <!-- [int[]] Comma seperated list of which uninstallers to run and in what order before installing. --> <RunUninstallers></RunUninstallers> <!-- [ScriptBlock] PowerShell script used to test if this installer should run. --> <!-- Note: Should return True of False --> <FilterScript></FilterScript> <!-- Directory path to be added to parent GlobalConfig directory --> <InstallFile>\x64\install.msi</InstallFile> </Installer> <Installer> <!-- [Int] Order in which installer functions will run. --> <ID>1</ID> <!-- [String] What OS architecture the installer will run under. --> <!-- Options: x64, x32, Both --> <Architecture>x32</Architecture> <!-- [String] What flags should be added to the installer. --> <Flags>/QN</Flags> <!-- [int[]] Comma seperated list of which uninstallers to run and in what order before installing. --> <RunUninstallers></RunUninstallers> <!-- [ScriptBlock] PowerShell script used to test if this installer should run. --> <!-- Note: Should return True of False --> <FilterScript></FilterScript> <!-- Directory path to be added to parent GlobalConfig directory --> <InstallFile>\x32\install.msi</InstallFile> </Installer> </Installers> </AppInstall>
内容的提问来源于stack exchange,提问作者Nick W.
相关产品推荐
相关产品推荐

