- 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'