【问题标题】:Powershell to Validate Email addressesPowershell 验证电子邮件地址
【发布时间】:2020-07-10 05:13:56
【问题描述】:

我正在尝试让 Powershell 使用正则表达式验证电子邮件地址,并将电子邮件地址放入好的和坏的 csv 文件中。我可以让它跳过一行并写入文件,但不能让它以电子邮件地址为目标并验证它们,然后将行写入好文件和坏文件。我可以在 C# 和 JavaScript 中做到这一点,但从来没有在 Powershell 中做到过。我知道这可以做到,但不知道怎么做。

这是我目前所拥有的:

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

我正在验证原始 csv 文件中的第三列“电子邮件”,并尝试将整行写入文件(好文件、坏文件)。不知道如何缓冲这样做。

ForEach ($emailAddress in $list) { 
    if (IsValidEmail($emailAddress)) { 
        "Valid: {0}" -f $emailAddress
        Out-File -Append C:\Emails\ValidEmails\ValidEmails.csv -Encoding UTF8
        $EmailAddressImp | Export-Csv "C:\Emails\ValidEmails\ValidEmails.csv" 
        -NoTypeInformation
    } 
    else { 
        "Invalid: {0}" -f $emailAddress 
        Out-File -Append C:\Emails\InValidEmails\InValidEmails.csv -
        Encoding UTF8
        $EmailAddressImp | Export-Csv 
        "C:\Emails\InValidEmails\InValidEmails.csv" -NoTypeInformation
    }     
}                                         

【问题讨论】:

  • 您好,您可能希望使用一种服务来实际检查电子邮件是否有效,而不仅仅是语法上的,而是它实际存在的。您可以使用支持 csv 文件验证的 isitarealemail.com 之类的东西。

标签: powershell validation email


【解决方案1】:

我正在尝试让 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 - 如果不是,则转换将导致异常,并返回$false


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

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

$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)}

如果您使用的是 PowerShell 4.0 或更高版本,我建议在 Split 模式下使用 .Where() 扩展方法:

$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')

在导出到文件之前:

if($valid.Count -gt 0){ 
    $valid |Export-Csv "C:\Emails\ValidEmails\ValidEmails.csv" -NoTypeInformation
}
if($invalid.Count -gt 0){ 
    $invalid |Export-Csv "C:\Emails\ValidEmails\InvalidEmails.csv" -NoTypeInformation
}

【讨论】:

  • [MailAddress]"me@myself..com" 验证不正确。
  • olly@somewhereolly@somewhere.olly@somewhere...com 都适用于这个!!!他们应该吗?
  • 它们都是 RFC 有效的邮件地址 :) 第二个验证步骤可能是 ([mailaddress]olly@somewhere.).Host 的 MX 解析
【解决方案2】:

您可以只使用-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
}

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

【讨论】:

  • 我很抱歉造成混乱,但我正在尝试验证 CSV 文件中的第三列“电子邮件”,然后将具有好或坏电子邮件地址的整行写入其中之一这两个文件(好电子邮件,坏电子邮件)。我只有在那里进行测试的字符串。很抱歉造成混乱。
  • 你在帮助方面真是太棒了......我知道另一个人不想让我使用正则表达式,但这是一个与其他编程语言(C#, JavaScript)。这个想法是使用正则表达式进行验证。我知道这可能不是最佳做法,但这是给我的说明(标准)。
  • @ChrisSingleton 很高兴为您提供帮助,克里斯。希望您可以将其适应您的 CSV 结构。这可能需要一个单独的问题。 :)
【解决方案3】:

这里当前的前 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 可能会产生性能开销。但我想那是另一回事了。

【讨论】:

  • [mailaddress]'John Doe ' 工作正常!看看输出...
【解决方案4】:

您可以使用 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

【讨论】:

    【解决方案5】:

    这是我编写和测试的一个尝试,迄今为止在任何环境中都没有让我失望。不是,说别人不会,但对我来说,是 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
    

    【讨论】:

      猜你喜欢
      • 2014-06-12
      • 1970-01-01
      • 2018-03-13
      • 2011-09-02
      • 2013-02-20
      • 2014-03-12
      • 1970-01-01
      • 2012-04-08
      • 2015-09-09
      相关资源
      最近更新 更多