I am converting Pester tests from V4 to V5 and in line with the best practices, moving the loops from foreach() to Describe -ForEach{}. The tests are a standard set that checks if each function has comment based help and this requires multiple nested loops.
This question is similar to Pester 5 variable scoping and Working with nested foreach and I have referred to Data Driven Tests, but my problem goes deeper as firstly, I need multiple levels of nested loops and secondly, I need access to multiple variables. The first variable $helpParameterNames is used by the loop and the value of each row is checked to see if it exists in the second variable $parameterNames
V4
In V4, the arrays are accessible throughout the whole set of Describe/Context/It blocks so when I get to the last foreach loop, both $helpParameterNames and $parameterNames are accessible.
$commands = Get-Command -Module ModuleName
foreach ($command in $commands) {
    $commandName = $command.Name
    $help = Get-Help $commandName -ErrorAction SilentlyContinue
    
    Describe "Test help for $commandName" -Tag Help {
        
      <It Tests Removed>
        
        Context "Test parameter help for $commandName" {            
            $common = 'Debug', 'ErrorAction', 'ErrorVariable', 'InformationAction', 'InformationVariable', 'OutBuffer', 'OutVariable', 'PipelineVariable', 'Verbose', 'WarningAction', 'WarningVariable'
            $parameters = $command.ParameterSets.Parameters | Sort-Object -Property Name -Unique | Where-Object Name -notin $common
            $parameterNames = $parameters.Name
            $helpParameterNames = $help.Parameters.Parameter.Name | Sort-Object -Unique
            
            foreach ($parameter in $parameters) {
                $parameterName = $parameter.Name
                $parameterHelp = $help.parameters.parameter | Where-Object Name -EQ $parameterName               
                
                <It Tests Removed>
            }
            
            foreach ($helpParm in $helpParameterNames) {
                It "Should find parameter $helpParm in the function" {
                    $helpParm -in $parameterNames | Should Be $true
                }
            }
        }
    }
V5
In V5 as the setup code has to be defined in the BeforeDiscovery block, I can't get it to be available in the sub-blocks automatically. I can make it accessible by passing the array into the -ForEach as a HashTable, but then it will treat it as 1 object and not iterate over it, which is fine for $help, but not for $helpParameterNames
BeforeDiscovery {
    $commands = Get-Command -Module ModuleName
}
Describe "Help Rules" -Tags Build, Help -ForEach $commands {
    BeforeDiscovery {
        $commandName = $_.Name
        $common = 'Debug', 'ErrorAction', 'ErrorVariable', 'InformationAction', 'InformationVariable', 'OutBuffer', 'OutVariable', 'PipelineVariable', 'Verbose', 'WarningAction', 'WarningVariable'
        $parameters = (Get-Command $commandName).ParameterSets.Parameters | Where-Object -Property Name -NotIn $common | Sort-Object -Property Name -Unique
        $parameterNames = $parameters.Name
        $help = Get-Help $commandName -Full -ErrorAction SilentlyContinue
    }
    Context "General Rules for $commandName" -ForEach @{help = $help} {
        <It Tests Removed>
        Describe "Parameter Rules for <parameter.Name>" -Tags Help, Parameter -ForEach $parameters {
        
            BeforeAll {
                $parameter = $_.parameters
                $helpParameterNames = $help.Parameters.Parameter.Name | Sort-Object -Unique
                $parameterHelp = $help.parameters.parameter | Where-Object Name -EQ $parameter.Name
            }
            <It Tests Removed>
        }
        It "Should find parameter <helpParameter> in the function" -Tag Help, Parameter -ForEach $helpParameterNames {
            
            BeforeAll {
                $helpParameter = $_
            }
            $helpParameter -in $parameterNames | Should -BeTrue
        }
    }
How do I get the last -ForEach to have access to both $parameterNames from the BeforeDiscovery block and also $helpParameterNames from the parent loop?
                        
This is a unique situation and the solution is that some code has to be repeated both in
BeforeDiscoveryandBeforeAll. Adding the code toBeforeDiscoverymeans that it can be used in theContext -ForEachand adding the code toBeforeAllmeans that it is accessible as a single object inside the childDescribeblocks.