Gotcha. Well, first of all it’s important to understand that everything in Windows PowerShell is object based, even an array or a string (My apologies if I’m already stating stuff you know.). Think of a person. A person (i.e. the object) has attributes (eye color, number of hands, number fingers on each hand, etc…). When you add other people you get an object (i.e. a group of people) that contains objects (i.e. individual people).
Ok, so now for a specific example of why this is working the way it does. Let’s start off with the example files I mentioned. I’ll be using the code, including variable names, as I wrote them.
--UserData.txt (Imported into $UserData):
When this file is imported. Each line is an object. The variable $UserData contains the group of objects.
UserName,Department,Title,Location
user1,DeptA,JobA,Dallas
user2,DeptA,JobB,Houston
user3,DeptB,JobA,Garland
user4,DeptB,JobB,Richardson
user5,DeptA,JobA,Frisco
Importing data from UserData.txt and dumping out to the screen.
PS C:\> $UserData = Import-Csv -Path C:\Data\UserData.txt
PS C:\> $UserData
UserName Department Title Location
-------- ---------- ----- --------
user1 DeptA JobA Dallas
user2 DeptA JobB Houston
user3 DeptB JobA Garland
user4 DeptB JobB Richardson
user5 DeptA JobA Frisco
user6 DeptA JobA Dallas
user7 DeptB JobB Houston
user8 DeptB JobA Garland
--TeamsData.txt (Imported into $TeamsData):
When this file is imported. Each line is an object, as with the previous set of data. The variable $TeamsData contains the group of objects.
Team,Recipient,Department,Title
TeamA,"tuser1@domain.com",DeptA,JobA
TeamB,"tuser1@domain.com,tuser2@domain.com",DeptA,JobB
TeamC,"tuser3@domain.com",DeptB,JobA
TeamD,"tuser3@domain.com,tuser4@domain.com",DeptB,JobB
user6,DeptA,JobA,Dallas
user7,DeptB,JobB,Houston
user8,DeptB,JobA,Garland
Importing information into $TeamsData & dumping it out on the screen.
PS C:\> $TeamsData = Import-Csv -Path C:\Data\TeamsData.txt
PS C:\> $TeamsData
Team Recipient Department Title
---- --------- ---------- -----
TeamA tuser1@domain.com DeptA JobA
TeamB tuser1@domain.com,tuser2@domain.com DeptA JobB
TeamC tuser3@domain.com DeptB JobA
TeamD tuser3@domain.com,tuser4@domain.com DeptB JobB
I’ll use TeamA to detail how this works. We’re doing exactly the same thing for all of the other teams as well.
The data for each file has been imported and now we’re starting the ForEach look for the $TeamsData objects. ForEach is a looping construct that basically says "For each object in this group of objects (can be only one object in the group…or none) do ". So, for one object at a time in the group of objects we do whatever is inside the brackets({}) of the ForEach block. In this case, the first object in the $TeamsData object we process is the one for TeamA, which gets stored in the $Team variable (Each object through the loop gets stored in the $Team variable, one at a time.). I know this because I can index into the group of objects as below, starting with the index of 0 (i.e. the first object).
PS C:\Users\miracles1315\OneDrive\Powershell\Scripts> $TeamsData[0]
Team Recipient Department Title
---- --------- ---------- -----
TeamA tuser1domain.com DeptA JobA
So, in the first iteration of the TeamsData ForEach loop we have the above information in the $Team variable. Now, the first thing we do in the TeamsData ForEach loop is the below, which is where we do our filtering. $UserData is all of the data I showed earlier. In this part of the code, we’re taking the entire contents of the $UserData variable and saying that we only want a subset of the data. In the case of TeamA, we’re saying that from $UserData only return the user objects where the Department = DeptA* (w/ * being a wildcard) & where Title = JobA.
$TeamResults = $UserData | Where{($_.Department -like "$($Team.Department)*") -and ($_.Title -match "$($Team.Title)")}
So, let’s see what that looks like. Remember that right now $Team = $TeamsData[0] = object for TeamA. So, When I manually pull this data out, rather than doing the ForEach loop by running the full code, I’m replacing $Team with $TeamsData[0] to see what I’d get in this iteration of the loop.
PS C:\> $TeamResults = $UserData | Where{($_.Department -like "$($TeamsData[0].Department)*") -and ($_.Title -match "$($TeamsData[0].Title)")}
PS C:\> $TeamResults
UserName Department Title Location
-------- ---------- ----- --------
user1 DeptA JobA Dallas
user5 DeptA JobA Frisco
user6 DeptA JobA Dallas
If I look back at the contents of the $UserData.txt, these are the 3 users with the criteria for TeamA. So far, so gook. Ok, time to move on.
Next, we run into the "If($TeamResults) block. If there were no users who happened to fit the criteria for TeamA, then this would evaluate to $False and the block of code in it would not execute. However, in this case, we have 3 users who fit the criteria for the team (TeamA, in this case). So, the code will execute.
The next thing we do, since $TeamResults has 3 objects in it, is the TeamResults ForEach loop. As with TeamsData ForEach loop, we take one object at a time and do whatever is inside the brackets({}). So, let’s take this loop one object at a time. Similar to me substituting $TeamsData[0] for $Team, I’ll be substituting $TeamResults[0] for $Result, then $TeamResults[1] for $Result, and finally $TeamResults[2] for $Result as the object for each of my 3 users is processed. In the TeamResults ForEach loop, I’m doing just one thing, assigning adding something to $BodyReplacementtxt. The plus-equals (+=) means that I’m taking what’s where and I’m adding to it. I’m not overriding what’s there already. In this case, I’m adding string objects to it that contain the information specified by the code and the current object I’m using.
Intially, $BodyReplacementTxt is blank.
PS C:\> $BodyReplacementTxt
PS C:\>
First, $Result = $TeamResults[0] (i.e. the first object in the $TeamResults object).
PS C:\> $TeamResults[0]
UserName Department Title Location
-------- ---------- ----- --------
user1 DeptA JobA Dallas
Now, I’m taking pieces from the above data (i.e. UserName, Department, & Location), for user1, and adding it to $BodyReplacementTxt.
PS C:\Users\miracles1315\OneDrive\Powershell\Scripts> $BodyReplacementTxt += "Username: $($TeamResults[0].UserName)`r`nTitle: $($TeamResults[0].Title)`r`nLocation: $($TeamResults[0].Location)`r`n`n"
PS C:\Users\miracles1315\OneDrive\Powershell\Scripts> $BodyReplacementTxt
Username: user1
Title: JobA
Location: Dallas
Now, I do that for the next object that gets assigned to $Result (i.e. $TeamResults[1]), which is a string that has the Username, Title, and Location of user5.
PS C:\Users\miracles1315\OneDrive\Powershell\Scripts> $BodyReplacementTxt += "Username: $($TeamResults[1].UserName)`r`nTitle: $($TeamResults[1].Title)`r`nLocation: $($TeamResults[1].Location)`r`n`n"
PS C:\Users\miracles1315\OneDrive\Powershell\Scripts> $BodyReplacementTxt
Username: user1
Title: JobA
Location: Dallas
Username: user5
Title: JobA
Location: Frisco
Finally, the last object that gets assigned to $Team (i.e. $TeamResults[2]), which is a string that has the Username, Title, and Location of user6 (i.e. the last of the 3 objects in $TeamResults).
PS C:\Users\miracles1315\OneDrive\Powershell\Scripts> $BodyReplacementTxt += "Username: $($TeamResults[2].UserName)`r`nTitle: $($TeamResults[2].Title)`r`nLocation: $($TeamResults[2].Location)`r`n`n"
PS C:\Users\miracles1315\OneDrive\Powershell\Scripts> $BodyReplacementTxt
Username: user1
Title: JobA
Location: Dallas
Username: user5
Title: JobA
Location: Frisco
Username: user6
Title: JobA
Location: Dallas
The next thing that happens, after the TeamResults ForEach loop, is that I determine what recipients (one, or more) should be stored in the $Recipient variable. In the case of TeamA, there is only one recipient listed. Again, $Team = $TeamsData[0] because we’re still in the first loop of the TeamsData ForEach block.
PS C:\> $TeamsData[0].Recipient
tuser1@domain.com
PS C:\> $Recipient = $TeamsData[0].Recipient -split ","
PS C:\> $Recipient
tuser1@domain.com
If there had been more than one recipient, as in the example of TeamB, it would look like this.
PS C:\> $TeamsData[1].Recipient
tuser1@domain.com,tuser2@domain.com
PS C:\> $Recipient = $TeamsData[1].Recipient -split ","
PS C:\> $Recipient
tuser1@domain.com
tuser2@domain.com
Next, I run the Send-MailMessage cmdlet, where the arguments I put in the $EmailArgs variable are used, what’s in the $BodyReplacmentTxt variable is put in place of the word “REPLACE” in the $MsgBody string object, and the list of recpients in $Recipient is assigned to the To parameter.
Finally, I remove the $TeamResults, $BodyReplacementTxt, & $Recipient variables. In case they don’t have values in them, I set the -ErrorAction parameter to SilentlyContinue.
The above is repeated for the other teams, one at a time.
Hopefully that wasn’t too much of an explanation and it made sense.
My apologies, again, if I’m assuming too much, but it seems like you could use some resources to help you better understand powershell, including objects. Below are some resources that I highly recommend. The books are co-authored by Don Jones and Jeffrey Hicks who happen to run this site. If you buy the physical books (pbooks as they call them), you also get the digital copies free in several forms (pdf, kindle, etc…).
Beginning Book/Courses:
-Learn Windows PowerShell In A Month Of Lunches (Chapter 9 is especially awesome at explaining the pipeline.)
–Getting Started with Microsoft PowerShell: https://mva.microsoft.com/en-US/training-courses/getting-started-with-microsoft-powershell-8276?l=vOd1PSWy_9204984382 (A Series of videos with Jeffrey Snover (helped create/design Windows Powershell) & Jason Helmick; Watching this in concert with reading the Learn Windows PowerShell In A Month Of Lunches book really helped the info sink in.)
–Getting Started with PowerShell Desired State Configuration (DSC): https://mva.microsoft.com/en-US/training-courses/getting-started-with-powershell-desired-state-configuration-dsc-8672?l=ZwHuclG1_2504984382 (Not yet started this.)
Advanced Book/Courses:
-Learn PowerShell Toolmaking In A Month Of Lunches (Reading through this now.)
–Advanced Tools & Scripting with PowerShell 3.0 Jump Start: https://mva.microsoft.com/en-US/training-courses/advanced-tools-scripting-with-powershell-30-jump-start-8277?l=WOWaGUWy_8604984382 (A Series of videos with Jeffrey Snover (helped create/design Windows Powershell) & Jason Helmick); Watching this in concert with reading the Learn PowerShell Toolmaking In A Month Of Lunches book has really helped the info sink in.)
–Advanced PowerShell Desired State Configuration (DSC) and Custom Resources : https://mva.microsoft.com/en-US/training-courses/advanced-powershell-desired-state-configuration-dsc-and-custom-resources-8702?l=3DnsS2H1_1504984382 (Not yet started this.)
If my above explanation doesn’t put you to sleep, I don’t know what will…lol