powershellhashtablepowershell-7.2

How to access properties in a nested hashtable without explicitly stating the property names?


Let's say I have a 2-level nested hashtable like this:

$programs = @{


    program1 = @{
        DisplayName = "DisplayName1"
        Program = "C:\program1.exe"

    }

    program2 = @{
        DisplayName = "DisplayName2"
        Program = "C:\program2.exe"

    }

    }

now, without explicitly mentioning each of the property names like this:

$programs.program1['program']

I want to iterate over the hashtable like this:

foreach ($Name in $programs) {


$r = Get-NetFirewallRule -DisplayName $programs.Keys['DisplayName'] 2> $null; 
if (-NOT $r) { 
                         
New-NetFirewallRule -DisplayName $programs.Keys['DisplayName']  -Program $program.Keys['Program']
         
}

}

but I keep getting errors like:

 Cannot validate argument on parameter 'DisplayName'. The argument is null. Provide a valid value for the argument, and then try running the command again.
InvalidOperation: untitled:Untitled-2:29:13

what am I doing wrong?

what is the right way to access nested hashtable properties like this without explicitly mentioning their names? I want to know the synatx of it so that if I ever have a 3 or 4 level nested hashtables I can access them without specifying their exact names.

even if we ignore the foreach loop, how to only list all the "DisplayName" properties? what if the "DisplayName" properties were in a 4-level nested hashtable and we wanted to list them in the PowerShell console without specifying the exact names of the items that came before it?


Solution

  • Thanks to the comments from Santiago Squarzon and zett42, here is the syntax to access properties of deeply nested hashtables.

    $programs.Values.Values.Values and so on.
    

    I found it work perfectly.

    also, after reading foreach and as mentioned in the comments, I found that my code above was incorrect and the correct way is this:

    foreach ($Name in $programs.values.GetEnumerator()) {
    
    
    $r = Get-NetFirewallRule -DisplayName $Name.DisplayName 2> $null; 
    if (-NOT $r) { 
                             
    New-NetFirewallRule -DisplayName $Name.DisplayName -Program $Name.Program
             
    }
    
    }
    

    in a foreach loop, we have to use the variable we create in the parenthesis. my mistake was that I was using the collection itself again.