Powershell从文本文件中提取数据并转换为csv

时间:2019-12-13 19:01:01

标签: regex string powershell substring

所以我有一个如下所示的文本文件。

我怎么能使用PowerShell来获取mac地址和端口号(最右边一列)并将其输出到带有标头(mac,端口)的csv文件中?

1        010D.0C93.A02C        Dynamic     Gi1/0/5
1        011B.782D.6719        Dynamic     Gi1/0/22
1        0003.4790.B479        Dynamic     Gi1/0/1
1        0054.B671.1EB8        Dynamic     Gi1/0/2

我尝试仅遍历文本文件并多次使用-replace。我剩下了想要的数据,这很好。但它似乎过于复杂,我仍然面临着将输出与标头输出到csv的问题。

$file = Get-Content file.txt
$file | ForEach-Object {$_ -replace ' ', '' -replace 'Dynamic', '' 
   -replace 'Management', '' -replace 'Gi1/0/', ', '}

这是我尝试过的。它输出如下:

010D.0C93.A02C, 5
011B.782D.6719, 22
0003.4790.B479, 1
0054.B671.1EB8, 2

从这里,我不确定如何将其转换为带标头的csv(mac,端口) 就像我说的必须有一种更有效的方法来过滤掉这些数据。

感谢您的帮助。

3 个答案:

答案 0 :(得分:1)

在评论中说Stack Overflow不是代码编写服务,我还是要编写一些代码...

以下代码假定存储文本的文件名位于变量$textfilename中,并且所需CSV文件的名称位于变量$csvfilename中。

Get-Content -Path $textfilename | 
    ForEach-Object {
        New-Object -TypeName PSObject -Property @{ 
            MAC=$_[9..22] -join ""
            Port=$_[44..($_.length-1)] -join ""
        }
    } | 
        Export-CSV -Path $csvfilename -Append -NoTypeInformation

请注意,我通过坐在那里计数来找出子字符串的“字段位置”;无疑有更好的方法。我的代码给出的是端口名称,而不是数字(也就是说,我产生的是“ Gi1 / 0/22”而不是“ 22”)。但是,关键是要创建具有成员属性PSObjectMAC的{​​{1}},为这些属性分配必要的值,然后将这些对象发送到CSV。 / p>

答案 1 :(得分:1)

您可以使用正则表达式过滤出所需的部分(mac和端口),如下所示:

$result = Get-Content -Path 'X:\file.txt' | ForEach-Object {
    if ($_ -match '^.+?(?<mac>[0-9A-F]{4}\.[0-9A-F]{4}\.[0-9A-F]{4}).+?(?<port>\d+)$') {
        [PsCustomObject]@{
            'mac'  = $matches['mac']
            'port' = $matches['port']
        }
    }
}

# output on screen
$result

# output to Csv file
$result | Export-Csv -Path 'X:\macports.csv' -NoTypeInformation

输出:

mac            port
---            ----
010D.0C93.A02C 5   
011B.782D.6719 22  
0003.4790.B479 1   
0054.B671.1EB8 2

正则表达式详细信息:

^                Assert position at the beginning of a line (at beginning of the string or after a line break character)
.                Match any single character that is not a line break character
   +?            Between one and unlimited times, as few times as possible, expanding as needed (lazy)
(?<mac>          Match the regular expression below and capture its match into backreference with name “mac”
   [0-9A-F]      Match a single character present in the list below
                 A character in the range between “0” and “9”
                 A character in the range between “A” and “F”
      {4}        Exactly 4 times
   \.            Match the character “.” literally
   [0-9A-F]      Match a single character present in the list below
                 A character in the range between “0” and “9”
                 A character in the range between “A” and “F”
      {4}        Exactly 4 times
   \.            Match the character “.” literally
   [0-9A-F]      Match a single character present in the list below
                 A character in the range between “0” and “9”
                 A character in the range between “A” and “F”
      {4}        Exactly 4 times
)
.                Match any single character that is not a line break character
   +?            Between one and unlimited times, as few times as possible, expanding as needed (lazy)
(?<port>         Match the regular expression below and capture its match into backreference with name “port”
   \d            Match a single digit 0..9
      +          Between one and unlimited times, as many times as possible, giving back as needed (greedy)
)
$                Assert position at the end of a line (at the end of the string or before a line break character)

答案 2 :(得分:0)

如果您正在寻找通用解决方案(自动定义了列),则可能要尝试使用ConvertFrom-SourceTable,另请参见:How can I save lines with spaces between characters in the right way (Array)?
我刚刚添加了一个新功能,您可以在其中提供列(属性)名称的列表,而不是对齐的标题行:

$Table = '
1        010D.0C93.A02C        Dynamic     Gi1/0/5
1        011B.782D.6719        Dynamic     Gi1/0/22
1        0003.4790.B479        Dynamic     Gi1/0/1
1        0054.B671.1EB8        Dynamic     Gi1/0/2'

ConvertFrom-SourceTable -Header Count,Address,Mode,Port $Table |
    Select-Object -Property Address, @{n = 'Port'; e = {$_.Port.Split('/')[-1]}}

Address        Port
-------        ----
010D.0C93.A02C 5
011B.782D.6719 22
0003.4790.B479 1
0054.B671.1EB8 2