send mail after successfull powershell script execution - windows

So I created the script below:
$target = "c:\$(get-date -F 'yyyy-MM')"
if (!(Test-Path $target)) {md $target}
gci 'c:\test\' -Filter *.xml -recurse | ?{!$_.PSIsContainer -and $_.CreationTime -ge (get-date "01.$((get-date).Month)")} | copy-item -Destination $target -Force
Could somebody point me to the right direction of how to send a email to a specific address after this script was successfully executed ?

As arco444 noted in his comment, send-mailmessage will allow you to send email from any machine running Powershell v2 or higher, as long as you have an accessible SMTP server.

you can try below solution in PowerShell
$EmailFrom = "someone1#company.com"
$EmailTo = "someone2#company.com"
$ccUsers="someone3#company.com"
$SMTPServer = "smtp.office365.com"
$port=587
$smtp = New-Object Net.Mail.SmtpClient($SMTPServer,$port)
$smtp.EnableSsl = "true"
$smtp.Credentials =New-Object System.Net.NetworkCredential($userName, $password);
$msg = New-Object Net.Mail.MailMessage
$msg.From = $EmailFrom
$msg.To.Add($EmailTo)
$msg.CC.Add($ccUsers)
$msg.IsBodyHTML = $true
$msg.Subject = "Test Subject";
#if you want to send some html in your email
$html = "<html><body><table width='100%'><tr bgcolor='#CCCCCC'><td height='25' align='center'> <font face='tahoma' color='#003399' size='4'><strong>Test Email from PowerShell</strong></font></td> </tr> </table></body></html>" $msg.Body = $html; $smtp.Send($msg);

If your using outlook, here is a example
[system.reflection.assembly]::loadwithpartialname("Microsoft.office.interop.outlook")
$OL=New-Object -ComObject OUTLOOK.APPLICATION
$ns =$OL.GETNAMESPACE("MAPI")
$mail =$ol.createitem(0)
$mail.recipients.add("something#live.nl")
$mail.CC=("something#ziggo.nl")
$MAIL.Subject= "$shortname"
#gets a signature
$mail.htmlbody= get-content $env:appdata\Microsoft\Signatures\*.txt
#for attachments..
$mail.Attachments.Add($file.FullName)
$lines=get-content $filename
$lines+=get-content $env:appdata\Microsoft\Signatures\*.txt
clear-variable text
foreach ($line in $lines)
{
$text += $line + "`r`n"
}
$mail.body= $text
$mail.display()

Related

How to check Time synchronization for domain controllers?

I am trying to write a PowerShell script to alert me if one of the domain controllers goes out of sync via an email, I tried to run the script, but I had a problem with sending the email, here is the code. Could you please help me and tell me what is missing in my code? I did not receive any email, so how can I send the script results to my email?
function Get-Time {
<#
.SYNOPSIS
Gets the time of a windows server
.DESCRIPTION
Uses WMI to get the time of a remote server
.PARAMETER ServerName
The Server to get the date and time from
.EXAMPLE
PS C:\> Get-Time localhost
.EXAMPLE
PS C:\> Get-Time server01.domain.local -Credential (Get-Credential)
#>
[CmdletBinding()]
Param(
[Parameter(Position=0, Mandatory=$true)]
[ValidateNotNullOrEmpty()]
[System.String]
$ServerName,
$Credential
)
try {
if ($Credential) {
$DT = Get-WmiObject -Class Win32_LocalTime -ComputerName $servername -Credential $Credential
} else {
$DT = Get-WmiObject -Class Win32_LocalTime -ComputerName $servername
}
} catch {
throw
}
$w32tm = Invoke-Command -Computer $Servers -ArgumentList $Servers -Scriptblock {
Param ($Servers)
foreach ($Server in $Servers) {
$Check = w32tm /monitor /computers:$Server /nowarn
$ICMP = (($Check | Select-String "ICMP")-Replace "ICMP: " , "").Trim()
$ICMPVal = [int]($ICMP -split "ms")[0]
$Source = w32tm /query /source
$Name = Hostname
switch ($ICMPVal) {
{$ICMPVal -le 0} {$Status = "Optimal time synchronisation"}
#you probably need another value here since you'll get no status if it is between 0 and 2m
{$ICMPVal -lt 100000} {$Status = "0-2 Minute time difference"}
{$ICMPVal -ge 100000} {$Status = "Warning, 2 minutes time difference"}
{$ICMPVal -ge 300000} {$Status = "Critical. Over 5 minutes time difference!"}
}
$String = $Name + " - $Status " + "- $ICMP " + " - Source: $Source"
Write-Output $String
}
}
$Servers = "localhost","DC001"
$Servers | Foreach {
Get-Time $_
$results = foreach ($Server in $Servers) {
Get-Time $Server
}
$Servers = "localhost","DC001"
$From = "abc#company.com"
$To = "abc#company.com"
$Cc = ""
$Subject = "Time Skew Results"
$Body = $Servers | ConvertTo-Html | Out-String
$SMTPServer = "imail.company.com"
Send-MailMessage -From $From -To $To -Subject $Subject -Body $Body -SmtpServer $SMTPServer -BodyAsHTML
}
}
I wrote the code again and it works now, here is the code:
$w32tm = Invoke-Command -Computer $Servers -ArgumentList $Servers -Scriptblock {
Param ($Servers)
Foreach ($Server in $Servers)
{
$Check = w32tm /monitor /computers:$Server /nowarn
$ICMP = (($Check | Select-String "ICMP")-Replace "ICMP: " , "").Trim()
$ICMPVal = [int]($ICMP -split "ms")[0]
$Source = w32tm /query /source
$Name = Hostname
Switch ($ICMPVal)
{
#{$ICMPVal -le 0} {$Status = "Optimal time synchronisation"}
#{$ICMPVal -lt 100000} {$Status = "0-2 Minute time difference"}
{$ICMPVal -ge 100000} {$Status = "Warning, 2 minutes time difference"}
{$ICMPVal -ge 300000} {$Status = "Critical. Over 5 minutes time difference!"}
}
if ($ICMPVal -gt 100000)
{
$String = "The Domain Controller: " + $Name + " has " + " - $Status " + " - $ICMP " + " - Source: $Source"
$From = "abc#company.com"
$To = "abc#company.com"
$Cc = ""
$Subject = "Time Synchronization Alert "
$Body = Write-Output $String
$SMTPServer = "imail.company.com"
Send-MailMessage -From $From -To $To -Subject $Subject -Body $Body -SmtpServer $SMTPServer -BodyAsHTML
}
}
}
$w32tm

Send-MailMessage : Cannot validate argument on parameter 'Subject'. [duplicate]

This question already has an answer here:
Send-MailMessage: Cannot validate argument on parameter 'Subject'
(1 answer)
Closed 5 years ago.
The emails will not send. Do i need some sort of a Try /Catch loop? What would be the best method of error checking this in Powershell?
I need it to check for each and if one location is not found that it still sends out the others and displays a message saying which Reports were sent and which were not depending on whether the report was found in the folder
Send-MailMessage : Cannot validate argument on parameter 'Subject'. The argument is null or empty. Provide an argument that is not null or empty,
and then try the command again.
#Defines Directory
$dir = "C:\Users\user\Desktop\reprts\Todays"
#Sets STMP server
$SMTPServer = "10.0.0.46"
#Declares todays time and formats
$Time = (Get-Date).ToString('MM/dd/yyyy hh:mm tt')
$japan = #{
Name = 'japan'
From = "me#me.com"
To = "you#you.com"
Cc = "him#him.com"
}
$ireland = #{
Name = 'ireland'
From = "me#me.com"
To = "you#you.com"
Cc = "her#her.com"
}
$spain = #{
Name = 'spain'
From = "me#me.com"
To = "you#you.com"
Cc = "her#her.com"
}
$_Regions = #()
$_Regions += New-Object PSObject -Property $japan
$_Regions += New-Object PSObject -Property $ireland
$_Regions += New-Object PSObject -Property $spain
ForEach ($_Region in $_Regions) {
#Searches dir for list , formats
$Attachment = Get-ChildItem -Path $dir -Filter "*$($_Region.name)*" -Recurse
$AttachmentName = $Attachment.BaseName
$Subject = "$AttachmentName"
$Body = "Please find attached the Missing Image Report for $($_Region.name).
Produced # $Time
Regards,
John Doe
"
#Actions Email
Send-MailMessage -From $_Region.From -To $_Region.To -CC $_Region.Cc -Subject $Subject -Body $Body -SmtpServer $SMTPServer -Attachments $Attachment.FullName
$Attachment | Move-Item -Destination "C:\Users\user\Desktop\reprts\old"
}
I added some error handling.
The region-objects will be returned, if it send successfully or not, but with a message, where/why it failed
#Defines Directory
$dir = "C:\Users\user\Desktop\reprts\Todays"
#Sets STMP server
$SMTPServer = "10.0.0.46"
#Declares todays time and formats
$Time = (Get-Date).ToString('MM/dd/yyyy hh:mm tt')
$_Regions = #(
#{
Name = 'japan'
From = "me#me.com"
To = "you#you.com"
Cc = "him#him.com"
},
#{
Name = 'ireland'
From = "me#me.com"
To = "you#you.com"
Cc = "her#her.com"
},
#{
Name = 'spain'
From = "me#me.com"
To = "you#you.com"
Cc = "her#her.com"
}
)
ForEach ($_Region in $_Regions) {
$null = $_Region.add('action','Starting work')
#Searches dir for list , formats
try {
$Attachment = Get-ChildItem -Path $dir -Filter "*$($_Region.name)*" -Recurse -ErrorAction Stop
$AttachmentName = $Attachment.BaseName
$Subject = "$AttachmentName"
$Body = "Please find attached the Missing Image Report for $($_Region.name).
Produced # $Time
Regards,
John Doe
"
#Actions Email
Send-MailMessage -From $_Region.From -To $_Region.To -CC $_Region.Cc -Subject $Subject -Body $Body -SmtpServer $SMTPServer -Attachments $Attachment.FullName -ErrorAction Stop
$Attachment | Move-Item -Destination "C:\Users\user\Desktop\reprts\old" -ErrorAction Stop
$_Region.action = 'success'
}
catch {
$_Region.action = $_ #catching the error
}
finally {
$_Region | Select-Object name, action
}
}

How can I optimize this Email list powershell script

How can I configure this script so that I can repeat this mailing process for multiple addresses eg Europe, Asia without copying the code multiple times?
For example could I do something like this?:
IF $keyword "Europe" found THEN
$europe
$europe = Does the Europe stuff
THEN
IF $keyword "Asia" found THEN
$asia
etc.
Here is my code:
# Email Automation
#Defines Directory
$dir = "C:\Users\user\Desktop\myfolder"
#Sets STMP server
$SMTPServer = "10.0.0.1"
#Declares todays time and formats
$Time = (Get-Date).ToString('MM/dd/yyyy hh:mm tt')
# Europe #
#Declares the keyword used to find List
$keywordEur = "Europe"
#Searches dir for list , formats
$AttachmentEur = Get-ChildItem -Path $dir -Filter "*$keywordEur*" -Recurse
$AttachmentNameEur = $AttachmentEur.BaseName
#Defines mailing list
$FromEur = "me#email.com"
$ToEur = "you#europeemail.com"
$CcEur = "him#email.com", "her#email.com"
$SubjectEur = "$AttachmentName # $Time"
$BodyEur = "Please find attached the file needed for Europe.
Regards,
Me
"
#Actions Email
Send-MailMessage -From $FromEur -To $ToEur -CC $CcEur -Subject $SubjectEur -Body $BodyEur -SmtpServer $SMTPServerEur -Attachments $AttachmentEur.FullName
# Asia #
#Declares the keyword used to find List
$keywordAs = "Asia"
#Searches dir for list , formats
$AttachmentAs = Get-ChildItem -Path $dir -Filter "*$keywordAs*" -Recurse
$AttachmentNameAs = $AttachmentAs.BaseName
#Defines mailing list
$FromAs = "me#email.com"
$ToAs = "you#asiaemail.com"
$CcAs = "him#email.com", "her#email.com"
$SubjectAs = "$AttachmentNameAs # $Time"
$BodyAs = "Please find attached the file needed for Asia.
Regards,
Me
"
#Actions Email
Send-MailMessage -From $FromAs -To $ToAs -CC $CcAs -Subject $SubjectAs -Body $BodyAs -SmtpServer $SMTPServerAs -Attachments $AttachmentAs.FullName
Here's how you could repeat it with a ForEach loop and an object built with two hashtables for the regions:
# Email Automation
#Defines Directory
$dir = "C:\Users\user\Desktop\myfolder"
#Sets STMP server
$SMTPServer = "10.0.0.1"
#Declares todays time and formats
$Time = (Get-Date).ToString('MM/dd/yyyy hh:mm tt')
$Europe = #{
Name = 'Asia'
From = "me#email.com"
To = "you#email.com"
Cc = "him#email.com", "her#email.com"
}
$Asia = #{
Name = 'Asia'
From = "me#email.com"
To = "you#email.com"
Cc = "him#email.com", "her#email.com"
}
$Regions = #()
$Regions += New-Object PSObject -Property $Asia
$Regions += New-Object PSObject -Property $Europe
ForEach ($Region in $Regions) {
#Searches dir for list , formats
$Attachment = Get-ChildItem -Path $dir -Filter "*$($Region.name)*" -Recurse
$AttachmentName = $Attachment.BaseName
$Subject = "$AttachmentName # $Time"
$Body = "Please find attached the file needed for $($Region.name).
Regards,
Me
"
#Actions Email
Send-MailMessage -From $Region.From -To $Region.To -CC $Region.Cc -Subject $Subject -Body $Body -SmtpServer $SMTPServer -Attachments $Attachment.FullName
}
Yes there is. Since the keywords themselves are the only thing that seems to change, put your keywords in an array and wrap the entire thing in a loop:
# Email Automation
#Define Directory
$dir = "C:\Users\user\Desktop\myfolder"
#Set STMP server
$SMTPServer = "10.0.0.1"
#Declare todays time and formats
$Time = (Get-Date).ToString('MM/dd/yyyy hh:mm tt')
#Define mailing list
$From = "me#email.com"
$To = "you#email.com"
$Cc = "him#email.com", "her#email.com"
#Declares the keywords used to find attachments
$keywords = 'Europe','Asia'
foreach($keyword in $keywords){
#Searches dir for list , formats
$Attachment = Get-ChildItem -Path $dir -Filter "*$keyword*" -Recurse
$AttachmentName = $Attachment.BaseName
$Subject = "$AttachmentName # $Time"
$Body = "Please find attached the file needed for $keyword.
Regards,
Me
"
#Actions Email
Send-MailMessage -From $From -To $To -CC $Cc -Subject $Subject -Body $Body -SmtpServer $SMTPServer -Attachments $Attachment.FullName
}

Send-MailMessage: Cannot validate argument on parameter 'Subject'

This error appears when running the script below:
Send-MailMessage : Cannot validate argument on parameter 'Subject'. The argument is null or empty. Provide an argument that is not null or empty, and then try the command again.
The email still sends successfully and the subject appears correctly.
$dir = "C:\Users\user\Desktop\Lists\TodaysLists"
$SMTPServer = "192.168.1.111"
$Time = (Get-Date).ToString('MM/dd/yyyy hh:mm tt')
$japan = #{
Name = 'Japan'
From = "me#me.com
To = "you#me.com"
Cc = "him#me.com"
}
$ireland = #{
Name = 'Ireland'
From = "me#me.com
To = "you#me.com"
Cc = "him#me.com"
}
$Regions = #()
$Regions += New-Object PSObject -Property $japan
$Regions += New-Object PSObject -Property $ireland
foreach ($Region in $Regions) {
$Attachment = Get-ChildItem -Path $dir -Filter "*$($Region.Name)*" -Recurse
$AttachmentName = $Attachment.BaseName
$Subject = "$AttachmentName"
$Body = "Please find attached the Report for $($Region.Name).
Produced # $Time
Regards,
John Doe
"
Send-MailMessage -From $Region.From -To $Region.To -CC $Region.Cc -Subject $Subject -Body $Body -SmtpServer $SMTPServer -Attachments $Attachment.FullName
$Attachment | Move-Item -Destination "C:\Users\user\Desktop\Lists\oldLists"
}
My guess would be that $Attachment = Get-ChildItem -Path $dir -Filter "*$($Region.Name)*" -Recurse is not returning any files for one or more of the regions, so $Subject ends up being $null.
You could either check for that state and perhaps throw a warning instead of attempting to send the mail, or another way to work around the error (and get an email sent but with a blank subject) would be to add some other (guaranteed) text to $subject. E.g:
$Subject = "$($Region.Name): $AttachmentName"
Although then I suspect it would complain about -Attachments being null.
To add a check/throw warning, you could do the following:
foreach ($Region in $Regions) {
$Attachment = Get-ChildItem -Path $dir -Filter "*$($Region.Name)*" -Recurse
If ($Attachment) {
$AttachmentName = $Attachment.BaseName
$Subject = "$AttachmentName"
$Body = "Please find attached the Report for $($Region.Name).
Produced # $Time
Regards,
John Doe
"
Send-MailMessage -From $Region.From -To $Region.To -CC $Region.Cc -Subject $Subject -Body $Body -SmtpServer $SMTPServer -Attachments $Attachment.FullName
$Attachment | Move-Item -Destination "C:\Users\user\Desktop\Lists\oldLists"
} Else {
Write-Warning "One or more files named $($Region.Name) were not found in $dir. Mail not sent."
}
}

Find the most recent file in a folder/dir and send that file in a email using shell script in windows cmd or powershell

I need to find the most recent file in a folder/dir and send that file as an attachment in a email, so far i have this code that find the most recent file in my windows SO, but i need to specify a route a find the most recent file there and then send that file in a email so far i have this:
EDIT 1:
So far i have this:
This part gives me the last file created in a dir/folder:
$dir = "D:\Users\myUser\Desktop\dirTest"
$latest = Get-ChildItem -Path $dir | Sort-Object LastAccessTime -Descending | Select-Object -First 1
$latest.Fullname
$attachment = $latest.Fullname
And this send the email (i'm using yahoo accounts):
$emailSmtpServer = "smtp.mail.yahoo.com"
$emailSmtpServerPort = "587"
$emailSmtpUser = "yahooAccountThatSendsTheEmail#yahoo.com"
$emailSmtpPass = "passForThisquestion"
$emailMessage = New-Object System.Net.Mail.MailMessage
$emailMessage.From = "yahooAccountThatSendsTheEmail#yahoo.com"
$emailMessage.To.Add( "yahooAccountThatRECIEVESTheEmail#yahoo.com" )
$emailMessage.Subject = "Testing e-mail"
$emailMessage.Body = "email from power shell"
$emailMessage.Attachments.Add( $attachment ) <---- this part gives me problems
$SMTPClient = New-Object Net.Mail.SmtpClient($emailSmtpServer, $emailSmtpServerPort)
$SMTPClient.EnableSsl = $true
$SMTPClient.Credentials = New-Object System.Net.NetworkCredential($emailSmtpUser, $emailSmtpPass);
$SMTPClient.Send($emailMessage)
It works now, this is my final script.
This script search the most recent file created in a Dir and it sends that file created to a email account.
Here is my script it works for me but it takes a few minutes to send the email, thanks for the help
This script do what i wanted, it find the most recent file and send tha file in a email.
$dir = "d:\Users\myUser\Desktop\testDir"
$latest = Get-ChildItem -Path $dir | Sort-Object LastAccessTime -Descending | Select-Object -First 1
$latest.Fullname
$attachment = $latest.Fullname
$emailSmtpServer = "smtp.mail.yahoo.com"
$emailSmtpServerPort = "587"
$emailSmtpUser = "test_sender_mail_account#yahoo.com"
$emailSmtpPass = "MyPassword"
$emailMessage = New-Object System.Net.Mail.MailMessage
$emailMessage.From = "test_sender_mail_account#yahoo.com"
$emailMessage.To.Add( "test_receiver_mail_account#gmail.com" )
$emailMessage.Subject = "My Subject"
$emailMessage.Body = "My body message"
$emailMessage.Attachments.Add($attachment)
$SMTPClient = New-Object Net.Mail.SmtpClient($emailSmtpServer, $emailSmtpServerPort)
$SMTPClient.EnableSsl = $true
$SMTPClient.Credentials = New-Object System.Net.NetworkCredential($emailSmtpUser, $emailSmtpPass);
$SMTPClient.Send($emailMessage)
With PowerShell, something like this should do alright:
function Send-RecentFile {
param(
[ValidateScript({Test-Path $_ })]
[String] $Path
)
$file = Get-ChildItem -Path $Path -File | Sort CreationTime | Select -Last 1
Write-Output "The most recently created file is $($file.Name)"
$messageParameters = #{
From = "myaccount#mydomain.com"
To = "destinationAccount#theirdomain.com"
Subject = "title"
Body = "message body"
SMTPServer = "mail.mydomain.com"
Attachments = $file.FullName
}
Send-MailMessage #messageParameters -Credential (Get-Credential "peopleo#anotherDomain.com")
}
If you do want to store the credentials in the file, you might have to do something slightly different with it.
Please check this powershell command.
$Body = “get the information here to show the data with attachement”
$dir = "Path\of\the\folder(C:\..\..)"
$latest = Get-ChildItem -Path $dir | Sort-Object LastAccessTime -Descending | Select-Object -First 1
$latest.Fullname
$file = $latest.Fullname
$EmailFrom = “sender#gmail.com”
$EmailTo = “receiver#gmail.com”
$SMTPServer = “smtp.gmail.com”
$EmailSubject = “Enter Your Subject”
$att = new-object Net.Mail.Attachment($file)
$mailmessage = New-Object system.net.mail.mailmessage
$mailmessage.from = ($EmailFrom)
$mailmessage.To.add($EmailTo)
$mailmessage.Subject = $EmailSubject
$mailmessage.Body = $Body
$mailmessage.IsBodyHTML = $true
$mailmessage.Attachments.Add($att)
$SMTPClient = New-Object Net.Mail.SmtpClient($SmtpServer, 587)
$SMTPClient.EnableSsl = $true
$SMTPClient.Credentials = New-Object System.Net.NetworkCredential(“sender_username”, “sender_password”);
$SMTPClient.Send($mailmessage)
$att.Dispose()

Resources