Powershell - Send email when number of days reaches a set interval - powershell

I'm at a blocker and need some help!
(New-Timespan -Start (Get-Date) -End (Get-AdfsCertificate -CertificateType Token-Signing | where-object { $_.IsPrimary -eq $true }).Certificate.NotAfter).Days
This returns a result of days until it is no longer a primary certificate. E.G simply "141"
How can I implement a way of looking at this result and sending an email when it reaches a certain day? E.G 20 days until it is no longer primary.
I can use a mail relay, so no credentials are required!
Many thanks in advance!

Put your code in a Task Schedule to run on a date and time, use an if/then code block to check the state, and send as needed when it meets your metric.
For example:
If ((New-Timespan -Start (Get-Date) -End (Get-AdfsCertificate -CertificateType Token-Signing |
where-object { $PSItem.IsPrimary -eq $true }).Certificate.NotAfter).Days -eq 20)
{
# Do something here
}
As for email, this is why the Send-MailMessage cmdlet exists.
Get-Help -Name Send-MailMessage -Full
Get-Help -Name Send-MailMessage -Examples
# Results
<#
NAME
Send-MailMessage
SYNOPSIS
Sends an email message.
# -- Example 1: Send an email from one person to another person --
Send-MailMessage -From 'User01 <user01#fabrikam.com>' -To 'User02 <user02#fabrikam.com>' -Subject 'Test mail'
The `Send-MailMessage` cmdlet uses the From parameter to specify the message's sender. The To parameter specifies the message's recipient. The Subject
parameter uses the text string Test mail as the message because the optional Body parameter is not included.
# ---------------- Example 2: Send an attachment ----------------
Send-MailMessage -From 'User01 <user01#fabrikam.com>' -To 'User02 <user02#fabrikam.com>', 'User03 <user03#fabrikam.com>' -Subject 'Sending the
Attachment' -Body "Forgot to send the attachment. Sending now." -Attachments .\data.csv -Priority High -DeliveryNotificationOption OnSuccess,
OnFailure -SmtpServer 'smtp.fabrikam.com'
The `Send-MailMessage` cmdlet uses the From parameter to specify the message's sender. The To parameter specifies the message's recipients. The
Subject parameter describes the content of the message. The Body parameter is the content of the message.
The Attachments parameter specifies the file in the current directory that is attached to the email message. The Priority parameter sets the message
to High priority. The -DeliveryNotificationOption parameter specifies two values, OnSuccess and OnFailure . The sender will receive email
notifications to confirm the success or failure of the message delivery. The SmtpServer parameter sets the SMTP server to smtp.fabrikam.com .
# ----------- Example 3: Send email to a mailing list -----------
Send-MailMessage -From 'User01 <user01#fabrikam.com>' -To 'ITGroup <itdept#fabrikam.com>' -Cc 'User02 <user02#fabrikam.com>' -Bcc 'ITMgr
<itmgr#fabrikam.com>' -Subject "Don't forget today's meeting!" -Credential domain01\admin01 -UseSsl
The `Send-MailMessage` cmdlet uses the From parameter to specify the message's sender. The To parameter specifies the message's recipients. The Cc
parameter sends a copy of the message to the specified recipient. The Bcc parameter sends a blind copy of the message. A blind copy is an email
address that is hidden from the other recipients. The Subject parameter is the message because the optional Body parameter is not included.
The Credential parameter specifies a domain administrator's credentials are used to send the message. The UseSsl parameter specifies that Secure
Socket Layer (SSL) creates a secure connection.
#>

Related

Is there a way to execute a command from within a string or have more than one body in a powershell email?

I'm trying to send an email that contains both some information that I type out as well as the contents of a text file that was generated in earlier code. I was wondering if there is a convenient way of doing so without sending two emails? The code below didn't work but I can get the message to send if I only have the text or only have the contents of the txt file. Thanks!
Send-MailMessage -SMTPServer localhost -To myemail#email.com -From myemail#email.com -Subject "TESTING Active Domain Replication Failure TESTING" -Body "The following Domain Controller has had a replication failure. Please see attached txt files for more information. `n"(Get-Content -Path .\causeOfFailure.txt | out-string) -attachment error.zip
So I edited the statement to look like this:
$fileContent = (Get-Content -Path .\causeOfFailure.txt)
compress-archive -Path causeOfFailure.txt,dnsInformation.txt -update -DestinationPath error.zip
Send-MailMessage -SMTPServer localhost -To email#email.com -From email#email.com -Subject "TESTING Active Domain Replication Failure TESTING" -Body "The following Domain Controller has had a replication failure. Please see attached txt files for more information. `n & $ExecutionContext.InvokeCommand.ExpandString($fileContent)" -attachment error.zip
The output in the email shows this message
"System.Management.Automation.EngineIntrinsics.InvokeCommand.ExpandString(Source Controller:".
Is there a better way to have a string followed by a function both be part of the body of an email with the send-mailmessage command?
If you are trying to add the contents of a file to the body of the email, you can simply use $() to include functions within the quotes.
Send-MailMessage -SMTPServer localhost -To email#email.com -From email#email.com -Subject "TESTING Active Domain Replication Failure TESTING" -Body "The following Domain Controller has had a replication failure. Please see attached txt files for more information. `n $fileContent" -attachment error.zip
If you want to include the function within your script, you can do this,
Send-MailMessage -SMTPServer localhost -To email#email.com -From email#email.com -Subject "TESTING Active Domain Replication Failure TESTING" -Body "The following Domain Controller has had a replication failure. Please see attached txt files for more information. `n $(Get-Content -Path .\causeOfFailure.txt)" -attachment error.zip
The problem is because of the way you are constructing the body string.
You already have the content of the causeOfFailure.txt in a variable $fileContent, so there is no need to do a Get-Content on the same file again.
I would suggest you create your body in a separate variable first, to make the code more readable.
There are several options for this, like
Make use of a Here-String
$body = #"
The following Domain Controller has had a replication failure. Please see attached txt files for more information.
$fileContent
"#
Or insert a NewLine followed by the $fileContent using the -f Format operator
$body = 'The following Domain Controller has had a replication failure. Please see attached txt files for more information.{0}{1}' -f
[Environment]::NewLine, $fileContent
Or simply create as one double-quoted string
$body = "The following Domain Controller has had a replication failure. Please see attached txt files for more information.`r`n$fileContent"
Whichever you find is the most readable/maintainable method for your code.
Then for the part where you use the Send-MailMessage cmdlet.
Here again, writing out all parameters as one long line can make the code less readable and by doing that, mistakes are easily made.
There is a better way to use a cmdlet with lots of parameters, known as Splatting.
Applied to your code, this looks like:
# create a hashtable object with all parameters you want to use for Send-MailMessage
$mailParams = #{
SMTPServer = 'localhost'
To = 'myemail#email.com'
From = 'myemail#email.com'
Subject = "TESTING Active Domain Replication Failure TESTING"
Body = $body
Attachments = 'error.zip'
}
Send-MailMessage #mailParams
Hope this helps

How to check whether the email has been sent with Powershell

I am currently writing a Powershell script, which pings a server and if a connection cannot be established, sends an email to the IT department to restart the server manually.
Right now, the script can successfully send the email when the ping is unsuccessful and the object has a property value, which is supposed to evaluate to "True", but I can't verify that, because upon sending the email, the variable deletes itself and therefore the property doesn't exist anymore.
$Outlook = New-Object -ComObject Outlook.Application
$Mail = $Outlook.CreateItem(0)
$Mail.To = "<recipient>"
$Mail.Cc = "<some_cc>"
$Mail.Send()
# After this line, the variable is deleted!
if ($Mail.Sent())
# The line which is supposed to work, but evaluates to False everytime
How do I make sure that this variable survives until I can verify the exchange?
The variable won't survive after Send method, and won't return a value either.
You are delegating the actual sending action to Outlook so you'll need to check Outlook Application for errors (i.e. a bounce).
If sending via Outlook is not necessary, you can have more options with
try {
Send-MailMessage -From 'monitoring#example.com' -To 'ITdesk#example.com' -Subject 'test' -Body 'whatever' -Priority High -DeliveryNotificationOption OnSuccess, OnFailure -SmtpServer 'mail.example.com' -ErrorAction stop -Port 25
}
catch{
write-warning "error in sending. $_"
}
Note that if you need authenticated send you can specify saved credentials via the -credential parameter.
References here:
https://learn.microsoft.com/en-us/powershell/module/microsoft.powershell.utility/send-mailmessage?view=powershell-6
You could put the mail.send() inside a try/catch block. That way it would output if there were any errors or if it succeeded. Plus, there's no need for another variable.
try{
mail.send()
write-host "success"
}catch{
write-host "fail"
}

Capture all errors in a powershell script and email

I have a script with many sections such as below that runs nightly. I would like to get it to email any/all errors so i can be alerted and review the errors. I'm having trouble with the first step which is to capture all/any errors... I assume to a file which i could email or capturing to some kind of buffer that i could then email would be even nicer. Any help with both steps would be appreciated - especially the capturing part.
#---- Set Exchange archive licnse for all users with an Office license ----
Get-MsolUser -ALL | where {($_.Licenses.accountskuID -contains
"Tennant:STANDARDWOFFPACK") -and ($_.Licenses.accountskuID -notcontains
"Tennant:EXCHANGEARCHIVE_ADDON")} | Set-MsolUserLicense -AddLicenses
"Tennant:EXCHANGEARCHIVE_ADDON"
#-------------------------- ENABLE LITIGATION HOLD ----------------------
Get-Mailbox -ResultSize Unlimited -Filter {RecipientTypeDetails -eq
"UserMailbox"} | Set-Mailbox -LitigationHoldEnabled $true -
LitigationHoldDuration 2555
Error messages should automatically be captured in the $error variable; use $error[0] for the latest message.
You could then use that as the body for your email in conjunction with the Send-MailMessage Cmdlet
example:
$body = "";
foreach ($e in $error) {
$body += "<hr /><pre>" + $e.ToString() + "</pre><hr />";
}
Send-MailMessage -BodyAsHtml -Body $body -SmtpServer "smtp_server_address" -From "alert#somedomain.tld" -To "your-email#somedomain.tld" -Subject "PowerShell Error Report"
In your code, you need to trap errors in order to log them, even write to your own event log...
https://blogs.technet.microsoft.com/heyscriptingguy/2013/02/01/use-powershell-to-create-and-to-use-a-new-event-log
https://blogs.technet.microsoft.com/heyscriptingguy/2013/06/20/how-to-use-powershell-to-write-to-event-logs
... or write your own log function.
Example:
https://gallery.technet.microsoft.com/scriptcenter/Write-Log-PowerShell-999c32d0
Or, start with using PowerShell logging.
Example:
Enable logging in Group Policy
https://gallery.technet.microsoft.com/scriptcenter/Write-Log-PowerShell-999c32d0
Use PowerShell transcript
Example:
https://technet.microsoft.com/en-us/library/ff687007.aspx?f=255&MSPPError=-2147217396
Then have those stored in a central share that you can pull into an email as an attachment.

Capture the Keyword FAILED from a file and send out a email notification

I require a PowerShell script to capture the error FAILED from an output file and, if the status is FAILED, then send the email to the DL list with the subject as failed and in the body of the email should have output file format as it is. I am stuck in writing the if statement. Please help me.
The location of the output file is D:\logs.
Format of the output file:
process_id : 1
STATUS : FAILED
RULE_ID : 44
RULE_NAME : OEBS-1
LAST_UPDATE_DATE : 1/4/2017 11:37:02 AM
import-csv d:\logs\logfile.csv | where-object { $_.STATUS -eq "FAILED" } |
send-mailmessage -from "User01 <user01#example.com>" -to "User02 <user02#example.com>",
"User03 <user03#example.com>" -subject "Sending the Attachment" -body
"Forgot to send the attachment. Sending now." -Attachments "data.csv"
-priority High -dno onSuccess, onFailure -smtpServer smtp.fabrikam.com
I have used the send-mailmessage from Example 2 of here: https://msdn.microsoft.com/en-us/powershell/reference/3.0/microsoft.powershell.utility/send-mailmessage?f=255&MSPPError=-2147217396. This gives the examples of using many of the send-mailmessage paramaters. You can use the ones you require, or modify to add what you would like.
** The formatting of the code might be out. I tried to keep it reasonably tidy and on one page without scrolling. I haven't used ` to indicate a new line as you would in actual PowerShell code.
$failed = import-csv d:\logs\logfile.csv | where-object {$_.STATUS -eq "FAILED"}
send-mailmessage -from failedjob#fabrikam.com -to dl#fabrikam.com -subject Failed -body $failed -smtpserver mailserverthatwillaccept.fabrikam.com
That's another option.
** Edited to import-csv as per comments from Ansgar
Thanks, Tim.

PowerShell send-mailmessage

How do I terminate cmdlet prompts for To[] address?
It keeps asking for more!
this is what I see:
send-mailmessage
cmdlet Send-MailMessage at command pipeline position 1
Supply values for the following parameters:
From: ABCD#boo.edu
Subject: test
To[0]: DCBA#foo.com
To[1]: jhgjjg#trtre.com
To[2]:???????
You have to at least include the SMTP server argument in the command because you won't get a prompt for it:
Send-MailMessage -SmtpServer "yoursmtpserver"
Once you've done that, enter your 'to' addresses as normal, and when you're done, press enter once more to escape from the final prompt and send the email.
Better yet, just enter the entire command with parameters included:
Send-MailMessage -From "ABCD#boo.edu" -To #("DCBA#foo.com", "jhgjjg#trtre.com") -Subject "test" -Body "Testing PS Email" -SmtpServer "yoursmtpserver"