Powershell验证电子邮件地址

时间:2018-01-14 20:12:58

标签: powershell validation email

我试图让Powershell使用Regex验证电子邮件地址,并将电子邮件地址放入好的和坏的csv文件中。我可以让它跳过一行并写入文件,但无法让它定位电子邮件地址并验证它们,然后将行写入好的和坏的文件。我可以在C#和JavaScript中完成它,但从未在Powershell中完成它。我知道这可以做到,但不知道如何做。

这是我到目前为止所做的:

EXPLAIN SELECT ...

我正在验证第三栏"电子邮件"在原始的csv文件中并尝试写出整行到文件(好文件,坏文件)。不确定如何缓冲这样做。

Function IsValidEmail { 
    Param ([string] $In) 
    # Returns true if In is in valid e-mail format. 
    [system.Text.RegularExpressions.Regex]::IsMatch($In,  
        "^([\w-\.]+)@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.)|
    (([\w-]+\.)+))([a-zA-Z]{2,4}|[0-9]{1,3})(\]?)$");  
} 


## Now we need to check the original file for invalid and valid emails.**

$list = Get-Content C:\Emails\OriginalEmails\emailAddresses.csv

# This way we also use the foreach loop.
##======= Test to see if the file exists ===========

if (!(Test-Path "C:\Emails\ValidEmails\ValidEmails.csv")) {
    New-Item -path C:\Emails\ValidEmails -name ValidEmails.csv -type 
    "file" # -value "my new text"
    Write-Host "Created new file and text content added"
}
else {
    ## Add-Content -path C:\Share\sample.txt -value "new text content"
    Write-Host "File already exists and new text content added"
}


if (!(Test-Path "C:\Emails\InValidEmails\InValidEmails.csv")) {
    New-Item -path C:\Emails\InValidEmails -name InValidEmails.csv -type 
    "file" # -value "my new text"
    Write-Host "Created new file and text content added"
}
else {
    # Add-Content -path C:\Emails\ValidEmails -value "new text content"
    Write-Host "File already exists and new text content added"
}

#$Addresses = Import-Csv "C:\Data\Addresses.csv" -Header 
Name, Address, PhoneNumber | Select -Skip 1
$EmailAddressImp = Import-Csv 
"C:\Emails\OriginalEmails\emailAddresses.csv" -Header 
FirstName, LastName, Email, Address, City, State, ZipCode  | Select  
FirstName, LastName, Email, Address, City, State, ZipCode -Skip 1

5 个答案:

答案 0 :(得分:7)

  

我正在尝试让Powershell使用Regex验证电子邮件地址

不要!

我会建议不要这样做。使用正则表达式准确验证电子邮件地址可能比您想象的要困难得多。

让我们来看看你的正则表达式模式:

^([\w-\.]+)@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.)|(([\w-]+\.)+))([a-zA-Z]{2,4}|[0-9]{1,3})(\]?)$

在它的当前表单中,它错误地验证了.@domain.tld

另一方面,它不会验证unicode编码的国际化域名,例如user@☎.com(是的,这是一个有效的电子邮件地址)

我不会尝试查找或构建完美的电子邮件验证正则表达式模式,而是使用MailAddress类进行验证:

function IsValidEmail { 
    param([string]$EmailAddress)

    try {
        $null = [mailaddress]$EmailAddress
        return $true
    }
    catch {
        return $false
    }
}

如果输入字符串是有效的电子邮件地址,则转换为[mailaddress]将成功,函数返回$true - 否则,强制转换将导致异常,并返回{{1 }}

导出数据时,我会考虑在内存中一次性收集所有结果,然后在结束时将其写入文件一次

如果您使用的是PowerShell版本2或3,则可以通过$false的两次传递执行相同操作:

Where-Object

如果您使用的是PowerShell 4.0或更高版本,我建议您在$EmailAddresses = Import-Csv "C:\Emails\OriginalEmails\emailAddresses.csv" -Header FirstName, LastName, Email, Address, City, State, ZipCode | Select -Skip 1 $valid = $list |Where-Object {IsValidEmail $_.Email} $invalid = $list |Where-Object {-not(IsValidEmail $_.Email)} 模式下使用.Where()扩展程序:

Split

导出到文件之前:

$EmailAddresses = Import-Csv "C:\Emails\OriginalEmails\emailAddresses.csv" -Header FirstName, LastName, Email, Address, City, State, ZipCode  | Select -Skip 1

$valid,$invalid = $list.Where({IsValidEmail $_.Email}, 'Split')

答案 1 :(得分:4)

您可以使用-match运算符,而不是调用[Regex]类。这是一个简单的例子,没有任何包装函数:

$EmailRegex = '^([\w-\.]+)@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.)|(([\w-]+\.)+))([a-zA-Z]{2,4}|[0-9]{1,3})(\]?)$'

$EmailList = @('a@a.com', 'b@b.co', 'm.a@example.il')

foreach ($Email in $EmailList) {
  $DidItMatch = $Email -match $EmailRegex
  if ($DidItMatch) {
    # It matched! Do something.
  }
  else {
    # It didn't match
  }
}

仅供参考,当您使用-match运算符时,如果它返回布尔值$true,则PowerShell会自动填充名为$matches的内置(又称“自动”)变量。为避免意外行为,您可能希望在每次迭代期间将此变量重置为$null,或者将其包装在函数中,就像在原始示例中一样。这将使变量作用域保持在函数级别,只要您不在其中一个父作用域中声明它。

验证完电子邮件地址后,您可以使用以下方法将其附加到现有的CSV文件中:

Export-Csv -Append -FilePath filepath.csv -InputObject $Email

为了提高可用文件系统资源的效率,您可能希望在将它们附加到目标CSV文件之前,在内存中缓冲一些电子邮件地址。

# Initialize a couple array buffers
$ValidEmails = @()
$InvalidEmails = @()

if ($ValidEmails.Count -gt 50) {
  # Run the CSV export here
}

if ($Invalid.Count -gt $50) {
  # Run the CSV export here
}

如果您需要进一步的帮助,请编辑您的问题并澄清哪些不适合您?

答案 2 :(得分:1)

当前的前2个答案中的每个都有一个明显的缺陷:

@Trevor的答案就可以了,除非您提供此答案:

John Doe <johndoe@somewhere.com>

@Mathias的答案是关于容纳特殊(至今有效)的地址,例如具有非ASCII或无TLD后缀的地址。以下地址全部通过[mailaddress]强制转换成功验证:

olly@somewhere | olly@somewhere. | olly@somewhere...com  etc

如果像我一样,您不会在电子邮件数据库中使用这些极端情况,那么两种想法的结合可能会更有用,就像这样:

function IsValidEmail { 
    param([string]$Email)
    $Regex = '^([\w-\.]+)@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.)|(([\w-]+\.)+))([a-zA-Z]{2,4}|[0-9]{1,3})(\]?)$'

   try {
        $obj = [mailaddress]$Email
        if($obj.Address -match $Regex){
            return $True
        }
        return $False
    }
    catch {
        return $False
    } 
}

为可能很长的邮件列表中的每个电子邮件地址创建$obj可能会带来性能开销。但是我想那是另一回事。

答案 3 :(得分:1)

您可以使用mailaddress类型来确保它符合RFC,但是您可能仍要确保域有效:

Resolve-DnsName -Name ('vertigoray@example.com' -as [mailaddress]).Host -Type 'MX'

作为功能参数的验证脚本,效果很好:

function Assert-FromEmail {
    param(
        [Parameter(Mandatory = $true)]
        [ValidateScript({ Resolve-DnsName -Name $_.Host -Type 'MX' })]
        [mailaddress]
        $From
    )

    Write-Output $From
}

成功输出该函数的示例:

PS > Assert-FromEmail -From vertigoray@example.com

DisplayName User       Host        Address
----------- ----       ----        -------
            vertigoray example.com vertigoray@example.com

在失败时输出该函数的示例:

PS > Assert-FromEmail -From vertigoray@example..com
Assert-FromEmail : Cannot validate argument on parameter 'From'. The " Resolve-DnsName -Name $_.Host -Type 'MX' "validation script for the argument with value "vertigoray@example..com" did not return a result of True. Determine why the validation script failed, and then try the command again.
At line:1 char:24
+ Assert-FromEmail -From vertigoray@example..com
+                        ~~~~~~~~~~~~~~~~~~~~~~~
    + CategoryInfo          : InvalidData: (:) [Assert-FromEmail], ParameterBindingValidationException
    + FullyQualifiedErrorId : ParameterArgumentValidationError,Assert-FromEmail

答案 4 :(得分:0)

这是一个尝试我编写和测试的人,并且在迄今为止的任何环境中都没有让我失望。不,说它不会在其他人身上,但对我来说,它已经100%了。

$SomeEmailAddresses = @'
From:JoeBob@yahoo.com,Tom TheCat tcat@snailmail.net,jerry@snailmail.net 
To:TulaJane@hotmail.com;JF@gmail.com;tiger@outlook.com; 
Doug Tompson DTompson@icloud.com 
MailTo:BobsYourUncle@protonmail.com; 
johnny.bravo@yahoo.co.uk
'@

(((Select-String -InputObject $SomeEmailAddresses `
-Pattern '\w+@\w+\.\w+|\w+\.\w+@\w+\.\w+\.\w+' `
-AllMatches).Matches).Value)


Rsults 

JoeBob@yahoo.com
tcat@snailmail.net
jerry@snailmail.net
TulaJane@hotmail.com
JF@gmail.com
tiger@outlook.com
DTompson@icloud.com
BobsYourUncle@protonmail.com
johnny.bravo@yahoo.co.uk