PowerShell script runs when pasted into the PowerShell window, but not when run from shortcut

To clarify:

  • It is perfectly fine to use Unicode (non-ASCII-range) quotation marks such as in PowerShell – see the bottom section.

  • However, in order to use such characters in script files, these files must use a Unicode character encoding such as UTF-8 or UTF-16LE (“Unicode”).

Your problem was that your script file was saved as UTF-8 without a BOM, which causes Windows PowerShell (but not PowerShell Core) to misinterpret it, because it defaults to “ANSI” encoding, i.e., the single-byte legacy encoding associated with the legacy system locale a.k.a language for non-Unicode programs (e.g., Windows-1252 in the US and Western Europe), which PowerShell calls Default.

While replacing the Unicode quotation marks with their ASCII counterparts solves the immediate problem, any other non-ASCII-range characters in the script would continue to be misinterpreted.

  • The proper solution is to re-save the file as UTF-8 with BOM.
  • It is a good habit to form to routinely save all PowerShell scripts (source code) as UTF-8 with BOM, because that ensures that they’re interpreted the same, irrespective of any given computer’s system locale.

To demonstrate the specific problem:

  • , the LEFT DOUBLE QUOTATION MARK (U+201C) Unicode character, is encoded as three bytes in UTF-8 format: 0xE2 0x80 0x9C.

  • You can verify this via the output from '“' | Format-Hex -Encoding Utf8 (only the byte sequence matters here; the printed characters. on the right are not representative in this case).

  • When Windows PowerShell reads this sequence as “ANSI”-encoded, it considers each byte a character in its own right, which is why you saw three characters for the single in your output, namely “.

  • You can verify this with [Text.Encoding]::Default.GetString([byte[]] (0xE2, 0x80, 0x9C)) (from PowerShell Core, use [Text.Encoding]::GetEncoding([cultureinfo]::CurrentCulture.TextInfo.ANSICodePage).GetString([byte[]] (0xE2, 0x80, 0x9C))).


Interchangeable use of ASCII-range and Unicode quotation marks, dashes, and whitespace in PowerShell:

In a properly encoded input file, PowerShell allows interchangeable use of the following quotation and punctuation characters; e.g., "hi", ”hi” and even "hi„ are equivalent.

Note:

  • Important: The above describes interchangeable syntactic use of these characters; if you use such characters in identifiers (which you shouldn’t) or in strings[1], they are not treated the same.

  • The above was in part gleaned from the source code on GitHub (class SpecialCharacters in file parserutils.cs).


[1] There are limited exceptions: given that PowerShell’s -eq operator compares string using the invariant culture rather than performing ordinal comparison, space-character variations may be treated the same in string comparisons, depending on the host platform; e.g., "foo bar" -eq "foo`u{a0}bar" yields $true on macOS and Linux (but not Windows!), because the regular ASCII-range space is considered equal to the no-break space (U+00A0) there.

Leave a Comment