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

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."
}
}

Related

Powershell, send email for each user that has been disabled to their managers

So after a-lot of help, there is a script that will search users that were disabled for the past 14 days + show their managers name + email and date when they were disabled:
$ou = "my-ou"
$date = (Get-Date).AddDays(-14)
$todaydate = Get-Date -DisplayHint Date
$disabledAccounts = Get-aduser -filter {Enabled -eq $false -and Modified -ge $date } -SearchBase $ou -Properties Modified,manager | select samaccountname,Modified,manager
#$ManagerName = ''
$Body = ”
<html>
<body>
<p>Dear $ManagerName,<br>
The user $userName has been disabled on $todaydate .<br
</body>
</html>”
ForEach($disabledAccount in $disabledAccounts){
$manager = get-aduser -property emailaddress,DisplayName $disabledAccount.manager
$ManagerName= $manager.Displayname
$userName = $disabledAccount.samaccountname
Send-MailMessage -To $manager.UserPrincipalName -From ‘test#email.com’ -Subject ‘Disabled account’ -Body $Body -SmtpServer ‘mysmtp’ -BodyAsHtml -Priority High
}
The problem for now that this script only sent email for 1 user when in my test i have 2 disabled users in this period of time.
And the first command with "Get-Aduser" i see both of the users, and in the second one "Get-aduser" i see only 1.
$ou = "my ou direction"
$date = (Get-Date).AddDays(-14)
$diabledAccounts = Get-ADUser -Filter {Enabled -eq $false -and Modified -ge $date } -SearchBase $ou -Properties Modified,manager | select samaccountname,Modified,#{n='Manager';e={(Get-ADUser $.manager).name}},#{n='ManagerEmail';e={(Get-ADUser $.manager -properties mail).mail}}
ForEach($diabledAccount in $diabledAccounts){
Send-MailMessage -To $diabledAccount.ManagerEmail -Subject 'Disabled account' -Body "Account $diabledAccount.samaccountname has been disabled in the last 14 days" -SmtpServer ''
}
I answered something like this on Spice works
$ou = “my_ou”
$date = (Get-Date).AddDays(-14)
$disabledAccounts = Get-aduser -filter {Enabled -eq $false -and Modified -ge $date } -SearchBase $ou -Properties Modified,manager | select samaccountname,Modified,manager
$ManagerName = ''
$Body = ”
<html>
<body>
<p>Dear $ManagerName,<br>
The user $userName has been disabled on .<br
</body>
</html>”
ForEach($disabledAccount in $disabledAccounts){
$manager = get-aduser -property emailaddress,DisplayName $disabledAccount.manager
$ManagerName= $manager.Displayname
$userName = $disabledAccount.samaccountname
Send-MailMessage -To $manager.ManagerEmail -From ‘myemail#’ -Subject ‘Disabled account’ -Body $Body -SmtpServer ‘mysmtp server’ -BodyAsHtml -Priority High
}

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
}
}

Delete email attachment after sending powershell

I have wrote a script for automated email using powershell.
The email sends however how can i configure it so that the file that is attached is moved to another folder inside the folder it was originally located?
#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
Move-Item Get-ChildItem -Path $dir -Filter "*$($Region.name)*" -Recurse "C:\Users\users\Desktop\MissingImageLists\OldLists"
}
Remove your Move-Item command and replace it with:
$Attachment | Move-Item -Destination "$dir\subfolder"

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 mail after successfull powershell script execution

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()

Resources