powershellimport-csvpsobjectpscustomobject

Import-CSV: add rows (members) to resulting object in foreach loop


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?


Solution

  • 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' 
            })
        }
    }