Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Powershell to Validate Email addresses

I'm trying to get Powershell to validate email addresses using Regex and put email addresses into good and bad csv files. I can get it to skip one line and write to file, but cannot get it to target the email addresses and validate them, then write lines to good and bad files. I can do it in C# and JavaScript, but have never done it in Powershell. I know this can be done, but not sure how.

Here is what I have so far:

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

I'm validating the third column "Email" in the original csv file and trying to write out the whole row to file (good file, bad file). Not sure how to buffer either doing this.

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
    }     
}                                         
like image 532
Chris Singleton Avatar asked Jan 14 '18 20:01

Chris Singleton


1 Answers

I'm trying to get Powershell to validate email addresses using Regex

Don't!

I would recommend against this. Accurately validating email addresses using regular expressions can be much more difficult than you might think.

Let's have a look at your regex pattern:

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

In it's current form it incorrectly validates [email protected].

On the other hand, it doesn't validate unicode-encoded internationalized domain names, like user@☎.com (yes, that's a valid email address)


Instead of trying to find or construct a perfect email validation regex pattern, I would use the MailAddress class for validation instead:

function IsValidEmail { 
    param([string]$EmailAddress)

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

If the input string is a valid email address, the cast to [mailaddress] will succeed and the function return $true - if not, the cast will result in an exception, and it returns $false.


When exporting the data, I'd consider collecting all the results at once in memory and then writing it to file once, at the end.

If you're using PowerShell version 2 or 3, you can do the same with two passes of 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)}

If you're using PowerShell version 4.0 or newer, I'd suggest using the .Where() extension method in Split mode:

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

before exporting to file:

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
}
like image 114
Mathias R. Jessen Avatar answered Oct 19 '22 16:10

Mathias R. Jessen