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
关键说明
- 初始化完整对象:每个Ruleset开始时就创建包含所有目标字段的PSCustomObject,确保所有列都被Export-Csv识别。
- 字段赋值:遍历condition时,通过
switch语句(替代原有的多个if)给对象的对应属性赋值,避免创建新对象。 - 统一输出:每个Ruleset处理完成后,输出完整的
$policyObj,这样Export-Csv会将所有字段写入CSV,缺失的字段自动填充为空字符串。
内容的提问来源于stack exchange,提问作者Adami
相关产品推荐
相关产品推荐

