CSV文件仅包含最后一次正则表达式匹配的部分条目。
我使用了ISE调试器,可以验证它是否找到匹配项。
$h = @{}
$a = @()
Get-ChildItem C:\Users\speterson\Documents\script\*.kiy | foreach {
Get-Content $_ | foreach {
if ($_ -match 'IF Ingroup\s+\(\s+\"(..+?)\"\s+\)') {
$h.Group = $matches[1]
}
if ($_ -match 'use\s+([A-Za-z]):"(\\\\..*?\\..*)\"')) {
$h.DriveLetter = $matches[1].ToUpper()
$h.Path = $matches[2]
}
}
$a += New-Object PSCustomObject -Property $h
}
$a | Export-Csv c:\temp\Whatever.csv -NoTypeInfo
输入文件如下所示,但是其中有1000多个行:
IF Ingroup ( "RPC3WIA01NT" ) use v: /del ENDIF IF Ingroup ( "JWA03KRONOSGLOBAL" ) use v:"\\$homesrvr\$dept" ENDIF IF Ingroup ( "P-USERS" ) use p:'\\PServer\PDRIVE ENDIF
CSV文件仅显示:
GROUP P-USERS
我想用/del
忽略驱动器号。
我正在尝试获取显示的CSV文件
Group Drive Path JWA03KRONOSGLOBAL V \\$homesrvr\$dept P-USERS P \\PServer\PDRIVE
答案 0 :(得分:0)
您的代码有两个循环,一个循环嵌套在另一个循环中。外循环处理Get-ChildItem
调用中的每个文件。内部循环处理外部循环的当前文件的内容。但是,由于要在内部循环完成后 创建对象,所以只能从每个已处理文件中获取最后一个结果。将对象创建移入内部循环以从所有文件中获取所有结果。
我还建议不要重用哈希表。重用对象始终会带来使数据遗留在不需要的地方的风险。散列表的创建是如此便宜,以至于冒这个风险永远都不值得。
最重要的是,您对文件内容的处理存在缺陷,因为内部循环一次只处理一行内容,但是您的两个条件都在不同的行上匹配并且没有相互链接。如果您每次迭代都创建一个新对象,则会给您不正确的结果。整体读取文件,然后将Select-String
与多行正则表达式一起使用以提取所需的信息。
要避免的另一件事是在循环中附加到数组(这是一个很慢的操作,因为它涉及重新创建数组并一遍又一遍地复制元素)。由于您使用的是ForEach-Object
,因此可以直接通过管道传输到Export-Csv
。
类似的事情应该起作用:
$re = 'IF Ingroup\s+\(\s+"(.+?)"\s+\)\s+' +
"use\s+([a-z]):\s*[`"'](\\\\[^`"'\s]+)"
Get-ChildItem 'C:\Users\speterson\Documents\script\*.kiy' | ForEach-Object {
Get-Content $_.FullName |
Out-String |
Select-String $re -AllMatches |
Select-Object -Expand Matches |
ForEach-Object {
New-Object -Type PSObject -Property @{
'Group' = $_.Groups[1].Value
'DriveLetter' = $_.Groups[2].Value
'Path' = $_.Groups[3].Value
}
}
} | Export-Csv 'C:\path\to\output.csv' -NoType