You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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.

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.20 02:21:15