Search code examples
powershellvariablessyntaxincrementindirection

Create an incrementing variable from 2 variables in PowerShell


OK, First I consider myself a newbie and have much to learn about PowerShell and this is my first post ever. I am trying to loop through some data and put it into a custom object and put them into separate arrays for later use. The issue is that I want to create a variable representing $week_data1 by using a counter $i so I can reduce the amount of code required. I do have a concatenated variable being written out: write-host '$week++ ='$week$i But I think it is being represented as a string? How can I get $week_data$i to represent the array to insert the data?

Input data. Each week ends on Saturday.
    $week1=@('2021-05-01')
    $week2=@('2021-05-02', '2021-05-03', '2021-05-04', '2021-05-05', '2021-05-06', '2021-05-07', '2021-05-08')
    $week3=@('2021-05-09', '2021-05-10', '2021-05-11', '2021-05-12', '2021-05-13', '2021-05-14', '2021-05-15')
    $week4=@('2021-05-16', '2021-05-17', '2021-05-18', '2021-05-19', '2021-05-20', '2021-05-21', '2021-05-22')
    $week5=@('2021-05-23', '2021-05-24', '2021-05-25', '2021-05-26', '2021-05-27', '2021-05-28', '2021-05-29')
    $week6=@('2021-05-30', '2021-05-31')
    $month =@($week1, $week2, $week3, $week4, $week5, $week6) 
    
Create the output structures to be populated.
    $week_data1=@()
    $week_data2=@()
    $week_data3=@()
    $week_data4=@()
    $week_data5=@()
    $week_data6=@()
    $month_data =@($week_data1, $week_data2, $week_data3, $week_data4, $week_data5, $week_data6)
Loop through the array and count the week number that is being processed.

    $i = 0
    foreach($week in $month)
    { $i++
    $n=0

Here I can write out a Variable and it concatenates properly.
    **write-host '$week++ ='$week$i**
        foreach($day in $week)
        {$n++
        write-host '$day ='$day
Pull in data from a .csv file to populate the custom object.
        foreach($line in $csv) 
         {
          if($line -match $day)
Match the line in the CSV file that has the correct Date in it. One line in the file per date in the month.
          { #write-host '$line.Day = ' $line.Day
            # custom object to be used later 
            $date_data = [PSCustomObject] @{
             week_numb = $i
             date = $line.Day
             attempts = $line.Attempts
             connects = $line.Connects
            }
I have tried different syntax versions but it does not work here? I want to put the custom object data into the new array for the week being processed. 
          #write-host '$week_data[$i]='$week_data[$i]
          $week_data$i += $date_data # Add data from csv file into a 
          #$week_data[$i] += $date_data
          }
         }
    
        }
    }

Issue using $week_data$i as a variable I get an error:

At line:38 char:17

  •   $week_data$i += $date_data # Add data from csv file into a
    
  •             ~~
    

Unexpected token '$i' in expression or statement. + CategoryInfo : ParserError: (:) [], ParentContainsErrorRecordException + FullyQualifiedErrorId : UnexpectedToken


Solution

  • You're looking for variable indirection, i.e. the ability to refer to a variable indirectly, by a name stored in another variable or returned from an expression.

    Note, however, that there are usually superior alternatives, such as using arrays or hashtables as multi-value containers - see this answer for an example.

    If you do need to use variable indirection, use Get-Variable and Set-Variable:

    $week_data1 = 'foo', 'bar'
    
    $i = 1
    
    # Same as: $week_data1
    # Note that "$" must NOT be specified as part of the name.
    Get-Variable "week_data$i" -ValueOnly
    
    # Same as: $week_data1 = 'baz', 'quux'
    Set-Variable "week_data$i" baz, quux
    
    # Updating an existing value requires nesting the two calls:
    # Same as: $week_data1 += 'quuz'
    Set-Variable "week_data$i" ((Get-Variable "week_data$i" -ValueOnly) + 'quuz')
    

    As an aside: "extending" an array with += is convenient, but inefficient: a new array must be created behind the scenes every time - see this answer.

    Similarly, calling cmdlets to set and get variables performs poorly compared to direct assignments and variable references.

    See this answer for applying the indirection technique analogously to environment variables, using Get-Content / Set-Content and the Env: drive.


    As for what you tried:

    • $week_data$i = ... is an assignment expression, which is interpreted as directly juxtaposing two variables, $week_data and $i, which causes the syntax error you saw.

    • By contrast, something like Write-Output $week_data$i is a command, and while $week_data$i is also interpreted as two variable references, as a command argument it is syntactically valid, and would simply pass the (stringified) concatenation of the two variable values; in other words: $week_data$i acts as if it were double-quoted, i.e. an expandable string, and the command is therefore equivalent to Write-Output "$week_data$i"