Define To: field from from various values - powershell

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

Related

Adding a variable to a -Body when sending an email

I'm creating a PowerShell script to make our starters and leavers process smoother. We have a separate team who needs to add certain accounts.
What I'd like to do is take the variable that is declared at the start of the script, the new users name, and put it in an email asking for this other department to set them up.
$username = "joe"
Send-MailMessage -SmtpServer smtp.office365.com -From "it#support.com" -To "other#department.com" -Subject 'Starter/Leaver ' -Body "Hi department, `n `nPlease can you add/remove" $username "from the necessary account please `n `nThanks"
I get an error saying:
Send-MailMessage : A positional parameter cannot be found that accepts argument "joe"
The issue here is that the string object sent to -Body is broken because of the quoting. You can just surround the entire body with one set of quotes to achieve the desired result.
$username = "joe"
Send-MailMessage -SmtpServer smtp.office365.com -From "it#support.com" -To "other#department.com" -Subject 'Starter/Leaver ' -Body "Hi department, `n`nPlease can you add/remove $username from the necessary account please `n`nThanks"
Neater Alternative:
I know this answer is not as concise, but it is more readable and adds some flexibility. It uses a here-string to create the body, which doesn't require having to add all of the line feed characters. It also uses splatting to execute the command. With splatting, you can just update the hash table when you need to change something.
$Body = #"
Hi department,
Please can you add/remove $username from the necessary account please
Thanks
"#
$Message = #{ SmtpServer = 'smtp.office365.com'
From = "it#support.com"
To = "other#department.com"
Subject = 'Starter/Leaver'
Body = $Body
}
Send-MailMessage #Message
When running a PowerShell command, parameters are space-delimited. In the case of Send-MailMessage positional parameters are also allowed, which means you don't have to provide the parameter name when passing in a value. In your attempt, your first quote pair was passed to the -Body parameter. After the first closing quote, a space followed by $username is interpreted. Because positional parameters are enabled for the command, PowerShell attempts to assign $username to a parameter and fails. Of course this also means that if you intend to include a space in your string, it must be surrounded by quotes.
Additional Reading:
See About Parameters for an overview of how parameters work.
See About Splatting for information on splatting.

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.

Who to email based on attachment file

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

Powershell Script Assistance

I have a script that will query domain controllers to get the expiry date for passwords which works great. I have an issue where I can't access a domain controller directly to run this same query as the only way I can access this domain is via a VPN and a Jumpbox.
What I would like to do is just create a simple script that could access a textfile. Inside this file I'd like to have just a number to represent days since last password reset. Each day this number would decrease. Once the number inside the file was below a certain point I could have an email sent out. I'm just not sure how I can do the process for having the file and decreasing the number each day inside the file. I'd also need to reset it once it reached zero of course.
Any assistance with this would be greatly appreciated.
Thank you in advance.
Steve
A text file will save values as string. So you would have to type cast it to integer before you can do operations.
$File = "C:\temp\ADpasspolicy.txt"
[int]$PassPolicyVal = Get-Content -Path $File
#check for threshold value
if (!($PassPolicyVal -gt 10))
{
#send mail
Send-MailMessage -Subject "Password expired" -To "jane.doe#gmail.com" -From "John#gmail.com" -SmtpServer "smtpserveraddress" -Body "add body here"
}
if ($PassPolicyVal -le 0)
{
$PassPolicyVal = 90
}
else
{
#Decrement by 1 if greater than 0
$PassPolicyVal--
}
$PassPolicyVal | Out-File -FilePath $File

Using pipeline object to populate mail -to and -attachment

First ever Powershell script so any advice or recommendations are appreciated. I'm parsing a .csv into smaller .csv's to send out information about servers to recipients and i'm running into a problem in my foreach. How do I get this to work?
One interesting thing is that in Send-MailMessage, -to should not accept pipeline objects, It still throws an error, but it still sends the emails. However the attachment will never send.
#had to set this as a variable because # was throwing splatting errors
$Mail = "#Email.com"
#Import csv and split information, exports UID.csv
Import-csv C:\path\info.csv | Group-Object UID |
ForEach-Object {
$_.Group | Export-csv "C:\path\$($_.Name).csv" -NoTypeInformation
}
#Import file again to get unique list of UID and send mail with
#respective UID.csv
Import-csv C:\path\info.csv | Group-Object UID |
ForEach-Object {
$_.UID | Send-MailMessage -From "<Me#email.com>" -To "<$($_.Name)$Mail>" `
-Attachments "C:\path\$($_.Name).csv" `
-Subject "Testing" -Body "Please Ignore This" -Priority High `
-SmtpServer smtp.server.com
}
in Send-MailMessage, -to should not accept pipeline objects
In principle it does, namely if the pipeline objects have a .To property (which is not the case for you).
However, with your current approach, you don't need pipeline input at all, given that you're supplying all input as arguments.
Additionally, your pipeline input is incorrect, because $_.UID sends $null through the pipeline, given that $_ - a group-info object output by Group-Object - doesn't have a .UID property.
Using delay-bind script blocks ({ ... }), you can simplify your command as follows, obviating the need for a ForEach-Object call:
Import-csv C:\path\info.csv | Group-Object UID |
Send-MailMessage -From "<Me#email.com>" -To { "<$($_.Name)#Email.com>" } `
-Attachments { "C:\path\$($_.Name).csv" } `
-Subject "Testing" -Body "Please Ignore This" -Priority High `
-SmtpServer smtp.server.com
In short, the script blocks passed to -To and Attachments are evaluated for each input object, and their output determines the parameter value in each iteration. In the script block, $_ represents the pipeline object at hand, as usual.
Note that such delay-bind script blocks can only be used with parameters that are designed to accept pipeline input (irrespective of whether by value (whole object) or by a specific property's value).