Reputation:
I have the following code:
$DataType = "X,Y,Z"
$Data = "1,2,3"
$Table = @()
for ($i = 0; $i -le ($DataType.Count-1); $i++)
{
$Properties = @{$DataType[$i]=$Data[$i]}
$Object = New-Object -TypeName PSCustomObject -Property $Properties
$Table += $Object
}
$Table | Format-Table -AutoSize
I get this output:
X
-
1
What I would like to get is:
X Y Z
- - -
1 2 3
Thanks for your help!
Upvotes: 1
Views: 576
Reputation: 466
One solution to this problem (if the inputs were two separate arrays):
$DataType = @( 'X','Y','Z' )
$Data = @( '1','2','3' )
$Table = New-Object psobject
for ($i = 0; $i -le ( $DataType.Count-1 ); $i++)
{
$Table | Add-Member -Name "$( $DataType[$i] )" -Value ( $Data[$i] ) -MemberType NoteProperty
}
$Table
Upvotes: 0
Reputation: 23830
Cutting a long story short:
$DataType, $Data | ConvertFrom-Csv
X Y Z
- - -
1 2 3
Ok, it needs a little explanation:
PowerShell will automatically unroll the array of strings ($DataType, $Data
) and supply it as individual line items to the pipeline. The ConvertFrom-Csv
cmdlet supports supplying the input table through the pipeline as separate lines (strings).
Upvotes: 4
Reputation: 25031
You can do the following instead:
$DataType = "X","Y","Z"
$Data = 1,2,3
$hash = [ordered]@{}
for ($i = 0; $i -lt $DataType.Count; $i++) {
$hash.Add($DataType[$i],$Data[$i])
}
$table = [pscustomobject]$hash
Explanation:
The code creates two collections, $DataType
and $Data
, of three items. $hash
is an ordered hash table. [ordered]
is used to preserve the order at which key-value pairs are added to the hash table. Since $hash
is the object type hashtable, it contains the .Add(key,value)
method for adding key-value pairs.
Since the [pscustomobject]
type accelerator can be cast on a hash table, we can simply use the syntax [pscustomobject]$hash
to create a new object.
If we consider your attempt, your variables are actually single strings rather than collections. Surrounding a value with quotes causes PowerShell to expand the inner contents as a string. When you index a string rather than a collection, you index the characters in the string rather than the entire item. You need to quote the individual elements between the commas so that the ,
acts as a separator rather than part of the string. You can see this behavior in the code below:
# DataType as a string
$DataType = "X,Y,Z"
$DataType[1]
,
# DataType as an array or collection
$DataType = "X","Y","Z"
$DataType[1]
Y
If you receive your data from another output in the current format, you can manipulate using $DataType = $DataType.Split(',')
in order to create a collection. Alternatively you can treat the data as comma-separated and use the Import-Csv or ConvertFrom-Csv commands as in iRon's answer provided you order your strings properly.
Inside of your loop, you are adding three new objects to your collection $table
rather than creating one object with three properties. $table += $Object
creates an array called $table
that appends a new item to the previous list from $table
. If this was your original intention, you can view your collection by running $table | Format-List
once you fix your $DataType
and $Data
variables.
When a collection is enumerated, the default table view displays the properties of the first object in a collection. Any succeeding objects will only display values for the first object's matching properties. So if object1 has properties X and Y and object2 has properties Y and Z, the console will only display values for properties X and Y for both objects. Format-List
overrides this view and displays all properties of all objects. See below for an example of this behavior:
$obj1
X Y
- -
1 2
$obj2
Y Z
- -
3 4
$array = $obj1,$obj2
# Table View
$array
X Y
- -
1 2
3
# List View
$array | Format-List
X : 1
Y : 2
Y : 3
Z : 4
Upvotes: 2
Reputation: 16612
It seems that you want to create a single object with a property for each value in the arrays $DataType
/$Data
, but the problems are...
$DataType
nor $Data
are arrays.for
loop you will create one object per iteration.$DataType
is a scalar variable $DataType.Count
returns 1
. Ordinarily, testing for $DataType.Count-1
would mean the loop never gets entered, but by the grace of using -le
(so 0 -le 0
returns $true
) instead of -lt
, it does for exactly one iteration. Thus, you do get your single result object, but with only the first property created.To fix this, let's create $DataType
and $Data
as arrays, as well as creating one set of properties before the loop to be used to create one result object after the loop...
...
$DataType = "X,Y,Z" -split ','
$Data = "1,2,3" -split ','
$Properties = @{}
for ($i = 0; $i -lt $DataType.Count; $i++)
{
$Properties[$DataType[$i]] = $Data[$i]
}
New-Object -TypeName PSCustomObject -Property $Properties | Format-Table -AutoSize
You'll also notice that $i -le ($DataType.Count-1)
has been simplified to $i -lt $DataType.Count
. On my system the above code outputs...
Y Z X
- - -
2 3 1
The properties are correct, but the order is not what you wanted. This is because Hashtable
instances, such as $Properties
, have no ordering among their keys. To ensure that the properties are in the order you specified in the question, on PowerShell 3.0 and above you can use this to preserve insertion order...
$Properties = [Ordered] @{}
Upvotes: 1
Reputation: 322
What if you initialized $Table as an appendable like so:
$Table = New-Object System.Collections.ArrayList
for ($i = 0; $i -le ($DataType.Count-1); $i++)
{
$Properties = @{$DataType[$i]=$Data[$i]}
$Object = New-Object -TypeName PSCustomObject -Property $Properties
$Table.Add ( $Object )
}
Reformat your logic as needed.
Upvotes: 0