This Join-Object Module
is basically meant to two join object lists based on a related property (see also: In Powershell, what's the best way to join two tables into one? but as it might also be used to do a side-by-side join (by omitting the related property define by the -on
parameter). This can be useful to transpose tables as e.g. a csv
file:
Install-Module -Name JoinModule -MinimumVersion 3.8.1
Sample Csv
$Csv = @'
"@","A","B","C"
"1","D","E","F"
"2","G","H","I"
"3","J","K","L"
'@
As Matrix
Considering a Csv file (or string) as a matrix were the header row has the same format as each following data row, you might just separate each field on the comma delimiter:
$Table = @()
# Get-Content .\My.csv |Foreach-Object { ...
$Csv -Split '\r?\n' |Foreach-Object { $Table = $Table |FullJoin $_.Split(',') }
$Transposed = $Table |Foreach-Object { $_ -Join ',' }
Explanation
$Csv -Split '\r?\n'
splits the multiline string in an array of lines which is the default behavior of the Get-Content
cmdlet
- Note: this approach doesn't take in account that the data might also contain a comma, e.g.:
"Name","Social"
"Mickey","123,456"
$Table = $Table |FullJoin $_.Split(',')
full joins each row as a column to the prior row and output a list of PSObject
collections ( System.Collections.ObjectModel.Collection[psobject]]
) similar to the foreach
and where
methods
- Note: there is a bug in the versions prior to
3.8.1
of the Join-Object
cmdlet that doesn't correctly implement the start from an empty pipeline ($Table = @()
)
$Table |Foreach-Object { $_ -Join ',' }
iterates through each row of PSObject
collections and joins each item (using the -join
operator) as a single string.
As List of PowerShell objects
$Data = ConvertFrom-Csv $Csv # = $xml.SelectNodes("//EmployeeImport/Employee")
$Names = $Data[0].PSObject.Properties.Name
$Last = $Names.get_Count() - 1
$Table = @() |FullJoin $Names[1..$Last] -Name $Names[0]
$Data |Foreach-Object {
$Values = $_.PSObject.Properties.Value
$Last = $Values.get_Count() - 1
$Table = $Table |FullJoin $Values[1..$Last] -Name $Values[0]
}
Explanation
In this case the input is considered to contain a list of PowerShell objects. Where it is common that each row is a PowerShell object and each property in the object represents a column.
- This means that the header row is actually contained by the first (and all other rows) in the
$Data[0].PSObject.Properties.Name
- The same counts for rebuilding the output where the first item should be considered to be the property name of each object. This is done with the command:
... |FullJoin $Names[1..$Last] -Name $Names[0]