Search code examples
arrayspowershellvariableshashtable

PowerShell, Pulling out multiple arrays from an variable to make a single variable


I have a variable $metrics, and for the lack of knowing for sure, I am calling this an Array of Arrays? I'm probably wrong, but its best I can think of.

Here is the variable.

PS C:\Windows\system32> $metrics


Id         : cpuUtil01
Label      : CPUUtilization
Messages   : {}
StatusCode : Complete
Timestamps : {11/27/2021 7:00:00 PM, 11/27/2021 7:05:00 PM, 11/27/2021 7:10:00 PM, 11/27/2021 7:15:00 PM...}
Values     : {51.22, 31.3833333333333, 31.4116666666667, 31.5283333333333...}

I want to pull the $metrics.timestamps and $metrics.values out so I can export them into a CSV file, so I can use Excel's Line Graph. I can't figure out how to pull out the two of them into one variable.

I can do it one at a time, like below, but how do I join them so I have a CSV I can use.

$o = ""
$out = @()

foreach ($GetMetric in $Metrics.timestamps){ 

$o = New-Object -TypeName PSCustomObject -Property  ([ordered]@{
            
            TimeStampUTC = $GetMetric;
                        
                           })
$out += $o

}
$out

TimeStampUTC          
------------          
11/27/2021 7:00:00 PM 
11/27/2021 7:05:00 PM 
11/27/2021 7:10:00 PM 
11/27/2021 7:15:00 PM 
11/27/2021 7:20:00 PM 
11/27/2021 7:25:00 PM 
11/27/2021 7:30:00 PM 
11/27/2021 7:35:00 PM 
11/27/2021 7:40:00 PM 
11/27/2021 7:45:00 PM 
$o = ""
$out = @()

foreach ($GetMetric in $Metrics.values){ 

$o = New-Object -TypeName PSCustomObject -Property  ([ordered]@{
            
            Values = $GetMetric;
                        
                           })
$out += $o

}
$out

          Values
          ------
           51.22
31.3833333333333
31.4116666666667
31.5283333333333
31.4166666666667
          31.425
31.4916666666667
31.4166666666667
          31.325
31.5916666666667

What I would like to have is a variable that has both values, and looks like below, so I can output it to a csv file.

PS C:\Windows\system32> $output

TimeStampUTC              Values
------------              ------
11/27/2021 7:00:00 PM     51.22
11/27/2021 7:05:00 PM     31.3833333333333
11/27/2021 7:10:00 PM     31.4116666666667
11/27/2021 7:15:00 PM     31.5283333333333
11/27/2021 7:20:00 PM     31.4166666666667
11/27/2021 7:25:00 PM     31.425
11/27/2021 7:30:00 PM     31.4916666666667
11/27/2021 7:35:00 PM     31.4166666666667
11/27/2021 7:40:00 PM     31.325
11/27/2021 7:45:00 PM     31.5916666666667

How would you do this?

Any help is greatly appreciated.

-Rugbyball

<edited - additional notes>

Here was my output for the .GetType() and Get-Member

PS C:\Windows\system32> $metrics.GeTtype()

IsPublic IsSerial Name                                     BaseType                                                                                                          
-------- -------- ----                                     --------                                                                                                          
True     True     List`1                                   System.Object                                                                                                     



PS C:\Windows\system32> $metrics.Values.GetType()

IsPublic IsSerial Name                                     BaseType                                                                                                          
-------- -------- ----                                     --------                                                                                                          
True     True     Object[]                                 System.Array                                                                                                      



PS C:\Windows\system32> $metrics | Get-Member


   TypeName: Amazon.CloudWatch.Model.MetricDataResult

Name        MemberType Definition                                                                              
----        ---------- ----------                                                                              
Equals      Method     bool Equals(System.Object obj)                                                          
GetHashCode Method     int GetHashCode()                                                                       
GetType     Method     type GetType()                                                                          
ToString    Method     string ToString()                                                                       
Id          Property   string Id {get;set;}                                                                    
Label       Property   string Label {get;set;}                                                                 
Messages    Property   System.Collections.Generic.List[Amazon.CloudWatch.Model.MessageData] Messages {get;set;}
StatusCode  Property   Amazon.CloudWatch.StatusCode StatusCode {get;set;}                                      
Timestamps  Property   System.Collections.Generic.List[datetime] Timestamps {get;set;}                         
Values      Property   System.Collections.Generic.List[double] Values {get;set;} 

Solution

  • What you're trying to do is usually known as "merge arrays" or "join arrays". There are many ways to approach this, for example, with a for loop.

    To answer your first question, $metrics is an object, and as any object it can have properties and methods. In this case, your object has 3 properties which are arrays. To give some perspective on how you can approach this in the future, it's key to know about the .GetType() method and Get-Member.

    This is a recreation of your object using [PSCustomObject]:

    $metrics = [pscustomobject]@{
        Id         = 'cpuUtil01'
        Label      = 'CPUUtilization'
        Messages   = @()
        StatusCode = 'Complete'
        Timestamps = '11/27/2021 7:00:00 PM','11/27/2021 7:05:00 PM','11/27/2021 7:10:00 PM'
        Values     = '51.22','31.3833333333333','31.4116666666667','31.5283333333333'
    }
    

    Now we can put it into practice:

    PS /> $metrics.GeTtype()
    
    IsPublic IsSerial Name             BaseType
    -------- -------- ----             --------
    True     False    PSCustomObject   System.Object
    
    PS /> $metrics.Values.GetType()
    
    IsPublic IsSerial Name             BaseType
    -------- -------- ----             --------
    True     True     Object[]         System.Array
    
    PS /> $metrics | Get-Member
    
       TypeName: System.Management.Automation.PSCustomObject
    
    Name        MemberType   Definition
    ----        ----------   ----------
    Equals      Method       bool Equals(System.Object obj)
    GetHashCode Method       int GetHashCode()
    GetType     Method       type GetType()
    ToString    Method       string ToString()
    Id          NoteProperty string Id=cpuUtil01
    Label       NoteProperty string Label=CPUUtilization
    Messages    NoteProperty Object[] Messages=System.Object[]
    StatusCode  NoteProperty string StatusCode=Complete
    Timestamps  NoteProperty Object[] Timestamps=System.Object[]
    Values      NoteProperty Object[] Values=System.Object[]
    

    Now to answer the main question, how to merge both arrays?:

    • First we need to know if both have the same length, else we would be losing information:
    $maxCount = [math]::Max($metrics.TimeStamps.Count, $metrics.Values.Count)
    

    Then just loop over each element of each array using a for loop creating a new object out of their values:

    $result = for($i = 0; $i -lt $maxCount; $i++)
    {
        [pscustomobject]@{
            TimeStamps = $metrics.TimeStamps[$i]
            Values = $metrics.Values[$i]
        }
    }
    
    PS /> $result
    
    TimeStamps            Values
    ----------            ------
    11/27/2021 7:00:00 PM 51.22
    11/27/2021 7:05:00 PM 31.3833333333333
    11/27/2021 7:10:00 PM 31.4116666666667
    11/27/2021 7:15:00 PM 31.5283333333333