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

PowerShell中为PSCustomObject添加值实现XML转CSV的问题

问题:PowerShell XML转CSV时字段无法写入CSV文件

编写PowerShell脚本将XML文件转换为CSV时遇到问题:脚本可正常将policyName列写入CSV,但后续迭代中,Resource、Action等字段的值能在控制台输出,却无法写入CSV。

问题根源:代码中先创建包含policyName的[PSCustomObject],处理Conditions下的condition时,每个字段都新建了独立的[PSCustomObject],导致CSV仅保留第一个对象的列(即policyName)。

原代码

[xml]$x = Get-Content C:\Users\Desktop\Policy.xml

$x.Profiles |
    ForEach-Object{
            $_.Profile |
                ForEach-Object{
                    $_.Ruleset |
                        ForEach-Object{
                            Write-Host "Policy ID = " $_.ID
                            [PSCustomObject]@{
                                policyName = $_.ID
                            }
                            $_.Conditions |
                                ForEach-Object{
                                    $_.condition |
                                        ForEach-Object{
                                            if($_.name -eq "Resource") {
                                                Write-Host "Resource = " $_.'#text'
                                                [PSCustomObject]@{
                                                    resource = $_.'#text'
                                                }
                                            }
                                            if($_.name -eq "Action") {
                                                Write-Host "Action = " $_.'#text'
                                                [PSCustomObject]@{
                                                    action = $_.'#text'
                                                }
                                            }
                                            if($_.name -eq "actor") {
                                                Write-Host "actor = " $_.'#text'
                                                [PSCustomObject]@{
                                                    actor = $_.'#text'
                                                }
                                            }
                                            if($_.name -eq "child") {
                                                Write-Host "child = " $_.'#text'
                                                [PSCustomObject]@{
                                                    child = $_.'#text'
                                                }
                                            }
                                            if($_.name -eq "number") {
                                                Write-Host "number = " $_.'#text'
                                                [PSCustomObject]@{
                                                    number = $_.'#text'
                                                }
                                            }
                                        }
                                }
                        }
                }
    } | Export-Csv C:\Users\Desktop\policy.csv -NoTypeInformation

XML示例

<?xml version="1.0" encoding="UTF-8"?>
<Profiles xmlns:pcrf="nothing interesting here">
    <Profile Desc="some description" ID="someid" Prio="0">
        <Ruleset Class="class1" Desc="" ID="policyid1" Prio="10" active="true">
            <Conditions>
                <condition name="Resource" type="matchExact">resource1</condition>
                <condition name="Action" type="matchExact">action1</condition>
                <condition name="actor" type="matchExact">actor1</condition>
            </Conditions>
        </Ruleset>
        <Ruleset Class="classX" Desc="" ID="policyidX" Prio="10" active="true">
            <Conditions>
                <condition name="Resource" type="matchExact">resource4</condition>
                <condition name="Action" type="matchExact">action4</condition>
                <condition name="child" type="matchExact">child1,child2</condition>
            </Conditions>
        </Ruleset>
    </Profile>
    <Profile Desc="some description" ID="someid" Prio="0">
        <Ruleset Class="classY" Desc="" ID="policyidY" Prio="10" active="true">
            <Conditions>
                <condition name="Resource" type="matchExact">resource99</condition>
                <condition name="Action" type="matchExact">action00</condition>
                <condition name="child" type="matchExact">child5</condition>
                <condition name="number" type="matchExact">number1</condition>
            </Conditions>
        </Ruleset>
    </Profile>
</Profiles>

当前生成的错误CSV结果

"policyName"
"policyid1"

控制台输出

PS C:\Users\Desktop> .\xmltocsv.ps1
Policy ID =  policyid1
Resource =  resource1
Action =  action1
actor =  actor1
Resource =  resource4
Action =  action4
child =  child1,child2
Resource =  resource99
Action =  action00
child = child5
number =  number1

期望的CSV格式

"policyName","Resource","Action","actor","child","number"
"policyid1","resource1","action1","actor1","",""
"policyidX","resource4","action4","","child1,child2",""
"policyidY","resource99","action00","","child5","number1"

解决方法

核心逻辑:每个Ruleset对应一个完整的PSCustomObject,先初始化包含所有目标字段的对象(默认值为空字符串),遍历Conditions时给对应字段赋值,最后统一输出这个完整对象。

修改后的代码:

[xml]$x = Get-Content C:\Users\Desktop\Policy.xml

$x.Profiles | ForEach-Object {
    $_.Profile | ForEach-Object {
        $_.Ruleset | ForEach-Object {
            # 初始化包含所有字段的对象,默认值为空字符串
            $policyObj = [PSCustomObject]@{
                policyName = $_.ID
                Resource   = ""
                Action     = ""
                actor      = ""
                child      = ""
                number     = ""
            }

            Write-Host "Policy ID = " $_.ID

            # 遍历Conditions,给对应字段赋值
            $_.Conditions.condition | ForEach-Object {
                switch ($_.name) {
                    "Resource" { 
                        $policyObj.Resource = $_.'#text'
                        Write-Host "Resource = " $_.'#text'
                    }
                    "Action" { 
                        $policyObj.Action = $_.'#text'
                        Write-Host "Action = " $_.'#text'
                    }
                    "actor" { 
                        $policyObj.actor = $_.'#text'
                        Write-Host "actor = " $_.'#text'
                    }
                    "child" { 
                        $policyObj.child = $_.'#text'
                        Write-Host "child = " $_.'#text'
                    }
                    "number" { 
                        $policyObj.number = $_.'#text'
                        Write-Host "number = " $_.'#text'
                    }
                }
            }

            # 输出完整的对象,供Export-Csv处理
            $policyObj
        }
    }
} | Export-Csv C:\Users\Desktop\policy.csv -NoTypeInformation

关键说明

  1. 初始化完整对象:每个Ruleset开始时就创建包含所有目标字段的PSCustomObject,确保所有列都被Export-Csv识别。
  2. 字段赋值:遍历condition时,通过switch语句(替代原有的多个if)给对象的对应属性赋值,避免创建新对象。
  3. 统一输出:每个Ruleset处理完成后,输出完整的$policyObj,这样Export-Csv会将所有字段写入CSV,缺失的字段自动填充为空字符串。

内容的提问来源于stack exchange,提问作者Adami

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.13 05:50:39