使用 powershell 从文本文件中提取用户名和电子邮件

Extract user name and email from text file using powershell

正在尝试从文本文件中检索新用户信息,以从文本文件中创建名字和姓氏不是中间名的域用户和电子邮件地址。该文件实际上是一个 .eml 文件,因此该文本文件包含更多内容,但这只是文件的底部,但其格式始终相同。我在下面列出了一个示例。我需要将这些项目提取到变量 $Fname、$Lname 和 $Eaddr。我需要了解的是如何首先搜索特定行,在本例中为“BILLING ADDRESS”,然后抓住第 2 行并将名字和姓氏放在上面的变量中。电子邮件地址是相同的情况,但键入“祝贺销售”。并向上移动。不能只从“BILLING ADDRESS”算起,因为可能会有一个额外的地址行,比如 apt 或 suite。名称行中也可能有一个中间名,因此脚本需要像第二个地址行一样解决这种可能性。 以下是文本示例。它位于文件底部,而且格式始终相同。

----------------------------------------


BILLING ADDRESS

Joe Some Blow
123 Nowhere
Someplace, TX 75075
joeblow@nowhere.org


----------------------------------------

Congratulations on the sale.

----------------------------------------

$path = "C:\Program Files (x86)\hMailServer\Data\theserver.com\autobot\B0"


$GETemail = (Select-String -Path "$path\*.eml" -Pattern '(^\W*.*@.*\.{1,}\w*$)' | Select-Object -ExpandProperty Line)

select-string -pattern "@" -InputObject $PREaddr -raw


$PREaddr = (Select-String -Path "$path\*.eml" -Pattern 'BILLING ADDRESS' -CaseSensitive -Context 0, 7) | Select-Object -Skip 3

$GETemail = Select-String -Pattern '(^\W*.*@.*\.{1,}\w*$)' | Select-String -Path "$path\*.eml" -Pattern 'BILLING ADDRESS' -CaseSensitive -Context 0, 7

#Using Regex to pull email addresses
$file = Get-Content "location of file"
(Select-String -InputObject $file -Pattern '\w+@\w+\.\w+' -AllMatches).Matches | select value



$GETemail = (Select-String -Path "$path\*.eml" -Pattern 'BILLING ADDRESS' -CaseSensitive -Context 0, 7) | Select-String -Pattern '\w+@\w+\.\w+'



$file = Get-Content "C:\Program Files (x86)\hMailServer\Data\theserver.com\autobot\B0\*.eml"
(Select-String -InputObject $file -Pattern '\w+@\w+\.\w+' -AllMatches).Matches | select value

$GETemail = Select-String -Path "$path\*.eml" -Pattern 'BILLING ADDRESS' -CaseSensitive -Context 0, 7 | Select-String -Pattern '(^\W*.*@.*\.{1,}\w*$)'



Get-Item -Path "$path\*.eml" | Get-Content -Tail -2


Select-String -Path "$path\*.eml" -Pattern 'BILLING ADDRESS' -CaseSensitive -Context 0, 2 | select-object Line | ft -HideTableHeaders
Select-String -Path "$path\*.eml" -Pattern 'Congratulations' -CaseSensitive -Context 5, 0 | select-object Line | ft -HideTableHeaders


Select-String -Path "$path\*.eml" -Pattern 'BILLING ADDRESS' -CaseSensitive -Context 0, 2 | select-object -Skip 1


好的,我将分解我的评论。我评论里的代码:

gci $path\*.eml|%{gc $_ -raw|?{$_ -match '(?ms)BILLING ADDRESS\s+(\S.+?)[\r\n].+?[\r\n](\S+@\S+)'}|%{[pscustomobject]@{FirstName=$Matches[1].split(' ')[0];LastName=$Matches[1].Split(' ')[-1];Email=$Matches[2]}}

我将从定义各种别名开始,这些别名在评论中用来保持简短:

gci -> Get-ChildItem
%   -> ForEach-Object
gc  -> Get-Content
?   -> Where-Object

格式化得更好一点,不使用别名,它看起来像这样:

Get-ChildItem $path\*.eml|
    ForEach-Object{
        Get-Content $_ -raw |
            Where-Object{$_ -match '(?ms)BILLING ADDRESS\s+(\S.+?)[\r\n].+?[\r\n](\S+@\S+)'}|
            ForEach-Object{
                [pscustomobject]@{
                    FirstName=$Matches[1].split(' ')[0];
                    LastName=$Matches[1].Split(' ')[-1];
                    Email=$Matches[2]
                }
            }
    }

这从 Get-ChildItem 开始,这只是在 $path 中定义的路径中搜索 *.eml。没什么特别复杂的,继续。

接下来我们进入一个 ForEach-Object 循环。我实际上 运行 这里有两个循环,一个嵌套在另一个循环中,因此对于外部循环,我们关心的是在找到文件时一次处理一个文件。因此,对于每个文件,它做的第一件事是:

Get-Content $_ -raw

该命令获取作为 multi-line 字符串传递给它的文件的内容。这允许我们一次搜索匹配整个电子邮件的多个组,这就是我们在下一部分中所做的:

Where-Object{$_ -match '(?ms)BILLING ADDRESS\s+(\S.+?)[\r\n].+?[\r\n](\S+@\S+)'}

这表示我们只需要与指定的 RegEx 模式匹配的电子邮件。如果您需要解释 RegEx(正则表达式),我会让您看看 RegEx 101 如何分解它。该匹配项中有两个捕获组,对于结果传递到的 ForEach-Object 循环的每次迭代,这些捕获组会填充到自动 $Matches 变量中。工作方式是它用一个数组填充 $Matches ,其中匹配的整个字符串是第一项,然后每个捕获组是数组中的一个附加项。在我们的例子中,您给出的例子是:

$Matches[0]
BILLING ADDRESS

Joe Some Blow
123 Nowhere
Someplace, TX 75075
joeblow@nowhere.org

$Matches[1]
Joe Some Blow

$Matches[2]
joeblow@nowhere.org

然后我只是循环遍历结果以利用 $Matches 结果,并为每个结果构建一个对象。

ForEach-Object{
    [pscustomobject]@{
        FirstName=$Matches[1].split(' ')[0];
        LastName=$Matches[1].Split(' ')[-1];
        Email=$Matches[2]
    }
}

因为我使用第一个捕获组 (Joe Some Blow),用 .split(' ') 在空格上拆分它,并将拆分的第一个结果用作名字,最后一个结果用作名字姓。我为电子邮件地址获取了第二个捕获组。然后它只是最后一个 } (我的评论中缺少)关闭外部 ForEach-Object 循环。