Sending output via Email from Powershell - powershell

See attached photo (link) of Output in PowerShell and Outlook.
I am trying to send output via email but having troubles getting the script to put the output in the body of the email. Instead of grabbing the Services Names and Expiration Dates that fall in-between the desired threshold (70 days), it is grabbing everything in the CSV (ex. see a Service that expires in 2022) and putting that into the body of the email.
My question is how do I have it email just the information that I pulled in PowerShell (the ones that fall between the specified threshold date)?
Somewhat newer to scripting, thanks! :)
$now=get-date
$cert = Import-Csv C:\Users\userID\Desktop\Certificate_CSV2.csv
$threshold = 70
$deadline = (Get-Date).AddDays($threshold)
$cert | Select-Object "Service Name", "Certificate Expiration Date" | Where-Object {$_."Certificate Expiration Date" -as [datetime] -le $deadline}
Send-mailMessage -to "SentTo#email.com" -subject "test message 8" -from "SentTo#email.com" -body ($cert | Out-String) -SmtpServer pobox.email.com

You're just printing out cert with the filter, not applying it back to cert. To fix, just set $cert equal to the filtered version of itself.
$cert = $cert | Select-Object "Service Name", "Certificate Expiration Date" | Where-Object {$_."Certificate Expiration Date" -as [datetime] -le $deadline}

Related

Best way to import a csv file of users and managers, then email the manager with a list of their users

forgive me for breaking any rules. I'm a brand new StackOverflow user, and a powershell noob. I'm working on a work project where I import a CSV file that contains a list of users and their respective managers. I then need to create an email that contains a table with the users for each respective manager.
I know how to import the csv file. I've gotten a basic email sending code created. I'm completely lost as to how to appropriately get the users and managers associated with each other.
For example, my csv is formatted with headers like this:
First Name Last Name Username Manager
Bob Dole BDole Jsmith
John Doe JDoe Anoob
Jane Doe JDoe1 Jsmith
etc.
Could someone please point me in the right direction? I've tried using a hashtable and an array, with no success. This is likely due to my noob status.
Please let me know if there is more information I should add. I don't have any real code written at this point since nothing has worked, so please pardon the very limited code in the post.
$users = import-csv "Path goes here"
"My code for associating the users and managers would go here"
"Email code goes here"
$users = Import-Csv .\test.csv -Delimiter ";"
$cred = Get-Credential # enter the credentials for your email account
from where you will send the mail
$users | Group-Object -Property Manager | % {
$managername = $_.name
write-host $managername
$body = $_.group | format-table | ConvertTo-Html
write-host $body
Send-MailMessage -to "$managername#some.com" -Body $body -From "yourmail" -SmtpServer "yoursmtpserver" -Port "your smtp port" -Subject "mailsubject" -Credential $cred -BodyAsHtml
}
If you dont want to enter your mail credentials every time you can save them as following.
get-credential | export-clixml -path "somepath"
later on you can read the credentials from you os:
$cred = import-clixml -path "somepath"
I am not exactly sure I understand what kind of output you want, but here is a suggestion. If you have a csv file named workers.csv, this should sort entries by the manager name:
contents of workers.csv:
first last username manager
john, doe, jdoe, boss1
jan, doe, jjdoe, boss2
jim, ddi, jddi, boss2
didi, goo, didigoo, boss1
at the Powershell prompt, type:
$managers = "boss1","boss2"
(then type enter )
then type:
foreach ($item in $managers) {
cat ./workers.csv | Select-String -Pattern "$item"
| out-file -append workers.csv
}

Unable to send attachment using Send-MailMessage

Unable to send attachments using the Send-MailMessage cmdlet. The email sends with the subject and body, but no attachment.
Get-ADComputer -Filter {operatingsystem -like '*server*'} |
where {
$_.distinguishedname -notlike '*production*' -and
$_.distinguishedname -notlike '*tbd*' -and
$_.distinguishedname -notlike '*disabled*' -and
$_.distinguishedname -notlike '*domain controll*'
} |
Select Name, Distinguishedname |
Export-Csv -Path C:\Users\User1\wrongOU.csv |
Send-MailMessage -From 'from.email#gmail.com' -To 'to.email#gmail.com' -Subject 'This is a test email.' -SmtpServer smtp.test.com -Attachments "C:\Users\User1\File.txt" -Body 'This is a test email.'
The only parameter that accepts pipeline by value input is Attachments. If you perform a parameterbinding trace, you can see C:\Users\User1\File.txt bind to Attachments. Then the pipeline input is evaluated and a bind attempt is made. The attempt fails because there are no unbound parameters available to accept the value. When you bind that parameter in your command while piping an object into Send-MailMessage, PowerShell effectively removes the previously bound value (C:\Users\User1\File.txt) from binding to the Attachments parameter.
For successful command execution, you can do either of the following:
# For emailing File.txt
Send-MailMessage -From 'from.email#gmail.com' -To 'to.email#gmail.com' -Subject 'This is a test email.' -SmtpServer smtp.test.com -Attachments "C:\Users\User1\File.txt" -Body 'This is a test email.'
# For emailing wrongOU.csv
"C:\Users\User1\wrongOU.csv" | Send-MailMessage -From 'from.email#gmail.com' -To 'to.email#gmail.com' -Subject 'This is a test email.' -SmtpServer smtp.test.com -Body 'This is a test email.'
In short, the symptom is due to the parameter binding conflict that you have created. If you chose to leave off the -Attachments parameter with all else remaining the same, you would then have encountered issues because you are not piping a file path into the Send-MailMessage.
This exception and binding behavior appears to be typical for many built-in commands. A custom function does not exhibit these symptoms unless additional parameter validation is added. I would like to have more evidence as to what strips off the parameter value, but that remains to be seen.

Powershell Scripting regarding decrementing dates by one

Here is my script so far. My intention is to take the event log from the previous day and send it an email to myself every morning. This is my script so far.
(Get-EventLog -LogName Application -After "10/26/16" | ConvertTo-Html | set-content 'C:\Users\myusername\Documents\Powershell Outputs\1day event log.html')
$date= get-date
if ($date=get-date).AddDays(-1)
Else {"File Not Found"}`
Send-MailMessage -To "my email" -From "my email" -subject "Eventlog for Yesterday" -body "This is a daily sent automated email for the event log of the previous day." -Attachments "`
Now what am I doing wrong, Im brand new to powershell so go easy.
So the first thing you are going to want to do is get Yesterday in a DateTime, which is what I assume you were trying to do with $date and if ($date = (get-date).AddDays(-1))
Then let's put you log location in a variable, so that we can use it both in saving the log and then sending the attachment
The -After parameter uses the DateTime that we saved in $Yesterday. The path for Set-Content is then $logPath
#Get DateTime for Yesterday
$Yesterday = (Get-Date).AddDays(-1)
#Set the location of the log attachment
$logPath = 'C:\Users\myusername\Documents\Powershell Outputs\1day event log.html'
#Get the Event Log After Yesterday, Convert it to HTML, Save it to the logPath
Get-EventLog -LogName Application -After $Yesterday | ConvertTo-Html | Set-Content $logPath
#Send Mail Message with the logPath as an attachment
Send-MailMessage -To "my email" -From "my email" -subject "Eventlog for Yesterday" -body "This is a daily sent automated email for the event log of the previous day." -Attachments $logpath

Looking for advice on how to proceed with working powershell script

So I posted for and got some help with this script:
#Command to get list of folders with logfiles where the logfile is at least 30 minutes old send results to variable.
$varlogfile = Get-ChildItem -Path "drive:\folder" -Recurse -Include "logfile" | Where-Object {$_.LastWriteTime -le ((Get-Date).AddMinutes(-30))}
#Add a carriage return to results contained in the variable so email is easier to read
$varlogfile = $varlogfile -join "`r`n"
#Email setup from this line down to next comment
$SMTPServer = "email.server"
$From = "Administrator <administrator#place.com>"
$To = "email","email2"
$Subject = "A Logfile older than 30 minutes has been detected"
$Body = "Logfile(s) older than 30 minutes have been detected in the following folder(s):
$varlogfile
Please login and attempt to process the files manually, if the manual process fails, open a ticket with someone.
From the Admin
"
#Email setup above this line
#If statement that looks for the text blah in the variable, if found email is sent.
if($varlogfile -match "blah")
{
#Command to send email
Send-MailMessage -From $From -to $To -Subject $Subject -Body $Body -SmtpServer $SMTPServer
}
exit 0;
And all that is working perfectly.
Here's the thing though. Over the weekend sometimes we may get a stuck logfile that can't be resolved until Monday morning and it would be nice to be able to turn off alerts when this happens.
Now I'm very new to powershell and this script has been my learning experience. The way I see it is I have 3 choices:
Keep the get-childitem from returning a result if it sees logfile and logfile.stop.
After get-childitem has produced $varlogfile, search $varlogfile for logfile.stop and delete the lines logfile and logfile.stop from it.
Rewrite the whole thing from scratch and produce $varlogfile in a better way that makes it easier to work with the results.
Thoughts and opinions? I'm leaning toward method 2, as I think I can figure that out, but I'm curious if that is a way of pain. I'd really like your input on this.
Thanks people!
I think you're on the right path with your current plan, so I'll help you with approach #2, creating a .sent file when we send an email, to keep the emails from sending multiple times.
Our first step: When an e-mail is sent , we create a new file titles $logfile.MessageSent or something like that. Doing this allows an e-mail to be sent, and for us to also create a flag that we can search for later in the filesystem to determine whether or not we send another e-mail.
#If statement that looks for the text blah in the variable, if found email is sent.
if($varlogfile -match "blah")
{
#Command to send email
Send-MailMessage -From $From -to $To -Subject $Subject -Body $Body -SmtpServer $SMTPServer
New-Item -path $varLogfile.Sent -itemType File
}
Our second step: Modify our Get-ChildItem query to search for the flag:
$varlogfile = Get-ChildItem -Path "drive:\folder" -Recurse -Include "logfile" |
Where-Object {$_.LastWriteTime -le ((Get-Date).AddMinutes(-30))} |
? "($_.BaseName).sent" -notin (Get-ChildItem -Recurse -Include "*.sent" -Path "drive:\folder" | Where-Object {$_.LastWriteTime -le ((Get-Date).AddMinutes(-30))})
This second modification to the $varlogfile step is hard to understand, admittedly. Here is how I've changed it:
Get a lit of files in the drive\folder path, recursively and include logfile
Where the LastWriteTime is older than 30 mins
Where filename.sent is not found in the same directory
The only other thing you'll need to do is add a cleanup task to regularly delete the .sent files, and you're good to go.
Please let me know if you have any questions about this approach, as I want to be sure you understand and to help you learn.

PowerShell send email to list of addresses within another script

I am trying to create a PowerShell script that will send an email to a list of people, but the email call is already embedded within a ping script. This is for a system that only has PowerShell v2.0.
Computers.txt contains a list of computers to be pinged and on failure will send an email.
This is my existing script I am trying to modify:
Get-Content -path "E:\Computers.txt" | ForEach-Object {
if (-not (Test-Connection -ComputerName $_ -Delay 2 -Quiet)) {
Send-MailMessage -To "email address" -Subject "$_ is Unreachable" -Body "$_ is unreachable by ping. Next check is in 5 minutes" -SmtpServer "server address" -From "another email address"
}
}
I know that I can use the Get-Content -path "E:\From_Email.txt" and Get-Content -path "E:\To_Email.txt" to call the list of email addresses, but I am not sure how to do this within the existing command. I have looked online, but I have not found how to nest calling additional text files within PowerShell for a script.
Do I need to call these files earlier and set them equal to a variable which gets called? Any help would be greatly appreciated. Thank you.
Assuming you have an email address on each line of "E:\To_Email.txt", the code below should work
$emails = (Get-Content "E:\To_Email.txt") -join ";"
Get-Content -path "E:\Computers.txt" | ForEach-Object {
if (-not (Test-Connection -ComputerName $_ -Delay 2 -Quiet)) {
Send-MailMessage -To $emails -Subject "$_ is Unreachable" -Body "$_ is unreachable by ping. Next check is in 5 minutes" -SmtpServer "server address" -From "another email address"
}
}
The extra first line reads in all lines of the email list file as an array, then joins it with semi-colons, which I think is how your email addresses should be separated. Worth checking though.
Example content of "E:\To_Email.txt"
person.one#yourdomain.whatever
person.two#yourdomain.whatever
person.three#yourdomain.whatever
person.four#yourdomain.whatever