0
$logDate = Get-Date
$codeBlockId = "NOTHING"
$addToCodeRunLog = Write-Host "However, inside addToCodeRunLog, codeBlockId is $codeBlockId. This line comes second"

function addCodeBlockLogs {
Write-Host "inside CodeBlockLogs, the value of codeBlockID is $codeBlockId. This line comes first."
$addToCodeRunLog
}

function deviceInfoLog {
$codeBlockId = "1002"
addCodeBlockLogs
}

deviceInfoLog

Returns:

However, inside addToCodeRunLog, codeBlockId is NOTHING. This line comes second
inside CodeBlockLogs, the value of codeBlockID is 1002. This line comes first.
  1. Why does the value of $codeBlockID not get changed when $addCodeToRunLog is called from the function?
  2. Why does is return the value of $addCodeToRunLog before returning the Write-Host value of the previous line?
0

2 Answers 2

2
  1. 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.


  1. 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'
      
Sign up to request clarification or add additional context in comments.

1 Comment

Thanks. I actually modified the code to include Write-Host as a way to simplify it for SO, but I suspect the same rules apply to the original. Thank you for your comprehensive answer. Very useful!
1

I believe it's because $addCodeToRunLog is declared as a variable rather than a function. I fixed it by changing it to:

$logDate = Get-Date
$codeBlockId = "NOTHING"
function addToCodeRunLog {
 Write-Host "However, inside addToCodeRunLog, codeBlockId is $codeBlockId. This line comes second"
}

function addCodeBlockLogs {
Write-Host "inside CodeBlockLogs, the value of codeBlockID is $codeBlockId. This line comes first."
addToCodeRunLog
}

function deviceInfoLog {
$codeBlockId = "1002"
addCodeBlockLogs
}

deviceInfoLog

1 Comment

I've restructured my answer to directly address your two questions. Using a function indeed avoids the problem, because it defers evaluation of the expandable string ("...") until the function is called, using the then-current variable value. The answer to the second question is that you mistakenly used Write-Host in your variable assignment, which prints immediately to the display and stores nothing in the variable.

Your Answer

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

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.