I\'ll begin by confessing that I\'m a Powershell (and coding) noob. I\'ve stumbled my way through a few scripts, but I make no claims to anything even approaching competence
String interpolation (expansion) in "..."
and @"<newline>...<newline>"@
strings happens instantly, with the values that the referenced variables contain at that time getting used.
As a result, the same string - whose value was determined before the loop - is output in each iteration of your foreach
loop.
Your use case calls for a templating approach, where string interpolation is deferred, to be invoked on demand with the then-current variable values, using $ExecutionContext.InvokeCommand.ExpandString()
[1]:
# Define the *template* string as a *literal* - with *single* quotes.
$xmlData = @'
<Invoice>
<InvoiceId>$InvID</InvoiceId>
<Timestamp>$Timestamp</Timestamp>
</Invoice>
'@
# ...
# ForEach ($file in $files) { ...
# Perform interpolation *on demand* with $ExecutionContext.InvokeCommand.ExpandString()
Add-Content $Manifest -Value $ExecutionContext.InvokeCommand.ExpandString($xmlData)
# }
Note:
Variable references can also be embedded by explicitly delineating the variable names via enclosure in {...}
, e.g., ${InvID}
, which may situationally be required for disambiguation.
In order to embed expressions / command output, use $()
, the subexpression operator, as demonstrated below.
In order to embed verbatim $
instances, escape them as `$
.
A simple example:
# Define a template string, *single-quoted*, with *literal contents*:
# - '$InvID' is simply literally part of the string, not a variable reference (yet).
# - Ditto for $((Get-Date).TimeOfDay)
$strTempl = 'Invoice ID $InvID extracted at $((Get-Date).TimeOfDay).'
# Echo the template string as-is - unexpanded - ...
$strTempl
# ... and expand it on demand
$InvID = 1
$ExecutionContext.InvokeCommand.ExpandString($strTempl)
# ... and again, after assigning a different value to $InvID
$InvID = 2
$ExecutionContext.InvokeCommand.ExpandString($strTempl)
The above yields something like:
Invoice ID $InvID extracted at $((Get-Date).TimeOfDay). # template literal
Invoice ID 1 extracted at 11:38:12.2719300. # first on-demand expansion
Invoice ID 2 extracted at 11:38:12.2766010. # second on-demand expnsion
[1] Surfacing the functionality of the $ExecutionContext.InvokeCommand.ExpandString()
method in a more discoverable way via an Expand-String
cmdlet is the subject of this GitHub feature request.