Emails not sending when calling multiple scripts - powershell

Good afternoon -
I have a "trigger file" that calls several scripts to run some morning reports. Each called script contains code that attaches a file to an email and sends (via ComObject). If I run each script individually then there all emails send correctly. However, when i run the "trigger file", only a couple of the emails send and I am not receiving any error messages. Any ideas what is happening? I purposely made the trigger file run the scripts concurrently to save time. But is that overloading Outlook?
EDIT: Updated code to include Try/Catch block. There are 8 scripts that run using this template. All 8 successfully complete the excel open/run/save. However, only some of the emails send. And even with this Try/Catch block, no error message is being sent.
#Establish script file locale
$FullPath = “//fullpath/”
$SavePath = “//savepath/”
#Open Excel file
& {
$Excel = New-Object -ComObject excel.application
$Excel.Visible=$False
$Workbook = $Excel.Workbooks.Open($FullPath)
#Run Macro
$app=$Excel.Application
$app.Run("Macro1")
#Save and close Excel
$Excel.Application.DisplayAlerts=$False
$Workbook.SaveAs($SavePath,51)
$Workbook.Close()
$Excel.Quit()
}
#Send email with attachment
Try
{
$EmailSettings=#{
SMTPServer = "smtp"
From = "me#email.com"
To =
#(
"you#email.com"
)
Subject = "Subject"
Attachments = $SavePath
BodyAsHtml = $true
Body =
"<body><p>
Attached is the thing.
</b></p></body>"
}
Send-MailMessage #EmailSettings
}
Catch
{
$Subject = 'ERROR: '+$EmailSettings.Subject
$ErrorMessage = $_.Exception.Message+' '+$_.Exception.ItemName
Send-MailMessage -From me#email.com -To me#email.com -Subject $Subject -SmtpServer smtp -Body $ErrorMessage
}

Related

Release Artifacts delivered to user group as an attachment in email

I work with build and release in VSTS. I use Copy Files option in my Build definition and copy the Artifacts in a folder. I want that the Artifacts ( .exe, .dll, .zip etc)created at the end of the release must be attached in an email and must be delivered to a list of email addresses.
How this can be achieved.
Use archive task to zip the files and use powershell script given below to send an email with attachment.
Now use Powershell task and paste following script. Please edit SMTP and email settings.
$SMTPServer = "smtp.gmail.com"
$SMTPPort = "587"
$Username = "Youremail#gmail.com"
$Password = "Pass#1"
$to = "senderemail#gmail.com"
#$cc = "ccemail#gmail.com"
# Below subject line will have todays date and Build status as Succeed or Failed
$subject = "$(get-date -format dd-mm-yy) Automation Test report $(Agent.JobStatus)"
$body = "Your email body text"
# Enter the path of existing Archieve output folder
$attachment = "$(Build.ArtifactStagingDirectory)/YourZipFolderName.zip"
$message = New-Object System.Net.Mail.MailMessage
$message.subject = $subject
$message.IsBodyHTML = $true
$message.body = $body
$message.to.add($to)
#$message.cc.add($cc)
$message.from = $username
$message.attachments.add($attachment)
$smtp = New-Object System.Net.Mail.SmtpClient($SMTPServer, $SMTPPort);
$smtp.EnableSSL = $true
$smtp.Credentials = New-Object System.Net.NetworkCredential($Username, $Password);
$smtp.send($message)
write-host "Mail Sent successfully using GMAIL"
Please make sure to Use run option as "Even if a previous task has failed, unless the build was canceled" as shown below.
You can use Send Email task to achieve it. Details as below:
In the end of your release environment -> Add a Send Email task -> configure required options.
To delivery the artifact files by the Send Email task, you can select the Add Attachment option and specify absolute path for the attachment:

Powershell Workflows

I wrote a PowerShell workflow that analyses the Excel data and triggers a mail based on the values in Excel.
I have developed a workflow which triggers mail but I'm having trouble in analysing the Excel data, where I couldn’t call the Send-Mail workflow.
Note: column “E-remainder 1” and “F-remainder 2” contains the date of the remainder mail to be sent.
Workflow test {
$worksheet = InlineScript {
$objExcel = New-Object -ComObject Excel.Application
$objExcel.Visible = $false
$WorkBook = $objExcel.Workbooks.Open(#filepath)
$worksheet = $workbook.Sheets.Item(#sheetname)
$currentdate = (Get-Date).ToString()
$rownumber = #contains rownumber from excel whose details has to be mailed
foreach ($i in $rownumbers) {
if ($worksheet.Range("B$i").Text -eq $currentdate) {
$output = [PSCustomObject][ordered]#{
ComputerName = $WorkSheet.Range("C$i").Text
Fromaddress = $WorkSheet.Range("D$i").Text
Toaddress = $WorkSheet.Range("E$i").Text
}
# I need to call a workflow which sends a mail
# (workflow which I have to trigger mail)
Send-Mail -To $output.Toaddress -From $output.Fromaddress -Name $output.ComputerName
} elseif ($worksheet.Range("F$i").Text -eq $currentdate) {
$output = [pscustomobject][ordered]#{
ComputerName = $WorkSheet.Range("C$i").Text
Fromaddress = $WorkSheet.Range("D$i").Text
Toaddress = $WorkSheet.Range("E$i").Text
}
# I need to call a workflow which sends a mail
# (Based on my knowledge I know that we couldn't call a workflow inside the inline script)
Send-Mail -To $output.Toaddress -From $output.Fromaddress -Name $output.ComputerName
}
} # foreach ends
} # Inline ends
} # workflow ends
Im getting the following error:
ERROR:The term "Send-Mail" is not recognized as the name of the cmdlet, function, script file, or operable program. Check the spelling of the name, or if a path was included, verify that the path is correct and try again.

Send mail via powershell without authentication

I was using nant to send mail and it is working fine - something like
<mail
from="Test#b.c"
tolist="A#b.c"
subject="Test"
mailhost="myhost.mydomain.com"
isbodyhtml="true"
message= "${Test}">
</mail>
I didn't have to use any kind of authentication.
Now when using powershell it seems I am forced to use authentication - something like this would fail:
Send-MailMessage -To $to -From $from -Subject "Test" –Body “Test (body) -SmtpServer "myhost.mydomain.com"
I would get the following message:
Send-MailMessage : No credentials are available in the security package
Am I missing some way to send mails without specifying credentials if the server supports that?
Edit:
I've also tried the answer here to send anonymous mails but it just times out:
send anonymous mails using powershell
Sending mails using Powershell v1 method works fine without authentication as shown here
My Powershell version is 5 yet this is apparently the way to go, unless someone has another idea.
$smtpServer = "ho-ex2010-caht1.exchangeserverpro.net"
$smtpFrom = "reports#exchangeserverpro.net"
$smtpTo = $to
$messageSubject = $subject
$messageBody = $body
$smtp = New-Object Net.Mail.SmtpClient($smtpServer)
$smtp.Send($smtpFrom,$smtpTo,$messagesubject,$messagebody)
I was looking for another issue and found this question here...
As #AngelicCore already explained one approach,
Here is another one if someone using Outlook dektop app...
The mail sent will appear in your outbox.
using outlook object
Try
{
#Email structure
$Outlook = New-Object -ComObject Outlook.Application
$Mail = $Outlook.CreateItem(0)
#Email Recipients
$Mail.To = "abc#domain.com;xyz#domain.com"
$Mail.Cc = "tuv#domain.com; pqr#domain.com"
#Email Subject
$date = Get-Date -Format g
$Mail.Subject = "Subject here $date"
#Email Body
$Mail.Body = "Body Here"
#Html Body
$Mail.HTMLBody == "<html> HTML Body Here </html>"
#Email Attachment
$file = "C:\path\xyz.txt"
$Mail.Attachments.Add($file)
$Mail.Send()
Write-Host -foreground green "Mail Sent Successfully"
}
Catch
{
write-host -foreground red $error[0].Exception.Message
}
pause
exit

Console output to email in Powershell

I am writing a powershell script for a monthly maintenance process. In order to track it I am using a try catch block that will send an email when it succeeds or fails. To do this I am using smtp. I am wondering how to write the console output to the email. Please let me know if you have any suggestions. Having trouble getting started.
Thank you in advance.
This is what I recently tried but it didn't work:
catch {
$smtpServer = "example"
$msg = new-object Net.Mail.MailMessage
$smtp = new-object Net.Mail.SmtpClient($smtpServer)
$msg.From = "example"
$msg.To.Add("example")
$msg.Subject = "MONTHLY MAINTENANCE FAILED!"
$msg.Body= Write-Error ("Monthly maintenance failed! Please investigate." + $_)
$smtp.Send($msg)
$msg.Dispose();
}
Q: What "Didn't work"?
SUGGESTION:
1) Write a sample script that deliberately triggers the error
2) Make sure you're successfully capturing the error text you want (you should be able to get it from $_, like you're doing)
3) Make sure your e-mail parameters are correct
4) Divide and conquer: Powershell syntax first, E-Mail connectivity after.
My hunch is you'll need to debug your e-mail connectivity.
For example:
Try {
1/0 # throw "divide by zero"
}
Catch {
$errmsg = "Monthly maintenance failed! Please investigate." + $_
Write-Console $errmsg
$smtpServer = "example"
$msg = new-object Net.Mail.MailMessage
$smtp = new-object Net.Mail.SmtpClient($smtpServer)
$msg.From = "example"
$msg.To.Add("example")
$msg.Subject = "MONTHLY MAINTENANCE FAILED!"
$msg.Body= $errmsg
$smtp.Send($msg)
$msg.Dispose();
}

Send outlook email from powershell script

When I write the following script into the powershell command line one by one, it successfully sends the email, but when I run the script, it returns a bunch of errors. I'm guessing something syntactically needs to be changed in order to run it as a script? Any ideas?
Start-Process Outlook
$o = New-Object -com Outlook.Application
$mail = $o.CreateItem(0)
#2 = high importance email header
$mail.importance = 2
$mail.subject = “Auto Build Test“
$mail.body = “This is a test“
#for multiple email, use semi-colon ; to separate
$mail.To = “myemail#company.com"
$mail.Send()
# $o.Quit()
Param(
[parameter(Mandatory=$true)]
[alias("e")]
[string]$RecipientEmailAddress
)
if($RecipientEmailAddress -notmatch "\b[A-Za-z0-9._%+-]+#BLAHH.com")
{
Write-Output "the email address for the receipient of log reports is not a valid email address, hence will not send the report via email. They can still be accessed at " |Out-String ;
}else
{
$returnVal= New-Object PSObject ;
$returnVal |Add-Member -Name is_Success -MemberType NoteProperty -Value $null;
$returnVal |Add-Member -Name Explanation -MemberType NoteProperty -Value $null;
try{
$Attachments =Get-ChildItem -Path "C:\FOLDERWHEREYOURAATACHMENTS ARESTORED";
if($Attachments.count -eq 0)
{
$returnVal.Explanation="Error sending log report email to the user: $RecipientEmailAddress. Please check if the C:\FOLDERWHEREYOURAATACHMENTS is accessible and there are indeed log files present";
#Write-Output "Error sending log report email to the user: $RecipientEmailAddress" |Out-String ;
#Write-Output "Please check if the C:\FOLDERWHEREYOURAATACHMENTS is accessible and there are indeed log files present "|Out-String;
$returnVal.is_Success= $false;
return $returnVal;
}
$TestedAttachmentsList = new-Object System.Collections.ArrayList;
for($i=0;$i -lt $Attachments.count;$i++)
{
$TestedAttachmentsList.add($Attachments[$i].FullName);
}
Send-MailMessage -From "<FROM#BLAHH.COM>" -To "<$RecipientEmailAddress>" -SmtpServer "mail.BLAHH.com" -Attachments $TestedAttachmentsList -Subject "BLAHH SUBJECT" -Body "BLAHH BLAHH";
$returnVal.is_Success=$true;
$returnVal.Explanation="An email has been sent to the $RecipientEmailAddress containing the log of the setup and configuration."
return $returnVal ;
}Catch [System.Exception]
{
#Write-Output "Error sending log report email to the user: $RecipientEmailAddress" |Out-String ;
#Write-Output "Please check communication between your host machine and mail.BLAHH.com on port 25 is possible"|Out-String;
$returnVal.is_Success= $false;
$returnVal.Explanation="Error sending log report email to the user: $RecipientEmailAddress Please check communication between your host machine and mail.BLAHH.com on port 25 is possible";
return $returnVal ;
}
}
The syntax doesn't change between the command line and a script file. What changes is how fast the commands are executed. If you're typing them in then there is plenty of delay between each command. But if they run from a script they get presented to Outlook much more quickly.
A simple way to fix this is add Sleep 1 (or similar) before the command that fails. Without seeing your error output I would guess that you want to sleep after CreateItem and maybe before Send. But if you look at the error messages closely you'll see they identify which line of the script failed. Put Sleep before the first line that failed. Retry the script. If a new line fails, then put a delay before it as well. If the first line still fails you can try Sleep 2. You can also make the Sleep shorter. For 1/2 second: Sleep -milliseconds 500.
IF adding Sleeps fixes the problems - in other words the problem is a synchronization issue, there may be something in the Outlook object model you could use that wouldn't be as hackish as using Sleeps.
I wasn't able to repro this on my Outlook 2010 installation. However I did look up an alternate method for sending email from PS (below). Maybe this method will work.
$i=$o.Session.folders.item(2).folders.item("Outbox").items.add(0)
$i.to="me#whereiwork.com"
$i.Subject="a wittle testy"
$i.Body="some body"
$i.send()