【问题标题】:Trying to export an array to csv using powershell (array objects are ; delimited and contain newlines)尝试使用 powershell 将数组导出到 csv(数组对象是 ; 分隔并包含换行符)
【发布时间】:2013-03-28 09:10:51
【问题描述】:

好的,我有这个数组,它本质上是一个 CSV 文件的Import-Csv。数组中的每个对象都是一个完整的 CSV 行。当我用 Excel 打开它时,输入文件正确呈现(列是正确的)

此 CSV 文件以逗号分隔,格式如下:

"第一","第二","就这些

第三个

列","第四"

我已经让脚本中的所有内容都能正常工作,除了我需要将此数组以可以正确呈现的格式写入 .csv 文件的部分。我在使用Out-FileExport-Csv 时遇到了问题,我什至尝试过this,但它并没有完全满足我的需求。每个对象必须是 csv 文件中的一个新行,只出现一次,并且必须遵守 Excel 对 CSV 文件的呈现(即每列需要双引号和逗号分隔)。

我什至非常绝望,以至于我试图通过这样做来正确地手动格式化这个东西:

$Array | % { $_ -replace "`"@`{","`n`"" } | % { $_ -replace "}`"","`"`n" } | % { $_ -replace "`;","`"`;`"" } | % { $_ -replace "Plugin ID=","" } | % { $_ -replace "CVE=","" } | % { $_ -replace "CVSS=","" } | % { $_ -replace "Risk=","" } | % { $_ -replace "Host=","" } | % { $_ -replace "Protocol=","" } | % { $_ -replace "Port=","" } | % { $_ -replace "Name=","" } | % { $_ -replace "Synopsis=","" } | % { $_ -replace "Solution=","" } | % { $_ -replace "Description=","" } | % { $_ -replace "Plugin Output=","" } | % { $_ -replace "`";`"","`",`"" } | Out-File "$dirResults\$Results-$Time.csv"    

基本上,我在这里做的是几件事:

  • 从每个对象的开头删除 @{ 并从末尾删除 }
  • 将分隔符从 ;到,
  • 将每一列放在双引号中
  • 从每个值的开头删除 ColumnHeader=

这是一段sn-p代码:

$arrayHeader = @("Plugin ID;CVE;CVSS;Risk;Host;Protocol;Port;Name;Synopsis;Description;Solution;Plugin Output")
$OutterArrayException = Import-Csv "$dirExceptions\$FileException" -Delimiter ","
$InnerArrayScanMe = New-Object System.Collections.ArrayList
# This method keeps the arrays separate types
FOREACH ( $Object in $OutterArrayScanMe )
        {   $InnerArrayScanMe.Add("$Object") | Out-Null }
# Note that the OutterArrayException is an Import-Csv from a similarly formatted file as OutterArrayScanMe
FOREACH ( $Exception in $OutterArrayException )
        { $InnerArrayScanMe.Remove("$Exception") }
# This method keeps the arrays separate types
$OutterArrayScanMe = @($arrayHeader) + @($InnerArrayScanMe)
$OutterArrayScanMe | Export-Csv "$dirResults\$FileScanMe-$startTime.csv" -Delimiter ";" -NoTypeInformation

更新
当我使用 export-csv 时,对象的新行将信息作为新行放置在 csv 中。因此,应该看起来像这样的东西变得非常混乱。

UPDATE2
关于格式是什么样的以及格式存在什么问题,一直存在一些问题。为了清除这些,我在数组中包含了一个对象来演示该问题。请记住,在我的脚本中发生的情况是有一个格式正确的 CSV 的 import-csv(具有多行等,并且可以完美呈现),删除不必要的对象(使用 $array.Remove),然后转储到文件( Out-File 或 Export-Csv)。如此简单,却又如此破碎……

示例数组对象(输出文件):
@{插件ID=#####; CVE=CVE-####-####; CVSS=#.#;风险=中等;主机=###.###.###.###;协议=xxx;端口=##;名称=Microsoft ASP.NET xxx;概要=远程 Web 服务器使用的框架
脆弱性。描述=远程主机上运行的 Web 服务器似乎正在使用 Microsoft
ASP.NET,并且可能受漏洞影响。

此外,有人猜测此漏洞可能会导致 如果攻击者可以物理访问机器,则在独角兽和彩虹中 插入。解决方案=使用魔法过滤器阻止对淘气网站的请求。;插件输出= Nessus 通过请求
收到了一个顽皮的页面或相关的错误消息 以下网址:

hxxp://###.###.###.###/xxx/xxxxxxxxx
}

示例数组对象(导出-Csv):
#TYPE System.String
“长度”
“616”

【问题讨论】:

  • 您使用 export-csv 时的渲染方式有什么问题?
  • 在 Excel 2013 中另存为 CSV 时,用“;”分隔不是“,”并且文本并不总是用引号引起来(实际上我尝试时从来没有)。上面的样本是什么?是“input.csv”吗?然后你修改它,导出它并希望保持相同的格式(每个对象多行),或者你想删除换行符?请提供输出 csv 的样本。
  • "first","second","this is all the third column","fourth" 都是新行吗?
  • 请举例说明您要导出到 CSV 文件的内容。
  • @mjolinor 查看更新。

标签: powershell scripting


【解决方案1】:

问题似乎在于您如何操作数组。看看这个:

Test.csv

"Age";"Name"
12;"Test name"
13;"My Other
test"

脚本

$Array = Import-Csv .\test.csv -Delimiter ";"

#$Array.Remove() is NOT a valid method. An array is of fixed size, and you will get an exception
#Instead, create a new array of items that are filtered through your rules.
#My test rule is only kids who are not 12 years old
$Newarray = $Array | Where-Object { $_.Age -ne "12" }

$Newarray | Export-Csv .\out.csv -Delimiter ";" -NoTypeInformation

输出.csv

"Age";"Name"
"13";"My Other
test"

一切都应该如此。

不要在对象上使用-replace。它将对象转换为字符串,您将获得在 update2 中提供的输出。例如:

$Array = Import-Csv .\test.csv -Delimiter ";"

$Array -replace "`r`n" | Export-Csv .\out2.csv -Delimiter ";"
$Array -replace "`r`n" | Out-File out2.txt

Out2.csv

#TYPE System.String
"Length"
"25"
"28"

“TYPE”部分只是因为您没有指定-NoTypeInformationExport-CSV

Out2.txt

@{Age=12; Name=Test name}
@{Age=13; Name=My Othertest}

顺便说一句,Out-File 不是导出对象的方法,但在-replace 之后,您的对象数组变成了字符串数组,就像 Out2.txt 中的输出一样

编辑 $OutterArrayScanMe = @($arrayHeader) + @($InnerArrayScanMe) 这是你的问题。您将两个数组合并在一起。新数组中的第一个对象将是一个字符串对象。 Export-CSV 使用第一个对象的属性作为每个对象的标题。由于第一个对象是字符串(只有 Length 属性),所有对象都将仅使用Length 属性导出。

如前所述,Export-CSV 使用对象属性作为标头(除非您指定另一个标头定义,例如 | Select Age, Name | Export-Csv)。因此,如果$InnerArrayScanMe 是具有相同属性的对象数组,只需使用:

$InnerArrayScanMe | Export-Csv "$dirResults\$FileScanMe-$startTime.csv" -Delimiter ";" -NoTypeInformation

Export-CSV 会自己找出标题。摘要:不要将您的标头字符串添加到数组中。如果您需要特定的顺序或需要排除某些属性,可以使用将字符串数组传递给select-object 定义标题,如下所示:

$arrayHeader = @("Plugin ID","CVE","CVSS","Risk","Host","Protocol","Port","Name","Synopsis","Description","Solution","Plugin Output")

$arrlist | Select-Object -Property $arrayHeader | 
Export-Csv "$dirResults\$FileScanMe-$startTime.csv" -Delimiter ";" -NoTypeInformation

【讨论】:

  • 使用 Excel 时,只要格式正确,显示多行字段似乎没有问题。我不想删除换行符,我只想确保当换行符在 CSV 中时,它的格式设置为 Excel 可以识别它应该是一个条目。
  • 要么我有一个“愚蠢的一天”,要么你解释得不够好。如果您在我的“答案”中打开第一个示例(使用; 而不是,),这是在 csv 中提供多行值的“正确方法”,它将在 excel 中正确读取。但是,您必须调整行高才能看到所有文本。那是你要的吗?让 Excel 了解它需要拉伸?
  • 通过update3,我的输出是:“Length”“91”“91”“616”“1234”“1234”“616”“616”“616”“1233”“1234”“607 " "616" "616" "852" "852"
  • 我做了更多测试,问题是不同类型的数组。 (又名“$InnerArrayScanMe = New-Object System.Collections.ArrayList”)一旦对象被添加到该数组中,它们就会变成垃圾(重新格式化,添加@{}等)并且不能很好地与 Export -CSV。
  • 问题是我在回答的编辑中描述的。我有 99.9% 的把握。这不是你组合两个数组的事实,而是数组中的对象不一样。 $arrayHeader 是您在组合它们时创建的新数组中的第一项,它的对象是一个字符串,Export-CSV 使用它作为其他对象的模板(这是错误的)。你试过最后一个样品吗?使用Select-Object 指定标题的那个。?
【解决方案2】:

不确定是否理解您的问题,您可以执行以下操作:

Import-Csv C:\temp\nessus.csv | where {$_.risk -eq "high"}
Import-Csv C:\temp\nessus.csv | where {$_.risk -eq "high"} | select host -Unique

您可以将其导出为可使用 Excel 编辑的 CSV

Import-Csv C:\temp\nessus.csv | where {"high","medium","low" -contains $_.risk} | select "Plugin ID", CVE, CVSS, Risk, Host, Protocol, Port, Name | Export-Csv 'c:\temp\nessusExcel.csv' -Delimiter ';' 

您可以在 gridview 中显示:

Import-Csv C:\temp\nessus.csv | where {"high","medium","low" -contains $_.risk} | select "Plugin ID", CVE, CVSS, Risk, Host, Protocol, Port, Name | Out-GridView

导出到 HTM 文件:

Import-Csv C:\temp\nessus.csv | where {"high","medium","low" -contains $_.risk} | select "Plugin ID", CVE, CVSS, Risk, Host, Protocol, Port, Name | ConvertTo-Html -As List > report.html

【讨论】:

  • 如果我不清楚,我很抱歉;该脚本导入一个csv,然后对其进行处理,将其与其他文件进行比较,解析条目等。此时我有一个“最终数组”,我希望以良好的格式输出到文件中。我的问题是,在那个输出阶段,格式很混乱,因为它似乎想在数组中的每个对象周围添加@{},并且它没有正确引用多行条目以正确解析。输入采用这种正确的格式,并且在数组中时不会手动更改格式。似乎 powershell 正在稍微改变格式(见项目符号)。
  • 你能举一个$Array的例子吗,例如在一个带有Export-Clixml的xml文件中?
  • 请查看我的更新2,如果这能满足您的需求,请告诉我。我做了一个 Export-Clixml 并提供了一个模糊的单行(有多个条目的格式完全相同)。我显然删除了 .
【解决方案3】:

问题出在脚本中,在这一步:

$InnerArrayScanMe = New-Object System.Collections.ArrayList  
# This method keeps the arrays separate types  
FOREACH ( $Object in $OutterArrayScanMe )  
        {   $InnerArrayScanMe.Add("$Object") | Out-Null }

$InnerArrayScanMe 成功地添加了普通数组 $OutterArrayScanMe 中的对象,而没有更改数组类型,但是由于它被放入 .NET 数组中,因此从这里开始数据格式不正确。

以最初的方式执行此操作的目的是让我可以使用 .NET 数组的 .Add 和 .Remove 方法。使我们不需要引用要通过索引删除的对象的解决方法如下所示:

FOREACH ( $Exception in $ArrayException )
{
    $ArrayScanMe = $ArrayScanMe | Where-Object {"$_" -ne "$Exception"};
}

然后我们就可以做一个基本的 Export-Csv

$ArrayScanMe | Export-Csv "$dirResults\$FileScanMe-$startTime.csv" -Delimiter "," -NoTypeInformation

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2021-12-07
    • 2012-01-20
    • 2013-05-06
    • 1970-01-01
    • 2020-02-02
    • 2021-11-17
    • 1970-01-01
    相关资源
    最近更新 更多