PowerShell setting environment variable to subexpression discards newline

Question:

I have a python script:

# temp.py
print("foonbar")

I can run this in powershell:

> python .temp.py
foo
bar

I want to set the environment variable FOO to the output of this python script. However, doing so changes the newline to a space:

> $env:FOO=$(python .temp.py)
> $env:FOO
foo bar

What I’ve Tried

Verify that environment variables can contain newlines:

> echo "foo`nbar"
foo
bar
> $env:FOO2=$(echo "foo`nbar")
> $env:FOO2
foo
bar

… so it seems like the issue has something to do with execution of a python script?

Verify that the subexpression operator $() is not modifying the python script output:

> $(python .temp.py)
foo
bar

echoing the output of the python script seems to exhibit the same behavior:

> echo "$(python .temp.py)"
foo bar

… but not if I exclude the quotes:

> echo $(python .temp.py)
foo
bar

Workaround

Base64 encoding the string bypasses bypasses this issue. However, I still wonder what could be causing this?

My powershell version is 5.1.22621.963

Asked By: kym

||

Answers:

Use the following:

$env:FOO = (python .temp.py) -join "`n"
  • PowerShell reports stdout output from external programs such as python line by line, which, when captured via $(...) or (...), results in an array of lines (for two or more lines).

  • If you try to assign the result as-is to an environment variable – which is invariably string-typed – PowerShell implicitly stringifies the array, which means that it joins its elements with a space as the separator, so that lines foo and bar turn into a string with verbatim content foo bar; that is, the newlines are replaced with spaces.

  • By explicitly joining the elements with a (LF-only) newline (expressed as "`n" via an expandable PowerShell string) using the -join operator, an explicit multi-line string is constructed up front, which can then be assigned to an environment variable.

Answered By: mklement0