使用属性字典导出哈希表为CSV

我似乎无法弄清楚如何简单地将格式化的信息导出到CSV,除非我遍历对象中的每个项目,并逐行写入到CSV行,这将永远。 我可以立即将值导出到CSV,只是在使用属性字典时遇到问题。

TestCSV文件格式化为具有IP地址的列。

这是我有:

$CSV = "C:\TEMP\OutputFile.csv" $RX = "(?:(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)(?:\.|dot|\[dot\]|\[\.\])){3}(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)" $TestCSV = "C:\TEMP\FileWithIPs.csv" $spreadsheetDataobject = import-csv $TestCSV $Finding = $spreadsheetDataObject | Select-String $RX $Props = @{ #create a properties dictionary LineNumber = $finding.LineNumber Matches = $finding.Matches.Value } $OBJ = New-Object -TypeName psobject -Property $Props $OBJ | Select-Object Matches,LineNumber | Export-Csv -Path $CSV -Append -NoTypeInformation 

这不会像书面那样工作。 您正在使用Import-CSV创build具有属性的对象数组。 Select-String命令期望string作为input,而不是对象。 如果要使用Select-String ,只需指定文件名,或者在文件上使用Get-Content ,然后将其传递给Select-String 。 如果你想要的是行号和IP,我认为这可能会同样适用,如果不是更好的话:

 $CSV = "C:\TEMP\OutputFile.csv" $RX = "(?:(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)(?:\.|dot|\[dot\]|\[\.\])){3}(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)" $TestCSV = "C:\TEMP\FileWithIPs.csv" $spreadsheetDataobject = import-csv $TestCSV $spreadsheetDataobject | Where{$_.IP -match $RX} | Select-Object @{l='Matches';e={$_.IP}},@{l='LineNumber';e={[array]::IndexOf($spreadsheetDataobject,$_)+1}} | Export-Csv -Path $CSV -Append -NoTypeInformation 

编辑: wOxxOm是非常正确的,这个答案比直接parsing文本的开销要大得多,就像他一样。 尽pipe对于刚接触PowerShell的人来说,这可能更容易理解。

至于$_.IP ,由于您使用Import-CSV您可以创build一个对象数组。 每个对象都具有基于CSV文件标题的相关属性。 IP作为您的列之一列在标题中,因此每个对象都具有IP属性,该属性的值是该logging的IP列中的值。

让我来为你解释Select行,然后你会发现将源path添加为另一个列是很容易的。

我正在做的是用散列表定义属性。 对于我的例子,我会参考上面的第一个例子。 由于它是一个散列表,它以@{开头,并以}结尾。 里面有两个键/值对:

 l='Matches' e={$_.IP} 

基本上'l'是Label的缩写,'e'是Expression的缩写。 标签决定了正在定义的属性的名称(在导出时相当于列标题)。 该expression式定义了分配给该属性的值。 在这种情况下,我真的只是将IP列重命名为Matches,因为我为每行分配的值是IP字段中的值。 如果你在Excel中打开CSV,复制整个IP列,粘贴到最后,并将标题更改为匹配,这基本上是我所做的。 因此,要将文件path添加为列,我们可以使用以下命令将另一个散列表添加到“ Select行:

 @{ l='FilePath' e={$CSV} } 

这增加了第三个属性,其中名称是FilePath,值是存储在$CSV任何值。 该更新的Select线将如下所示:

  Select-Object @{l='Matches';e={$_.IP}},@{l='LineNumber';e={[array]::IndexOf($spreadsheetDataobject,$_)+1}},@{l='FilePath'e={$CSV}} | 

任何基于内置CSV cmdlet的代码都非常缓慢,因为每行的每个字段都创build了对象,而且在大文件上显而易见(例如,来自其他答案的代码需要900秒来处理具有10万行的9MB文件)。

如果您input的CSV文件很简单,那么对于100k行文件,您可以在不到一秒的时间内将其作为文本处理:

 $CSV = ....... $RX = ....... $TestCSV = ....... $line = 0 # header line doesn't count $lastMatchPos = 0 $text = [IO.File]::ReadAllText($TestCSV) -replace '"http.+?",', ',' $out = New-Object Text.StringBuilder ForEach ($m in ([regex]"(?<=,""?)$RX(?=""?,)").Matches($text)) { $line += $m.index - $lastMatchPos - $text.substring($lastMatchPos, $m.index-$lastMatchPos).Replace("`n",'').length $lastMatchPos = $m.Index + $m.length $out.AppendLine('' + $line + ',' + $m.value) >$null } if (!(Test-Path $CSV)) { 'LineNumber,IP' | Out-File $CSV -Encoding ascii } $out.ToString() | Out-File $CSV -Encoding ascii -Append 

代码跳过引用的URL字段只是在不太可能,但可能的情况下,那些包含匹配的IP。