0

Sorry for the bad title, but I'm having trouble describing this with brevity.

I wrote a Powershell script that sends an email with a specific attachment to a list of users in a CSV. The script does what it is supposed to do. I am importing a CSV and piping it to ForEach-Object. Ex:

Import-Csv $csvFile | ForEach-Object{Send-MailMessage -To $($_.email) -Attachments $attachPath$($_.attachment) -SmtpServer $mailServer -Credential $credential -UseSsl $subject -Port $mailServerPort -Body "Hello $($_.name),$body" -From $sender -BodyAsHtml }

Again, this works as intended. The issue I have is that if there is an error I have no idea which iteration of the loop it occurred in.

I've figured out how to pipe the errors to a file using:

Import-Csv $csvFile | ForEach-Object{Send-MailMessage -To $($_.email) -Attachments $attachPath$($_.attachment) -SmtpServer $mailServer -Credential $credential -UseSsl $subject -Port $mailServerPort -Body "Hello $($_.name),$body" -From $sender -BodyAsHtml } 2>> error.txt

However, this does not give me any specific information on which line of the CSV it failed on.

According to Microsoft's documentation for the Send-MailMessage Cmdlet it does not provide any output.

I'd be happy if it would just print the $_.email along with the error to error.txt but everything I've tried doesn't work.

Any help would be immensely appreciated.

1 Answer 1

3

I swear, I only post try/catch responses here now.

So, the way around this problem is to take your process, add -ErrorAction STOP and place the whole bit of code within a try/catch block. This will allow us to try your first command, if we hit an error, then we'll run the bit of code within the catch block. We'll just put a better Write-Error message here to give you some better output. And we'll also store of the one's with errors in a variable we can output at the end.

$errors = @()

Import-Csv $csvFile | ForEach-Object{
    try {Send-MailMessage -To $($_.email) -Attachments $attachPath$($_.attachment) `
            -SmtpServer $mailServer -Credential $credential -UseSsl $subject `
            -Port $mailServerPort -Body "Hello $($_.name),$body" -From $sender -BodyAsHtml -ErrorAction Stop}
  catch {Write-Error "Unable to send e-mail for this object $_.email" 
        $errors += $_.Email}  
    }

    Write-output "Unable to send e-mails for the following users"
    $errors

Give it a shot, and let me know how it works for you.

Sign up to request clarification or add additional context in comments.

2 Comments

Thanks so much. As written, it runs fine when there are no errors. When I introduce an error (I gave a bad email address on one of the csv lines) I get: Unable to send e-mail for this object The specified string is not in the form required for an e-mail address..email At line:1 char:1 + C:\ps\key-mail\keys-mail-test.ps1 + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + CategoryInfo : NotSpecified: (:) [Write-Error], WriteErrorException + FullyQualifiedErrorId : Microsoft.PowerShell.Commands.WriteErrorException,keys-mail-test.ps1 Unable to send e-mails for the following users
Cool, that's better than no output. Another thing you could do is modify that $catch statement and add the current error message to $errors. The code for that, is as follows $errors += $error[0] also, you'll want to comment out the Write-Error line I provided. These changes will grab the most recent error and collect that in $errors. Then you'll be able to capture the output from Send-Mailmessage.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.