When I run
Get-ItemProperty HKLM:\Software\Microsoft\Windows\CurrentVersion\Uninstall\* | Select-Object DisplayName, DisplayVersion, Publisher, InstallDate | Format-Table –AutoSize
directly from PowerShell, the code works just fine.
However, when I placed this exact code into file script.txt
and then run
$stdout = Invoke-Command -ScriptBlock ([ScriptBlock]::Create((Get-Content 'script.txt'))) *>&1
I received the following error:
Exception calling "Create" with "1" argument(s): "At line:1 char:163
+ ... me, DisplayVersion, Publisher, InstallDate | Format-Table –AutoSize
+ ~~~~~~~~~
The string is missing the terminator: "."
What causes this behavior? How do I have to adjust the code to be able to execute the script from the external txt file?
tl;dr
The implication is that you're using Windows PowerShell and that there is a character-encoding problem.
(The problem would not arise in PowerShell (Core) 7+, whose consistent default encoding is now (BOM-less) UTF-8.)
You have two solution options:
Either: Re-save your script.txt
file as UTF-8 with BOM.
Or: Use -Encoding utf8
with your Get-Content
call (note the bug alert below):
# Note the addition of -Encoding utf8.
# -Raw is added for robustness; it would be needed for *multiline* scripts.
Invoke-Command -ScriptBlock (
[ScriptBlock]::Create(
(Get-Content -Encoding utf8 -Raw 'script.txt')
)
) *>&1
A simpler alternative is to use Invoke-Expression
(whose use is generally best avoided, however):
Get-Content -Encoding utf8 -Raw 'script.txt' | Invoke-Expression *>&1
Bug alert:
When combining the above commends with redirection *>&1
, error output, specifically, disappears, i.e. it unexpectedly isn't merged into the success output stream (1
).
This applies to both Windows PowerShell (where it won't be fixed) and PowerShell (Core) up to at least v7.3.6; the relevant bug report is GitHub issue #10476.
A workaround is to enclose the Invoke-Command
call or the Invoke-Expression
pipeline in (...)
, the grouping operator before applying *>&1
, e.g.:
# Note the (...), which has side effects, however.
(Get-Content -Encoding utf8 -Raw 'script.txt' | Invoke-Expression) *>&1
The workaround has a side effect: Using (...)
means that all output from the enclosed command is collected in memory first, in full, before the redirection is applied and output is produced.
It looks like your script.txt
is UTF-8-encoded but lacks a BOM, which causes Windows PowerShell to misinterpret your file as ANSI-encoded (i.e., using the single-byte ANSI code page of your system's legacy locale).
It isn't obvious but your file contains a non-ASCII-range character:
It is the “
(LEFT DOUBLE QUOTATION MARK, U+201C
) - which PowerShell accepts as an alternative to the usual ASCII-range double quote, QUOTATION MARK, U+0022
- that causes the syntax error, because a closing double quote is missing.
Similarly, PowerShell accepts -
(EN DASH) in lieu of the ASCII-range -
.
For the complete list of interchangeable quotation and punctuation characters with syntactic function supported by PowerShell, see this answer.
However, for robustness it is generally better to use the ASCII-range characters.
The remedies in the top section avoid the problem.