2

I am trying to achieve the following with imported CSV Data in Powershell:

the CSV has the following structure:

| FirstName | LastName | Tier |
| --------- | -------  | ---- |
|  George   | Smith    |  0   |
|  John     | Fritz    |  1   |
|  Thomas   | Adams    |  1   |
|  Manuel   | Evans    |  0   |

I import the CSV Data as follows:

$csv = Import-Csv csvfile.csv

Now here is the Problem. I am trying to add few more lines to the object

$csv

If a User is of Tier 0 then the same User should be added to the object with Tier 1.

The resulting $csv object should look like:

| FirstName | LastName | Tier |
| --------- | -------  | ---- |
|  George   | Smith    |  0   |
|  John     | Fritz    |  1   |
|  Thomas   | Adams    |  1   |
|  Manuel   | Evans    |  0   |
|  George   | Smith    |  1   |
|  Manuel   | Evans    |  1   |

The order in which the new Tier 1 rows are placed in the object do not matter. They should just be somewhere in the object with all the original data. I also do not need the resulting Tier 1 Lines in any CSV File. I only need those new Lines (Members) to be a part of $csv object with all other Data untouched so i can then iterate through original and new data in the same object using a foreach loop.

What i tried so far without positive results:

$csv = Import-Csv csvfile.csv

foreach ($User in $csv){ 
    $tier = $User.Tier -replace '\s',''
    if($tier -eq '0'){  
    $csv+= @{FirstName= $User.FirstName; LastName=$User.LastName; Tier='1'}
    }
}

another try without positive results:

$csv = Import-Csv csvfile.csv

foreach ($User in $csv){ 
    $tier = $User.Tier -replace '\s',''
    if($tier -eq '0'){  
        $csv | Add-Member -MemberType NoteProperty -Name 'FirstName' -Value $User.FirstName -Force
        $csv | Add-Member -MemberType NoteProperty -Name 'LastName' -Value $User.LastName -Force
        $csv | Add-Member -MemberType NoteProperty -Name 'Tier' -Value '1' -Force
    }
}

After failing miserably i have come to get help from the Wizards of StackOverflow.

How can i achieve this? How do i get the Tier 0 Rows duplicated with a different Tier Value while leaving all other Data untouched into the same object?

Zombievirus
  • 177
  • 1
  • 2
  • 12

1 Answers1

2

This is one way you can do it but note that this example does not check if Tier 1 object already exists for a Tier 0 object.

$newCsv = Import-Csv ... | ForEach-Object {
    $_
    if ($_.Tier -eq 0) {
        $copy = $_.PSObject.Copy()
        $copy.Tier = 1
        $copy
    }
}

Demo:

@'
FirstName|LastName|Tier
George|Smith|0
John|Fritz|1
Thomas|Adams|1
Manuel|Evans|0
'@ | ConvertFrom-Csv -Delimiter '|' | ForEach-Object {
    $_
    if ($_.Tier -eq 0) {
        $copy = $_.PSObject.Copy()
        $copy.Tier = 1
        $copy
    }
}

FirstName LastName Tier
--------- -------- ----
George    Smith    0
George    Smith    1
John      Fritz    1
Thomas    Adams    1
Manuel    Evans    0
Manuel    Evans    1

Your first attempt was very close, the problem is that you're adding a hashtable @{ ... } instead of a custom object [pscustomobject]@{ ... } to the $Csv, then it should work fine but you should also try to avoid += as it is inefficient, you can do this instead which in the end is very similar to my example above:

$csv = Import-Csv ...
$newCsv = foreach ($User in $csv) {
    $User
    if ($User.Tier -eq '0') {
        [pscustomobject]@{
            FirstName = $User.FirstName
            LastName  = $User.LastName
            Tier      = '1' 
        }
    }
}

If you want to add to $Csv without producing a new array te recommendation is to use a List<T> and its .Add method. This method also requires a for loop instead of foreach otherwise you would get an error due to trying to mutate a collection while being enumerated.

[System.Collections.Generic.List[object]] $csv = Import-Csv ...
for ($i = 0; $i -lt $csv.Count; $i++) {
    if ($csv[$i].Tier -eq '0') {
        $csv.Add([pscustomobject]@{
            FirstName = $User.FirstName
            LastName  = $User.LastName
            Tier      = '1' 
        })
    }
}
Santiago Squarzon
  • 41,465
  • 5
  • 14
  • 37
  • In that case @Zombievirus instead of `+=` the recommendation would be to use a `List` and its `.Add` method (see update) – Santiago Squarzon Aug 17 '23 at 12:56
  • thank you santiago. i will try. i am trying to do it all in one loop. import the csv then start the loop to do the required changes to the users and if a tier 0 user is found then add tier 1 user with same info to the object which is already being used in the foreach loop i currently am in hoping that the same loop will find the added users on the next iteration – Zombievirus Aug 17 '23 at 12:58
  • unfortunately getting an error. Collection was modified; enumeration operation may not execute. i guess it won't work without an additional array – Zombievirus Aug 17 '23 at 13:09
  • @Zombievirus that update should fix the enumeration error but it's only adding more complexity to a simple problem. You should use the examples 1 or 2 – Santiago Squarzon Aug 17 '23 at 13:16
  • the first example returned an array of original data + original data + corrected tier 1 duplicates. an original tier 0 user appeared in the array 3 times (twice with original data and once with correction of tier) and a tier 1 user appeared twice. correction was to delete the $_ in the beginning of foreach loop – Zombievirus Aug 17 '23 at 13:38
  • @Zombievirus idk what you mean. im using the sample data you've provided and it is working fine, even added a reproducible example to the answer. – Santiago Squarzon Aug 17 '23 at 13:42
  • 1
    now i know what i did wrong. $csv = Import.. in first line and then $csv | Foreach.. from second line on. This is why the output was different. now it's all fixed and working perfectly. thank you Santiago. I upvoted your answer. The First Example is indeed the best solution. – Zombievirus Aug 17 '23 at 14:11
  • @Zombievirus glad it helped. possibly it was failing before for you because your rows might have white spaces on each cell? Like I see you're doing `-replace '\s',''` so that might be the reason why it was failing? Also, I recommend you to do `$user.Tier.Trim()` to remove white spaces if thats the case – Santiago Squarzon Aug 17 '23 at 14:33