5

I am trying to create a new variable that would use other variable with dynamic name as its value. Here's what I am trying to do:

I have a System.Array with two values:

$Years = 2015, 2016

Another variable, $Transactions has a list of various transactions.

I am trying to use each of those $Years values in the following way:

foreach ($Year in $Years){
   New-Variable -Name "Transactions_$Year" -Value $Transactions |
     Where {$_.Date -like "*.$Year"}
}

Now what I would like to do (within that same foreach loop) is to use that $Transactions_$Year value when I am creating a another new variable, like this:

New-Variable -Name "Income_$Year" -Value $Transactions_$Year |
  Where {$_.Amount -NotLike "-*"} | 
    Measure-Object Amount -Sum | Select -ExpandProperty Sum

Is this possible, or do you have any alternative ways how I could achieve this?

2 Answers 2

6

First of all, your New-Variable invocation doesn't do what you think it does, as you'd pipe the output of New-Variable to Where-Object instead of using the value of $Transactions | Where ... as value for the variable. You need parentheses for that to work:

New-Variable -Name "Transactions_$Year" -Value ($Transactions | Where {$_.Date -like "*.$Year" })

If you absolutely have to use this approach, then you can get the variables again via Get-Variable:

Get-Variable Transactions_$Year | % Value

However, multiple variables with magic names is a rather poor way of solving this. You probably rather want a map:

$TransactionsPerYear = @{}
$Years | ForEach-Object {
  $TransactionsPerYear[$_] = $Transactions | Where Date -like "*.$_"
}

And you can get all transactions for 2015 with $TransactionsPerYear[2015].

Another way is Group-Object which doesn't even require a list of possible years to begin with, but groups a number of objects by some property or expression result:

$TransactionsPerYear = $Transactions | Group-Object { [int]($_.Date -replace '.*\.') }

(This is a guess on how it could work. It seems like your date string contains something up to a period, after which there is the year and nothing else, so perhaps something like dd.MM.yyyy date format.

Sign up to request clarification or add additional context in comments.

2 Comments

$TransactionsPerYear = @{} $Years | ForEach-Object { $TransactionsPerYear[$_] = $Transactions | Where Date -like '*.$_' } I didn't get anything with this, it does not create the variables $TransactionsPerYear[2015] or $TransactionsPerYear[2016]. I also didn't really understand how I could use this in the second phase, where I want to get the income from each year into separate variable.
Those are not variables, just FYI. You're just making matters more confusing by calling things by different names. In any case, I forgot to use double quotes for the second example, that why it didn't work. It should work now. (Or just leave the quotes out at that point.)
-1

You want to use Invoke-Expression cmdlet. You need to create dynamic string expression of commands that would initialize variable with the value. Here's how you do it:

$Years = 2015, 2016, 2017, 2018
$Years | ForEach-Object { 
    $Year = $_
    Invoke-Expression ('$Year' + $Year + ' = "Year is ' + $Year + '"')
 }

Here's the output:

Get-Variable Year*

Name                           Value                                                                                                                                                                                                                             
----                           -----                                                                                                                                                                                                                             
Year                           2018                                                                                                                                                                                                                              
Year2015                       Year is 2015                                                                                                                                                                                                                      
Year2016                       Year is 2016                                                                                                                                                                                                                      
Year2017                       Year is 2017                                                                                                                                                                                                                      
Year2018                       Year is 2018                                                                                                                                                                                                                      
Years                          {2015, 2016, 2017, 2018}         

3 Comments

I'd say adding Invoke-Expression is just adding another very questionable element to an already questionable pattern here. Don't do it. New-Variable is a perfectly fine way of creating a variable without incurring the headaches that come with the need of properly escaping stuff to use in Invoke-Expression.
By using Invoke-Expression you can do really complex and flexable dynamic variables and values. Don't see anything bad of doing so. Yet another way to achieve the goal.
Here's the PowerShell team's perspective: Invoke-Expression considered harmful

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.