none
How to retain the order of the psobjects passed into a function? RRS feed

  • Question

  • I have the following script that gets objects from another scripts and converts it to a pscustomobject

    & ".\script1.ps1" -ViewConnection "$cinput" -OutVariable xprtOut | Format-Table -Wrap
    
    #converting xprtOut from Arraylist to pscustomobject to be used with ConvertTo-HTMLTable
    $Arr = @()
    foreach ($Object in $xprtOut) {
        $i = -1
        $arrayListCount = -($Object | gm | Where-Object {$_.MemberType -like "noteproperty"}).Count
    
        $customObj = New-Object PSCustomObject
        do {
            $customObj | Add-Member -MemberType NoteProperty -Name (($Object | gm)[$($i)].Name) -Value ($Object."$(($Object | gm)[$($i)].Name)")
            $i--
        } while ($i -ge $arrayListCount)
    
        $Arr += $customObj
    }

    it works great and all but i notice the ordering of the objects changes. how can i preserve the ordering in the function?

    i am trying the answer here: https://stackoverflow.com/a/42300930/8397835

    $Arr += [pscustomobject]$customObj

    but that doesnt work. i tried placing the cast elsewhere in the function and gave out errors.

    The ordered attribute can be specified only on a hash literal node.

    i guess i am not sure where am i supposed to place the [ordered] or [pscutomobject] in the function since in my case i dont have @ symbol

    Sunday, July 14, 2019 2:58 AM

Answers

  • You can use an "ordered" hash to generate objects very easily:

    $hash = [ordered]@{}
    $hash.Add('name1','value1') $hash.Add('name2','value2') [pscustomobject]$hash


    This line need to be:

    $xprtOut  = .\script1.ps1 -ViewConnection $cinput

    This would work more correctly:

    $resulArray = .\script1.ps1 -ViewConnection $cinput |
        ForEach-Object {
            $count = ($_ | Get-Member | Where-Object {$_.MemberType -like "noteproperty"}).Count
            $hash = [ordered]@{}
            for($i = 0;$i -lt $count,$i++){
                $hash.Add($_.Name,$_.Value)
            } 
            [pscustomobject]$hash
        }
    

    Of course all of the depends on what is in your script and what it returns.

    Before attempting such tricky code you should first learn the basics of PowerShell and coding.  Much of what you are doing is either unnecessary or wrong.

    If you have real objects to start with then none of this would be neccessary


    \_(ツ)_/


    • Edited by jrvModerator Sunday, July 14, 2019 3:42 AM
    • Marked as answer by cataster Monday, July 15, 2019 3:28 PM
    Sunday, July 14, 2019 3:41 AM
    Moderator

All replies

  • You can use an "ordered" hash to generate objects very easily:

    $hash = [ordered]@{}
    $hash.Add('name1','value1') $hash.Add('name2','value2') [pscustomobject]$hash


    This line need to be:

    $xprtOut  = .\script1.ps1 -ViewConnection $cinput

    This would work more correctly:

    $resulArray = .\script1.ps1 -ViewConnection $cinput |
        ForEach-Object {
            $count = ($_ | Get-Member | Where-Object {$_.MemberType -like "noteproperty"}).Count
            $hash = [ordered]@{}
            for($i = 0;$i -lt $count,$i++){
                $hash.Add($_.Name,$_.Value)
            } 
            [pscustomobject]$hash
        }
    

    Of course all of the depends on what is in your script and what it returns.

    Before attempting such tricky code you should first learn the basics of PowerShell and coding.  Much of what you are doing is either unnecessary or wrong.

    If you have real objects to start with then none of this would be neccessary


    \_(ツ)_/


    • Edited by jrvModerator Sunday, July 14, 2019 3:42 AM
    • Marked as answer by cataster Monday, July 15, 2019 3:28 PM
    Sunday, July 14, 2019 3:41 AM
    Moderator
  • You can use an "ordered" hash to generate objects very easily:

    $hash = [ordered]@{}
    $hash.Add('name1','value1') $hash.Add('name2','value2') [pscustomobject]$hash


    This line need to be:

    $xprtOut  = .\script1.ps1 -ViewConnection $cinput

    This would work more correctly:

    $resulArray = .\script1.ps1 -ViewConnection $cinput |
        ForEach-Object {
            $count = ($_ | Get-Member | Where-Object {$_.MemberType -like "noteproperty"}).Count
            $hash = [ordered]@{}
            for($i = 0;$i -lt $count,$i++){
                $hash.Add($_.Name,$_.Value)
            } 
            [pscustomobject]$hash
        }

    Of course all of the depends on what is in your script and what it returns.

    Before attempting such tricky code you should first learn the basics of PowerShell and coding.  Much of what you are doing is either unnecessary or wrong.

    If you have real objects to start with then none of this would be neccessary


    \_(ツ)_/


    My bad, should've had a little explanation. I am passing objects from script 1, and those objects could be different depending on the input switch the user chooses. Objects exported include fir example iteration,server,server alias, cube name, and connection info. 

    Not all the time is guaranteed these objects will be exported. That's why I have the loop in my post to dynamically recreate the array list as a pscustomobject for use in another function I have (not relevant to this thread) in script 2. 

    I cant/dont want a hash table hardcoded because as I said I want the loop to recreate the array list of objects exported from script 1 to be converted to pscustomobject dynamically, and that is exactly what the loop in my post does, and it works. All I want is to add something to the loop to keep the ordering as is from the arraylist

    Also I am using -outvariable for some outputting purposes (note the FT pipe)

    But I think your code might be what I'm looking for, gonna try it out :)

    • Edited by cataster Sunday, July 14, 2019 4:03 AM
    Sunday, July 14, 2019 3:57 AM
  • "select-object *" will create a custom object array directly. What you are doing serves no purpose.

    .\script1.ps1 -ViewConnection$cinput  | Select *

    Again - start by learning the basics of PowerShell so you know what objects are, how they are used and how to manipulate them with PowerShell.


    \_(ツ)_/

    Sunday, July 14, 2019 4:15 AM
    Moderator
  • https://stackoverflow.com/questions/57022534/how-to-keep-the-psobjects-ordered

    Live long and prosper!

    (79,108,97,102|%{[char]$_})-join''

    Sunday, July 14, 2019 10:22 AM
  • I'm pretty sure your problem is that you're using Get-Member. That cmdlet sorts the properties into alpha-numeric order.

    Try using "Select -Property *" instead, or just $x without the ornamentation, I think you'll see it works the way you expect it to.

    If you uncomment one line at a time in this script (the ones that display the variable $x) you'll see the results differ when you use Get-Member. Don't uncomment all of them at once or you get different results!

    # create a PSCustomObject
    $x=new-object pscustomobject
    $x | Add-Member NoteProperty 'z' 'zzzz'
    $x | Add-Member NoteProperty 'a' 'aaaa'
    $x | Add-Member NoteProperty 'm' 'mmmm'
    $x | Add-Member NoteProperty 'arr' @(1,2,3)
    $x | Add-Member NoteProperty 'hash' @{one=1;two=2;three=3}
    
    # show it (it only shows NoteProperty elements)
    #$x
    
    # Select the properties (does the same thing as plain old $x)
    #$x | select -Property *
    
    # use Get-Member to show the NoteProperty elements
    #$x | gm -MemberType NoteProperty


    --- Rich Matheisen MCSE&I, Exchange Ex-MVP (16 years)

    Sunday, July 14, 2019 3:42 PM
  • I'm pretty sure your problem is that you're using Get-Member. That cmdlet sorts the properties into alpha-numeric order.

    Try using "Select -Property *" instead, or just $x without the ornamentation, I think you'll see it works the way you expect it to.

    If you uncomment one line at a time in this script (the ones that display the variable $x) you'll see the results differ when you use Get-Member. Don't uncomment all of them at once or you get different results!

    # create a PSCustomObject
    $x=new-object pscustomobject
    $x | Add-Member NoteProperty 'z' 'zzzz'
    $x | Add-Member NoteProperty 'a' 'aaaa'
    $x | Add-Member NoteProperty 'm' 'mmmm'
    $x | Add-Member NoteProperty 'arr' @(1,2,3)
    $x | Add-Member NoteProperty 'hash' @{one=1;two=2;three=3}
    
    # show it (it only shows NoteProperty elements)
    #$x
    
    # Select the properties (does the same thing as plain old $x)
    #$x | select -Property *
    
    # use Get-Member to show the NoteProperty elements
    #$x | gm -MemberType NoteProperty


    --- Rich Matheisen MCSE&I, Exchange Ex-MVP (16 years)

    Interesting

    with both $x and  $x | select -Property *

    z    : zzzz
    a    : aaaa
    m    : mmmm
    arr  : {1, 2, 3}
    hash : {one, three, two}

    i get same results, however, i notice the 'hash' noteproperty has the data rearranged

    notice instead of {one, two, three} i get {one, three, two}

    but yes, i also see that the results were unordered with gm

    Name MemberType   Definition
    ---- ----------   ----------
    a    NoteProperty string a=aaaa
    arr  NoteProperty Object[] arr=System.Object[]
    hash NoteProperty hashtable hash=System.Collections.Hashtable
    m    NoteProperty string m=mmmm
    z    NoteProperty string z=zzzz



    • Edited by cataster Monday, July 15, 2019 3:35 PM
    Monday, July 15, 2019 3:34 PM
  • It's a hash. There is no "order".

    --- Rich Matheisen MCSE&I, Exchange Ex-MVP (16 years)

    Monday, July 15, 2019 5:50 PM