I created dynamic variable like this :
$Data = @()
$i = 1
Foreach ($S in $SB) {
New-variable "JR$i" "content"
New-variable "SN$i" "content"
New-variable "T$i" "content"
New-variable "FN$i" "content"
$i = $i++
}
My goal is to put them in a psobject as follow :
$Data += new-object psobject -property ([ordered]@{JR = "<tr><td>$JR$i</td>"; SN = "<tr><td>$SN$i</td>"; T = "<tr><td>$T$i</td>"; FN = "<tr><td>$FN$i</td>"})
$i = $i++
- this doesn't do what you think it does. You probably want $i++
or $i += 1
instead.
What your code is actually doing is complicated. The increment operator documentation says:
The postfix version of the operator increments a variable after its value is used in the statement.
In other words your code $i = $i++
does this:
$i
( = 1)$i
($i
now equals 2)$i
$i
now equals 1 again!You can try this yourself:
$i = 1;
$i = $i++;
$i
# 1
You can fix that by using one of these options instead of $i = $i++
:
$i++;
$i += 1;
$i = $i + 1;
In your New-Variable
lines, Powershell is doing string interpolation to create a variable named, e.g JR$i
-> JR1
, but in the second example <td>$JR$i</td>
is expanding two different variables - $JR
-> $null
(because $JR
isn’t defined) and $i
-> 1
rather than what you’re probably expecting which is $JR1
-> content
.
You can test this as well:
$i = 1;
New-Variable -Name "JR$i" -Value "content";
$JR1
# content
"<td>$JR$i</td>"
# <td>1</td>
It's clearer if you enable Strict Mode as you get an error instead:
Set-StrictMode -Version "Latest";
"<td>$JR$i</td>"
# InvalidOperation: The variable '$JR' cannot be retrieved because it has not been set.
What you want instead is "<td>$JR1</td>"
, but it looks like you need to dynamically generate the variable name because you're looping over multiple values for $i
, so you're going to be stuck doing this:
$i = 1;
$jr = (Get-Variable -Name "JR$i").Value;
"<td>$jr</td>"
# "<td>content</td>"
This one's easy - just use $i++
or $i += 1
instead
See @iRon's general best-practice advice mentioned in comments for some more background information - I'll apply this to your specific case below.
Instead of creating lots of "dynamic variables", just pack the values into a hashtable using the name as a key - it'll be easier to retrieve the values later...
$SB = @( 1, 2 )
$vars = [ordered] @{};
$i = 1
foreach( $S in $SB )
{
$vars.Add("JR$i", "content");
$vars.Add("SN$i", "content");
$vars.Add("T$i", "content");
$vars.Add("FN$i", "content");
$i++
}
$vars
# Name Value
# ---- -----
# JR1 content
# SN1 content
# T1 content
# FN1 content
# JR2 content
# SN2 content
# T2 content
# FN2 content
Note - strictly speaking, I'm using an OrderedDictionary instead of a hashtable so the keys get shown in the order they're added, but other than that they're basically the same.
And then to use the hashtable / ordereddictionary:
$i = 1;
foreach( $S in $SB )
{
"<tr><td>$($vars["JR$i"])</td>";
$i++
}
# <tr><td>content</td>
# <tr><td>content</td>
However, if you're just trying to generate the pscustomobjects, a cleaner way to do that from your source data might be this, and bypass the entire "dynamic variables" and temporary hashtables / OrderdDictionary completely:
# generate the source data
$SB = @(
@{
"JR_Property" = "jr content 1"
"SN_Property" = "sn content 1"
"T_Property" = "t content 1"
"FN_Property" = "fn content 1"
},
@{
"JR_Property" = "jr content 2"
"SN_Property" = "sn content 2"
"T_Property" = "t content 2"
"FN_Property" = "fn content 2"
}
);
$data = $SB | foreach-object {
[pscustomobject] @{
"JR" = "<tr><td>$($_.JR_Property)</td>";
"SN" = "<tr><td>$($_.SN_Property)</td>";
"T" = "<tr><td>$($_.T_Property)</td>";
"FN" = "<tr><td>$($_.FN_Property)</td>"}
}
$data | format-list *
# JR : <tr><td>jr content 1</td>
# SN : <tr><td>sn content 1</td>
# T : <tr><td>t content 1</td>
# FN : <tr><td>fn content 1</td>
#
# JR : <tr><td>jr content 2</td>
# SN : <tr><td>sn content 2</td>
# T : <tr><td>t content 2</td>
# FN : <tr><td>fn content 2</td>