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?

mklement0
  • 382,024
  • 64
  • 607
  • 775

2 Answers2

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.

Joey
  • 344,408
  • 85
  • 689
  • 683
  • $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. –  Mar 14 '17 at 12:21
  • 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.) – Joey Mar 14 '17 at 12:57
-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}         
Kirill Pashkov
  • 3,118
  • 1
  • 15
  • 20
  • 2
    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`. – Joey Mar 14 '17 at 10:55
  • 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. – Kirill Pashkov Mar 14 '17 at 11:13
  • 1
    Here's the PowerShell team's perspective: [Invoke-Expression considered harmful](https://blogs.msdn.microsoft.com/powershell/2011/06/03/invoke-expression-considered-harmful/) – mklement0 Nov 19 '18 at 13:00