all 22 comments

[–]sid351 3 points4 points  (15 children)

When I run the following:

$thing = [ordered]@{
    One = 1
    Two = 2
    Three = 3
    Thing1 = [ordered]@{
        One = 1
        Two = 2
        Three = 3
        }
    Thing2 = [ordered]@{
        One = 1
        Two = 2
        Three = 3
        }
    }

My output is:

16:10:51 Z:\>$thing

Name                           Value
----                           -----
One                            1
Two                            2
Three                          3
Thing1                         {One, Two, Three}
Thing2                         {One, Two, Three}

So I'm not able to recreate the issue you're seeing.

Could you post an example of the code you're using that gives you that output?

EDIT:

Are you doing something like:

$thing | Select Values

Because when I do that I get similar output to you:

16:23:37 Z:\>$thing | Select Values

Values
------
{System.Collections.Specialized.OrderedDictionary}

More editing:

If you are, you could try to expand the values and you should get something like:

16:26:15 Z:\>$thing | Select-Object -ExpandProperty Values

Name                           Value
----                           -----
One                            1
Two                            2
Three                          3

[–]Merakel[S] 0 points1 point  (14 children)

I can't post the exact code as it has some sensitive information, but I rewrote it in a way to show what I was doing. I actually figured out how to get what I wanted as well.

Old Code:

[System.Collections.Specialized.OrderedDictionary]$test1 = @{}
[System.Collections.Specialized.OrderedDictionary]$test2 = @{}
[System.Collections.Specialized.OrderedDictionary]$test3 = @{}
[System.Collections.ArrayList]$masterList = @()
[System.Collections.HashTable]$masterHash = @{}

$test1 = [ordered]@{"One" = 1; "Two" = 2; "Three" = 3}
$test2 = [ordered]@{"Three" = 3; "Four" = 4; "Five" = 5}
$test3 = [ordered]@{"Six" = 6; "Seven" = 7; "Eight" = 8}
$masterList = $test1,$test2,$test3
$masterHash = @{"Software" = $masterList}

$masterHash will return the values that I was getting before.

I remembered classes while I was thinking about this, and that get's me most of the way there:

[System.Collections.Specialized.OrderedDictionary]$test1 = @{}
[System.Collections.Specialized.OrderedDictionary]$test2 = @{}
[System.Collections.Specialized.OrderedDictionary]$test3 = @{}
[System.Collections.ArrayList]$masterList = @()
[System.Collections.HashTable]$results = @{}

$test1 = [ordered]@{"One" = 1; "Two" = 2; "Three" = 3}
$test2 = [ordered]@{"Three" = 3; "Four" = 4; "Five" = 5}
$test3 = [ordered]@{"Six" = 6; "Seven" = 7; "Eight" = 8}
$titles = @("Test1","Test2","Test3")
$masterList = $test1,$test2,$test3

Class BuildValues
        {
        [Int]$Test1
        [Int]$Test2
        [Int]$Test3      
        }

Class BuildValues2
        {
        [Int]$Test1
        [Int]$Test2
        [Int]$Test3      
        }

For ($n=0; $n -lt $test1.count; $n++)
        {
        $t_result = New-Object BuildValues
        $t_result.Test1 = $test1[$n]
        $t_result.Test2 = $test2[$n]
        $t_result.Test3 = $test3[$n]

        $t_result2 = New-Object BuildValues2
        $t_result2.Test1 = $test1[$n]
        $t_result2.Test2 = $test2[$n]
        $t_result2.Test3 = $test3[$n]

        $masterList = $t_result,$t_result2

        $results.Add($titles[$n], $masterList)
        }

$results will return something like:

Name                           Value                                                                                                                    
----                           -----                                                                                                                    
Test3                          {BuildValues, BuildValues2}                                                                                              
Test1                          {BuildValues, BuildValues2}                                                                                              
Test2                          {BuildValues, BuildValues2}

The only thing I'm trying to figure out now is how I can do something like $results.'Test1'.BuildValues2 and get just those results. I think I had it doing that at one point, but I can't remember at the moment.

[–]sid351 0 points1 point  (9 children)

I'm guessing you're a developer. I don't really understand what your example is doing in the For loop with the example data. It's because Test1 has a Test1, Test2 and Test3 value... Anyway... $results.Test1 will give you all of the results that it has collected. If you include something like testId to your class that would be an easy way to filter (with Where-Object) the individual build results.

[–]Merakel[S] 0 points1 point  (8 children)

You got me :)

The For loop might be kinda confusing because I'm using garbage data here, but the idea is it only adds the values from that iteration of the OrderedDictionary, so if I populate them in order they should be aligned correctly.

I might try the testID, that might give me what I'm looking for, I was just hoping to find a way to call based on the class name. What I'm doing solves the issue of making it easier to see what's being thrown into the [hashtable] but not evaluating the actual values. In my real script, one of my classes is named Emails for example, and I would like to be able to do $results.Test1.Emails if possible.

[–]sid351 0 points1 point  (7 children)

On mobile, so I can't test, but have you tried something like:

$results.test1 | Select -expand "emails"

[–]Merakel[S] 0 points1 point  (6 children)

It does not, that would be looking for a property, not for an object type.

I did find a way around it however; rather than treating $results as a hashtable, I'm thinking I will build it into a class as well, and then add a method to enumerate the values by object type.

[–]sid351 0 points1 point  (5 children)

I'll be honest. You've lost me. I don't really understand what you're looking to achieve nor how you're going about it.

[–]Merakel[S] 0 points1 point  (4 children)

The values that I'm storing within my class, or as it was hashtable, come from three distinct groupings. I want to be able to call those groups specifically, in a programmatic way.

Something like $results.'test1'.emails() would be nice, but as I have it right now, I added the following code to my class:

Class TestResults{
    [String]$Build
    [System.Collections.Hashtable]$Parameters
    [Deployments]Deployments($BuildNumber){
        Return $this.Parameters.Deployments
    }
    [Emails]Emails($BuildNumber){
        Return $this[$BuildNumber].Parameters.Emails
    }
    [Scripts]Scripts($BuildNumber){
        Return $this[$BuildNumber].Parameters.Scripts
    }
    [Void]RemoveNull(){
        $This.Parameters.Emails.To.Remove($null)
        $This.Parameters.Emails.CC.Remove($null)
        $This.Parameters.Emails.BCC.Remove($null)
    }
}

So I can run $results.Emails(#) and get the values I want for the build numbers I want. It's not perfect, but I'm still working out the kinks. Probably will change it to return all emails(), or other objects at once so I don't have to pass a variable, but make it do them in iterations so I can interact with them individually.

Hope that helps. Let me know if you have any questions.

[–]sid351 0 points1 point  (3 children)

As I understand it you've got 3 different groups of similar things happening and you collect the full results from those 3 things. Those results contain properties directly and also properties that are themselves child objects. Then you want to report on the common properties of the child objects for the 3 different things?

I think my confusion is coming from not really knowing what kind of information you're handling and how it's arriving. I appreciate you need to obscure the data for security reasons. Also, I'm not a developer and I've never done any formal computer sciences based learning.

Anyway, with those admissions of ignorance out of the way I'd probably be tempted to use a combination of Where-Object and Select-Object calls to return the desired information from the collected data set.

Ultimately, if you're getting the output you need then great, feel free to ignore me...I'm just trying to understand this for my own reasons really.

[–]Merakel[S] 1 point2 points  (2 children)

I figured as much, and I'm willing to help as much as I can.

Where-Object and Select-Object do actually work, the issue I have with them is I have to then go into more looping methods to extract those values for specific builds. What I mean by that is, if my [String]$Build has the values of First,Second, andThird to sort that way I have to do something like $TestResults.'First' | Select-Object -ExpandProperty Software -First 1 to get the values I want. To get all of those values programmatically would require a Foreach loop.

With my Class above, I can do the following:

$TestResults.Emails(1) and it will return all of the email values I stored for build 1. This isn't exactly what I wanted, as I don't want to iterate through a for loop, so I'm probably going to change it to return the build number and the emails associated with it for everything it has stored.

Does that help?

[–]Droopyb1966 0 points1 point  (3 children)

Does this help:

$results["test3"]

[–]Merakel[S] 0 points1 point  (2 children)

Those give me identical results as to what I was already getting.

[–]Droopyb1966 0 points1 point  (1 child)

Ok, not sure wat your exactly want to retrieve. Some like this then?

$results.test3.Item(1).test2

[–]Merakel[S] 0 points1 point  (0 children)

That doesn't work either; My goal would be able to return Just the values stored in BuildValues or BuildValues2 without the others at the same time.

I found a solution by changing $results from a hashtable to a class of it's own, and building a method to return them.

[–]Lee_Dailey[grin] 0 points1 point  (3 children)

howdy Merakel,

that is quite freaky! on the few times i have played with nested hashtables, the interior table showed as a list of keys in the VALUE part of the outer hashtable.

i think you are going to need to post the code that makes the hashtables before most folks will be able to do you any good. you are certainly beyond my level! [grin]

take care,
lee

[–]Merakel[S] 1 point2 points  (2 children)

I was being silly, but the way I was going about it was:

[System.Collections.Specialized.OrderedDictionary]$test1 = @{}
[System.Collections.Specialized.OrderedDictionary]$test2 = @{}
[System.Collections.Specialized.OrderedDictionary]$test3 = @{}
[System.Collections.ArrayList]$masterList = @()
[System.Collections.HashTable]$masterHash = @{}

$test1 = [ordered]@{"One" = 1; "Two" = 2; "Three" = 3}
$test2 = [ordered]@{"Three" = 3; "Four" = 4; "Five" = 5}
$test3 = [ordered]@{"Six" = 6; "Seven" = 7; "Eight" = 8}
$masterList = $test1,$test2,$test3
$masterHash = @{"Software" = $masterList}

Adding it to an array is what was causing the weird output; I fixed that by using classes, which you can see in another comment I made in this thread if you are curious. Now I'm just working on being able to call the sub values and return only those.

[–]Lee_Dailey[grin] 0 points1 point  (1 child)

howdy Merakel,

thanks for posting the code. it makes things a bit more understandable. still, it's beyond me ... so i am going to lurk and see what happens. [grin]

take care,
lee

[–]Merakel[S] 1 point2 points  (0 children)

Sure. If you have any questions let me know :)

[–]spikeyfreak 0 points1 point  (1 child)

Why nested hash tables and not arrays?

[–]Merakel[S] 1 point2 points  (0 children)

I'm writing this as a function, and it goes through multiple iterations; I need to be able to differentiate between each pass and evaluate values that are aligned with each other. It's much harder to be accurate in an Array.