Home > Software design >  How to specify column position when adding new column to a csv file using PowerShell
How to specify column position when adding new column to a csv file using PowerShell

Time:10-05

How can I specify the column position when adding a new column to an existing csv file?

I want to add the new column as second column (Not at the end what the default is).
The first column is always the same, but the other columns can differ per file (so it is not known on beforehand which columns (names and order) there are (with the exception of the first column, which always contains the name)).

As far as I know there is no position parameter for Add-Member.

Sample code:

$csv = Import-Csv -Path "attendees.csv" -Delimiter ';' 

foreach ($row in $csv)
{
    $row | Add-Member -'GUID' -Value (New-Guid).Guid -MemberType NoteProperty 
}

$csv | Export-Csv new_attendees.csv' -NoTypeInformation

CodePudding user response:

In case you do not know the column names at forehand.
Using Select-Object with a calculated property for this:

$csv = Import-Csv -Path "attendees.csv" -Delimiter ';' 
$Properties = [Collections.Generic.List[Object]]$csv[0].psobject.properties.name
$Properties.Insert(1, @{ n='Guid'; e={ (New-Guid).Guid } })
$csv |Select-Object -Property $Properties |Export-Csv new_attendees.csv' -NoTypeInformation

CodePudding user response:

Add-Member does not let you specify at which position to add a property to an object. So you have to build a new object where you can control the position of the property, e.g.:

$newObjects = @(
    foreach ($row in $csv){
        $attrsHt = [ordered]@{
            [propertyName]=[propertyValue]
            Guid=([guid]::NewGuid()).guid
            [propertyName]=[propertyValue]
            [propertyName]=[propertyValue]
        }
        New-Object -TypeName psobject -Property $attrsht
    }
)

Or you can use select-object to change the order of the output:

foreach ($row in $csv)
{
    $row | Add-Member -Name 'GUID' -Value (New-Guid).Guid -MemberType NoteProperty 
}

$csv | select-object [propertyName],Guid,[propertyName],[propertyName] | export-csv new_attendees.csv' -NoTypeInformation

Ok as the propertyNames are unknown/dynamic you could do:

#Get the csv header and split by delimiter to get array of property names
[System.Collections.ArrayList]$csvHeader = (get-content [path])[0] -split ","

#Insert Guid at 2nd Position
$csvHeader.insert(1,'GUID')

$csv | select-object $csvHeader | export-csv new_attendees.csv -NoTypeInformation

CodePudding user response:

I don't think there's an easy way to insert a property into an object in-place at a specific index, but here's a quick proof-of-concept I knocked out to create a new object based on the original...

It could do with some error handling and perhaps some parameter attributes to support the pipeline, but it basically works...

function Insert-NoteProperty
{

    param(
        [pscustomobject] $InputObject,
        [string] $Name,
        [object] $Value,
        [int] $Index
    )

    $properties = @($InputObject.psobject.Properties);

    $result = [ordered] @{};

    # append the properties before the index
    for( $i = 0; $i -lt $Index; $i   )
    {
        $result.Add($properties[$i].Name, $properties[$i].Value);
    }

    # append the new property
    $result.Add($Name, $Value);

    # append the properties after the index
    for( $i = $Index; $i -lt $properties.Length; $i   )
    {
        $result.Add($properties[$i].Name, $properties[$i].Value);
    }

    return [pscustomobject] $result;

}

Example:

$original = [pscustomobject] [ordered] @{ "aaa"="bbb"; "ccc"="ddd" }

$original
# aaa ccc
# --- ---
# bbb ddd

$updated = Insert-NoteProperty `
    -InputObject $original `
    -Name        "new" `
    -Value       "value" `
    -Index       1;

$updated
# aaa new   ccc
# --- ---   ---
# bbb value ddd

You can use this with a csv file as follows:

$csv = @"
aaa,ccc
bbb,ddd
"@

$data = $csv | ConvertFrom-Csv;

$newdata = $data | foreach-object {
    Insert-NoteProperty `
        -InputObject $_ `
        -Name        "new" `
        -Value       "value" `
        -Index       1
}

$newcsv = $newdata | ConvertTo-Csv

$newcsv
# "aaa","new","ccc"
# "bbb","value","ddd"
  • Related