powershellpowershell-7.2

Powershell create New-Variable from foreach loop to be used outside of the loop


So I am pulling in an array and then cleaning it to just the unique values I need and then running that though a foreach loop to create

$ZoneArray = Import-Csv -Path "Test.csv" | select Zone
$Zones = @()
foreach ($Zone in $ZoneArray){
        $Zones += $Zone.Zone
}
$Zones = $Zones | select -Unique

foreach ($ZonesTest in $Zones){
            Set-Variable -Name "Zone$_" -Value $ZonesTest -Force
    
            New-UDTab -Text $ZonesTest -Content {
                    New-Variable -Name 'CurrentZone'
                    New-UDmuButton -Id 'Zone1Test' -Text ( + " On") -Variant contained -FullWidth -OnClick {
                            Show-UDToast -Message "Starting" -Duration 1000 -Position center
                            $ZoneFullArray = $FullArray | Where-Object Zone -eq $ZonesTest
                            foreach ($ZoneFullArrayTest in $ZoneFullArray){
                                    Set-UDButtonStateChange -Id 'Zone1Test' -Text $ZoneFullArrayTest.ReceiverIPAddress
                                    Start-Sleep -Milliseconds 1000
                            }
                    }
            }
    }

Using Set-Variable -Name "Zone$_" -Value $ZonesTest -Force I am able to call the correct value while it is running. I have tried using

$Q=1
Set-Variable -Name "Zone$Q" -Value $ZonesTest -Force`
$Q++

But then I don't know how to dynamically call back the correct $Zone$Q for the later button press.

Is there anyway to program a dynamic variable that remembers the state it was made and then I can recall it later without knowing it's name? I know that sounds really confusing.

Ideas?


Edit:

I am banging my head against the wall. I know that the $ZoneFullArray = ... and foreach ($ZoneFullArrayTest in $ZoneFullArray){... is what is breaking it but can't think of another way to write it. The problem I am trying to solve with the second foreach to create a button dynamically based off the CSV table and then pull the value of the IP addresses that match the main row value making $Zones. The issue is that the code within the button is not run until it is pressed so it is hard to write them dynamically.


Solution

  • As iRon points out, variable indirection (referring to variables indirectly, via dynamically created variable names) is best avoided - see this post.

    It sounds like what you're really looking for are script-block closures that lock in then-current variable values in each iteration of a loop, along the following lines:

    # Sample input zones.
    $zones = 'foo', 'bar', 'baz'
    
    # Create a script block with a closure for each zone.
    $scriptBlocks = 
     foreach ($zone in $zones) {
       # .GetNewClosure() locks in the iteration-specific value of $zone
       { "This zone: $zone" }.GetNewClosure()
     } 
    
    # Execute the script blocks to demonstrate that the values where
    # captured as intended.
    $scriptBlocks | ForEach-Object { & $_ }
    

    Output:

    This zone: foo
    This zone: bar
    This zone: baz