Home > Software engineering >  PowerShell append to first available row in a headered column in csv
PowerShell append to first available row in a headered column in csv

Time:01-29

Fairly new to PowerShell and having challenges with appending data in the first available row for each headered column in a csv file.

I would like to utilize foreach for each column's type of data that will be independent of another column's data. The column headers are $headers = "Scope", "Drawing", "Submittal", "Database", "Estimate", "Sequence" with a foreach to locate and append their individual items to each column. The current problem that is happening is that because each category/column with its respective foreach will add it on a separate row because the previous row already had data appended from another category's/column's data creating a diagonal appended data.

The reason that a separate foreach is being used is for each category/column is because the category's are looking for and filtering files independently for each category.

Below is what is happening in the CSV file:

| Scope | Drawing | Submittal | Database | Estimate | Sequence |
| ------| ------- |---------- |--------- |--------- |--------- |
| DATA01| empty   | empty     | empty    | empty    | empty    |
| empty | DATA11  | empty     | empty    | empty    | empty    |
| empty | empty   | DATA21    | empty    | empty    | empty    |
| empty | empty   | empty     | DATA31   | empty    | empty    |
| empty | empty   | empty     | empty    | DATA41   | empty    |
| empty | empty   | empty     | empty    | empty    | DATA51   |

This is what would be the desired result be for the CSV file:

| Scope | Drawing | Submittal | Database | Estimate | Sequence |
| ------| ------- |---------- |--------- |--------- |--------- |
| DATA01| DATA11  | DATA21    | DATA31   | DATA41   | DATA51   |         

Here is part of the code that is being worked on:

# Creates the CSV if it does not already exist
$headers = "Scope", "Mechanical Drawing", "Controls Submittal", "Database", "Estimate", "Sequence of Operations"
$psObject = New-Object psobject
foreach($header in $headers)
{
 Add-Member -InputObject $psobject -MemberType noteproperty -Name $header -Value ""
}
$psObject | Export-Csv $CsvFile -NoTypeInformation

foreach ($file in $ScopeList)
{
    $hash=@{
        "Scope" = $file.Fullname
    }
    $NewItem = New-Object PSObject -Property $hash
    Export-Csv $CsvFile -inputobject $NewItem -append -Force
}

foreach ($file in $DrawingList)
{
    $hash=@{
        "Drawing" = $file.Fullname
    }
    $NewItem = New-Object PSObject -Property $hash
    Export-Csv $CsvFile -inputobject $NewItem -append -Force
}

foreach ($file in $SubtmittalList)
{
    $hash=@{
        "Submittal" = $file.Fullname
    }
    $NewItem = New-Object PSObject -Property $hash
    Export-Csv $CsvFile -inputobject $NewItem -append -Force
}

foreach ($file in $DatabaseList)
{
    $hash=@{
        "Database" = $file.Fullname
    }
    $NewItem = New-Object PSObject -Property $hash
    Export-Csv $CsvFile -inputobject $NewItem -append -Force
}

foreach ($file in $EstimateList)
{
    $hash=@{
        "Estimate" = $file.Fullname
    }
    $NewItem = New-Object PSObject -Property $hash
    Export-Csv $CsvFile -inputobject $NewItem -append -Force
}

foreach ($file in $SequenceList)
{
    $hash=@{
        "Sequence" = $file.Fullname
    }
    $NewItem = New-Object PSObject -Property $hash
    Export-Csv $CsvFile -inputobject $NewItem -append -Force
}

The PowerShell version being used is 5.1. Windows 10 OS.

Could someone help me understand how to append on the same row but a different column without erasing another column's existing row of data? Would this be something that could be done with splatting or looking at each variable ${named}List?

CodePudding user response:

If I understand the question properly, you have 6 arrays of '$file' items that need to be combined into a CSV file.

Then instead of using 6 foreach loops, just use one indexed loop and create Objects from the various lists

If all lists have the same number of items:

$result = for ($i = 0; $i -lt $ScopeList.Count; $i  ) {
    [PsCustomObject]@{
        Scope     = $ScopeList[$i].FullName
        Drawing   = $DrawingList[$i].FullName
        Submittal = $SubtmittalList[$i].FullName
        Database  = $DatabaseList[$i].FullName
        Estimate  = $EstimateList[$i].FullName
        Sequence  = $SequenceList[$i].FullName
    }
}

# now save the result as CSV file
$result | Export-Csv -Path 'X:\Path\to\TheResult.csv' -NoTypeInformation

If the lists are not all of the same length, you need to do some extra work:

# get the maximum number of items of your lists
$maxItems = (($ScopeList, $DrawingList, $SubtmittalList, $DatabaseList, $EstimateList, $SequenceList) | 
            Measure-Object -Property Count -Maximum).Maximum

# loop over the maximum number of items and check each list 
# if the index $i does not exceed the max number of items for that list
$result = for ($i = 0; $i -lt $maxItems; $i  ) {
    [PsCustomObject]@{
        Scope     = if ($i -lt $ScopeList.Count)      {$ScopeList[$i].FullName}      else { $null}
        Drawing   = if ($i -lt $DrawingList.Count)    {$DrawingList[$i].FullName}    else { $null}
        Submittal = if ($i -lt $SubtmittalList.Count) {$SubtmittalList[$i].FullName} else { $null}
        Database  = if ($i -lt $DatabaseList.Count)   {$DatabaseList[$i].FullName}   else { $null}
        Estimate  = if ($i -lt $EstimateList.Count)   {$EstimateList[$i].FullName}   else { $null}
        Sequence  = if ($i -lt $SequenceList.Count)   {$SequenceList[$i].FullName}   else { $null}
    }
}

# now save the result as CSV file
$result | Export-Csv -Path 'X:\Path\to\TheResult.csv' -NoTypeInformation

CodePudding user response:

Like Theo posted, this mostly worked or brought the intentions closer to the goal. within each foreach loop that created their independent lists, another list was created for filtering the list and used in the below section from Theo.

# loop over the maximum number of items and check each list 
# if the index $i does not exceed the max number of items for that list
$result = for ($i = 0; $i -lt $maxItems; $i  ) {
    [PsCustomObject]@{
        Scope     = if ($i -lt $ScopeList.Count)      {$ScopeList[$i].FullName}      else { $null}
        Drawing   = if ($i -lt $DrawingList.Count)    {$DrawingList[$i].FullName}    else { $null}
        Submittal = if ($i -lt $SubtmittalList.Count) {$SubtmittalList[$i].FullName} else { $null}
        Database  = if ($i -lt $DatabaseList.Count)   {$DatabaseList[$i].FullName}   else { $null}
        Estimate  = if ($i -lt $EstimateList.Count)   {$EstimateList[$i].FullName}   else { $null}
        Sequence  = if ($i -lt $SequenceList.Count)   {$SequenceList[$i].FullName}   else { $null}
    }
}

# now save the result as CSV file
$result | Export-Csv -Path 'X:\Path\to\TheResult.csv' -NoTypeInformation

To get the $maxItems, an alternative way was to have a default value of 1 unless a user input has a keyword "list" when they are prompted for other info, which is another challenge on how to limit values to greater than or equal to 1...

  •  Tags:  
  • Related