Who to email based on attachment file - powershell

Without using a ton of ElseIf statements is it possible to select the the recipient of an email based on the file that will be attached to the email while iterating over all files in a folder?
I have started building this without the foreach get-ChildItem running over the folder where I create the email object, assign specific recipients, and choose a specific file out of the folder, but this is quite tedious and repetitive. I feel like there has to be a way to use an array of arrays or something where based on the file that the loop is on it pulls through the recipients and maybe a custom subject line.
There's tons of powershell email code out there so I won't repost that. Just not sure how to even attack this.

One option would be to have an accompanying CSV file, with rows for the filename, the recipient and the subject name etc. You could then import the CSV file using Import-Csv.
For example:
$emailList = Import-csv c:\users.csv
foreach ($line in $emailList) {
Write-Host "Sending message to $($line.emailAddress)"
Send-MailMessage -To $line.emailAddress `
-Subject $line.subject `
-Attachments $line.attachmentPath `
-Body $line.bodyText
}
and if you wanted to define the contents of the CSV in the PowerShell script, rather than using an external file, you could do something like:
$emailList = "emailAddress,subject,attachmentPath,bodyText
joe#bloggs.com,Attachment for Joe,c:\attachmentsToSend\joe.pdf,Attached is your file
Mary#bloggs.com,Mary's attachment,c:\attachmentsToSend\mary.pdf,Hello, Mary. Attached is your file
" | ConvertFrom-Csv
Put that above the foreach loop in the script

Related

Windows Powershell - trouble importing CSV and iterating

I'm new to Powershell (of course), and having troubles with a seemingly simple process. I have found a couple of examples that I think I am following, but they aren't working for me.
What I am trying to do: add a bunch of users to the local Windows OS, by reading from a CSV file (has names, usernames, passwords, etc).
My understanding is that the 'Import-CSV' cmdlet is supposed to return an object-like thing you can iterate over:
"The result of an Import-Csv command is a collection of strings that
form a table-like custom object."
When I perform that step, saving it to a variable, it seems that there is only ever 1 row present. And if I don't provide the "-Header" parameter, I get errors about a 'member is already present'... even if I include the header in the CSV file (my original file did not include a header row in the CSV file.)
I have tried various methods trying to get a Count of the imported CSV results, just trying to see what the data is, but I'm not having any luck. (MS Docs say you can use the Count property.)
MS Docs (https://learn.microsoft.com/en-us/powershell/module/microsoft.powershell.utility/import-csv?view=powershell-7.2) say this about "Import-CSV":
Outputs
Object
This cmdlet returns the objects described by the content in the CSV
file.
...
Notes
Because the imported objects are CSV versions of the object type...
The result of an Import-Csv command is a collection of strings that
form a table-like custom object. Each row is a separate string, so you
can use the Count property of the object to count the table rows. The
columns are the properties of the object and items in the rows are the
property values.
An example of my input CSV file:
"ISA","LOG","Consulting & Other","Vendor","Isalog","alsdkjfalsdjflasdkfjalsdkfjlaksdjflkasdfj"
"Bry","Link","Bry Link","Vendor","Bry","asdkfjalsdjflaksdjflasdkjflaksdfj"
"Michael","Had","Premier Service Of Western","Vendor","Michael","alsdkfjalskdjflaksdjflaksdfjalksdfj"
Code of one example that I am testing:
param ($InputFile)
Write-Host "Provided input file: $InputFile"
$CSV = Import-CSV -Path $InputFile -Header 'FirstName', 'LastName', 'FirmName', 'Type', 'Username', 'Password'
foreach($LINE in $CSV)
{
$NewUser="$($LINE.USERNAME)"
$NewPass="$($LINE.PASSWORD)"
$SecurePass=ConvertTo-SecureString –AsPlainText -Force -String "$NewPass"
Write-Host "User = $NewUser"
#New-LocalUser -Name $NewUser -Password $SecurePass
}
And a screenshot of my script plus the run results:
Running on: Windows server 2019 datacenter.
Powershell version: 5.1
The ultimate answer was that the character encoding for the CSV file I was using as input was causing problems for Powershell. Specifically, the line-ending encoding.
My original file was created on a Mac. The line-ending enconding was 'Macintosh (CR)'. The files that worked OK were created on this Windows machine, and used the line-ending encoding = "Windows (CR LF)".
Thanks to Olaf who got me thinking about this issue and made me investigate that area further.

Loop through Search-mailbox

I have a requirement to search mailboxes for an email based on subject line and report if the email is in the Inbox or another folder. The below code works well for individual users.
Search-Mailbox -Identity "test#example.com" -SearchQuery ‘Subject:”Suspect email alert”‘ -TargetMailbox “admin” -TargetFolder “inbox”-LogOnly -LogLevel Full
The report received states if the email is in that particular mailbox and the location. This is great for one user, though I need to do this for over 500 users.
I have a csv file with a list of email addresses I need to check for this particular email and it's location. So I have imported the csv file to a variable. Then put the command in a foreach loop, though cannot get this working correctly.
Correction: updated to txt file a used get-content
$users = Get-Content -Path userslist.txt
foreach ($user in $users) {
Search-Mailbox $user -SearchQuery ‘Subject:”Suspect email alert”‘ -TargetMailbox “admin” -TargetFolder “inbox”-LogOnly -LogLevel Full }
How do I run through the list of users, so I can get one report rather than a report for each user individually. Any ideas would be great.
Issue was with the csv file formatting. imported text file and loop running fine. Would be good to get the results into one Search results file, rather than one for each loop.

Send emails with Powershell mailto with formated text

My current script creates (after an account modification) a .ps1 file that is send to another computer and there it is executed opening a new Gmail tab with some information hosted in several variables. I need this email to have format like bold, hyper-link, etc.
Im using the start-process 'mailto' for this but i can not find the way to give this email a format (believe me, i have tried), is this even possible?
I appreciate any insights on this.
My current script creates (after an account modification) a .ps1 file that is send to another computer and there it is executed opening a new Gmail tab with some information hosted in several variables. I need this email to have format like bold, hyper-link, etc.
Im using the start-process 'mailto' for this but i can not find the way to give this email a format (believe me, i have tried), is this even possible?
Additional information:
Code:
$outPut = 'Start-Process'
$outPut+= '"mailto:'+$userMail+"?Subject=Password Reset"+"&Body=Hi, your password is $Password"
$outPut+= '";'
$mailFile = "Path" + $user.SAM + ".ps1"
$outPut | Out-File $mailFile
So, this takes the information this way and stored it in a ps1 file, then executed, opening a new Gmail tab with proper data.
I need that some words has format, bold for the password or hyper-link for guideness link...
Regards!
You haven't provided any indication of what you are doing. But the way to send emails via PowerShell is with the Send-MailMessage cmdlet. If you are using Send-MailMessage and formatting the body of the message with HTML, you just need to make sure you are using the -BodyAsHtml argument.
Here's an example:
$html = "<body><h1>Heading</h1><p>paragraph.</p></body>"
Send-MailMessage -To "bob#fake.com" -From "me#fake.com" -Subject "Test" -Body $html -BodyAsHtml

Empty .csv with headers shows count as '1'. When .csv has one entry, count still shows as '1'

We have a .csv file with headers that is auto-populated daily with mobile devices enrolled into our MDM, yet are not entered into our device database.
I have script to parse the .csv, tag the devices in the console, and send out an email to the support team to investigate. The script performs a count of the rows, but runs into a problem when there is no data, meaning the rows are empty except for the headers. I'm guessing this is because the script has no data to perform actions against, yet when this happens, the count still shows as '1'.
When there is only one row populated with data, the count still shows as '1', however, always shows correct counts when more data (rows) is populated.
I'm guessing my best solution would be to simply code in a 'script kill switch', meaning if there is no data in the spreadsheet, the script should stop.
I also wanted to only send an email to support if there is data in the .csv file.
Any suggestions would be helpful.
I've tried many methods to count the rows, but when the spreadsheet is empty it still counts the header. The header is not counted when there are rows populated.
# Path to file
$NoICK = Import-Csv \\server\folder\TrueUp.csv
#Device Counts
$devicecount = ($NoICK | Measure-Object).Count
# Creates a copy file and tags all devices (function not show here)
Foreach ($item in $NoICK){
$noICK | Export-Csv -Path $path -NoTypeInformation
tag_NoICKregistration $item.device_id
}
# Only send email to support if there are devices
If ($devicecount -gt '0'){
Send-MailMessage -From $smtpFrom -To $smtpTo -Subject $messageSubject -Body $body -SmtpServer $smtpServer
}
If the true count is zero, meaning no data was entered into the .csv file, I would like the script to stop after creating the copy, and to not send the email.

Define To: field from from various values

In a CSV file I have various columns and two of those are for emails. Each row within these email columns have a group of emails.
I want to be able to send to these email addresses from a script.
I have everything setup and working, except for the TO:.
The idea of the script is that it loops each line of the csv and generates an email grabbing values from the cells of that row into various parts of the body. Then it sends of an email and loops back to the next line of the CSV to do the same, and so on until it reaches the end of the CSV file.
I'm having issues to plug a variable for the email columns, I'm guessing because the emails don't have "quotations".
How do I bring these in?
In a nutshell for the code
data is imported CSV
a loop is created foreach line of imported data
smtp, from, to, subject, attachments, body variables are defined
then the sendmail-message command is provided.
close the loop
##For the purpose of this, the emaildata.csv looks like this sample:
"NameGroup","emailGroupA","emailGroupB"
"Groupabc","a.b#b.com;c.a#b.com","xyv#b.com;xxd#b,com"
"Grouptrd","ca.r#b.com;as.b#b.com","aaa#a.com;bbb#b.com"
"Groupghd","dd.r#b.com;dd.b#b.com","dddaa#a.com;ddddddb#b.com"
$DataDir = "C:\Users\acastrellon\Documents"
$Data= import-csv $DataDir\emaildata.csv
foreach ($i in $Data) {
$NameGroup = $i.NameGroup
$TeamA = $i.emailGroupA.replace(';',"`n")
$TeamB = $i.emailGroupB.replace(';',"`n")
function send-email {
$smtpserver = " server.smtp"
$from = "myemail.com"
$to = $TeamA,$TeamB
send-MailMessage -From $from -To $to -Subject $subject -Body $body -SmtpServer $smtpServer
}
[string] $subject = "some text here: $NameGroup"
#[string] $attachment = "not here yet"
[string] $body = "
Text here that calls out $NameGroup
This also lists: $TeamA
This here lists $TeamB
Done"
send-email -subject $subject -attachment $attachment -body $body
}
#this should loop to get data from next line of csv and generate a new email with data.
Unlike a batch file where environment variables have a global impact to the current session, PowerShell isolates variables in different scopes.
You're referencing the two $TeamA & $TeamB variables inside a function but you set their values outside the function. Because the function scope (where they are read) is different to the script scope (where you set them) those variables will be empty inside the send-email function in your script.
Have a read on PowerShell scopes as you'll need to make some changes to your script functions; to either read the variables from the script scope ($script:TeamA) or to pass them into the function as a parameter