- Why does is return the value of $addCodeToRunLog before returning the Write-Host value of the previous line?
Because you're mistakenly using Write-Host
in your assignment:
# Write-Host prints *to the display*, it doesn't output to the *pipeline*.
# Therefore:
# * The message *prints instantly*
# * *Nothing* is stored in var. $addToCodeRunLog, because Write-Host
# produced *no success-output stream (pipeline) output*.
$addToCodeRunLog = Write-Host "However, inside addToCodeRunLog, codeBlockId is $codeBlockId. This line comes second"
See this answer for background information.
To instead store the string in your $addToCodeRunLog
variable, either replace Write-Host
with Write-Output
or, preferably, just assign the string directly:
$addToCodeRunLog = "However, inside addToCodeRunLog, codeBlockId is $codeBlockId. This line comes second"
However, this will still not do what you want, as discussed next.
- Why does the value of $codeBlockID not get changed when $addCodeToRunLog is called from the function?
Even if you fix your assignment as shown above, it uses the value of variable $codeBlockId
at the point when the assignment statement containing the "..."
string is executed, and "bakes it into" the string - that is how expandable (double-quoted) string ("..."
) work in PowerShell.
If you want to defer expansion (string interpolation) for on-demand interpolation based on the then-current variable value(s), you need to :
Either: Use string templating, where you define your string as a
verbatim (single-quoted) string ('...'
) and later call $ExecutionContext.InvokeCommand.ExpandString()
with it - see this answer (also shows an alternative with -f
).
Or: You can wrap your expandable string in a function - as shown in your own answer - which implicitly also defers expansion.
PowerShell's dynamic scoping ensures that the child scope in which your wrapper function executes sees the desired $codeBlockId
value from its parent scope - see the conceptual about_Scopes help topic.
Note: A variant solution based on the same principles would be to define your variable as a script block ({ ... }
), which you can invoke on demand with &
, the call operator, in order to perform on-demand expansion:
$addToCodeRunLog = { "`$foo = $foo" }
$foo = 1
& $addToCodeRunLog # -> '$foo = 1'
$foo = 2
& $addToCodeRunLog # -> '$foo = 2'