I need to write a script that sends a single email to each person. That email will have unique codes for the person. Each person can get any number of codes.
The data looks like this
Email,Codes
[email protected],213
[email protected],999
[email protected],111
[email protected],123
[email protected],643
[email protected],809
[email protected],722
[email protected],013
I think the script will go something like this.
#get the data
$PeopleAndCodes = Import-Csv C:\temp\PeopleCodes.csv
#Count how many groups of unique people
[array]$CountOfPeople = $PeopleAndCodes.email | Group-Object -noelement | Select-Object Count
#Loop through unique people
$Index = 0;
while ($Index -lt $CountOfPeople.count) {
$Index
#THIS BELOW EXITS BEFORE GETTING THROUGH ALL THE CODES FOR ONE PERSON
[int]$DCodes = 0
foreach ($DCodes in [int]$CountOfPeople[$DCodes].count) {
$DCodes
Write-Host $DCodes DCODES
Write-Host $CountOfPeople[$DCodes].count CountOfPeople
Write-Host $PeopleAndCodes[$DCodes].codes
}
}
The problem is that my 2nd loop stops as soon as number of unique people is reached and then moves to the next person.
I don't understand why the 2nd loop is not going through the codes and then to the next person?
CodePudding user response:
You are very close, I would make some small tweaks to your code and we can get it there.
First, instead of indexing through the array, let's select all of the unique e-mails from the list of codes.
$uniqueUsers = $PeopleAndCodes | select -Unique Email
Next, we can foreach
loop our way through the list of $uniqueUsers
, and for each, find any matching codes for them.
foreach($uniqueUser in $uniqueUsers){
$thisEmail = $uniqueUser.Email
$matchingCodes = $PeopleAndCodes | Where Email -Match $uniqueUser.Email |
Select-Object -ExpandProperty Codes
Now we have within this loop a $thisEmail
var that holds the email address of the user, and then an array of all of the matching codes for the user, called $matchingCodes
. We don't need to index through these either. In fact that second loop was likely causing the issue, as there are more items in the list than unique users.
Your limiting condition was the number of unique users, not the number of items in the list.
So, to avoid confusion and get the desired output, just remove that second loop entirely since it isn't helping us.
Write-Host "Person - $thisEmail"
Write-Host "Person has $($matchingCodes.Count) codes"
$matchingCodes -join ","
Gives an output of
Person - [email protected]
Person has 2 codes
213,999
--------------------
Person - [email protected]
Person has 5 codes
111,123,643,809,722
Completed Code
$PeopleAndCodes = Import-Csv C:\temp\PeopleCodes.csv
$uniqueUsers = $PeopleAndCodes | select -Unique Email
foreach($uniqueUser in $uniqueUsers){
$thisEmail = $uniqueUser.Email
$matchingCodes = $PeopleAndCodes | where Email -Match $uniqueUser.Email | Select-Object -ExpandProperty Codes
Write-Host "Person - $thisEmail"
Write-Host "Person has $($matchingCodes.Count) codes"
$matchingCodes -join ","
Write-Host "--------------------"
}
CodePudding user response:
I want to point out that while above is the best answer. In the comments is another answer that works with my original code as well.
#get the data
$PeopleAndCodes = Import-Csv C:\temp\PeopleCodes.csv
#Count how many groups of unique people
[array]$CountOfPeople = $PeopleAndCodes.email | Group-Object -noelement | Select-Object Count
#Loop through unique people
$Index = 0;
while ($Index -lt $CountOfPeople.count) {
$Index
#This loops through each person and gets their code(s)
[int]$DCodes = 0
foreach ($DCodes in 0..[int]$CountOfPeople[$DCodes].count) {
Write-Host $PeopleAndCodes[$DCodes].email
Write-Host $PeopleAndCodes[$DCodes].codes
$DCodes
}
}