Reputation: 4502
I have a project where I'm trying to dynamically prepare a Powershell script, then write it out to a file for later execution.
Here's a minimal example of the issue:
# The string that I want to write out, having most special characters
$_output_str = "~@#$%&*()-_=+{}[]<>?/.,'`"``;!"
# Write it out directly
Write-Output "$_output_str"
This is putting a string with escaped special characters into a variable, then writing the value of that variable out to stdout. It works as expected:
~@#$%&*()-_=+{}[]<>?/.,'"`;!
Now, let's try storing that command in a file for later execution.
# The string that I want to write out, having most special characters
$_output_str = "~@#$%&*()-_=+{}[]<>?/.,'`"``;!"
# Turn it into a string command
$_cmd = "Write-Output `"$_output_str`""
# Write the command out to a file
"$_cmd" | Out-File "execution.ps1"
And now let's try executing that file:
powershell.exe .\execution.ps1
This throws an error:
At C:\{MYPATH}\execution.ps1:1 char:43
+ Write-Output "~@#$%&*()-_=+{}[]<>?/.,'"`;!"
+ ~
The string is missing the terminator: ".
+ CategoryInfo : ParserError: (:) [], ParseException
+ FullyQualifiedErrorId : TerminatorExpectedAtEndOfString
OK, so let's look at the content that was written to the file. This is what execution.ps1
contains:
Write-Output "~@#$%&*()-_=+{}[]<>?/.,'"`;!"
Notice that the "
and the backtick near the end of the string are no longer escaped. So for some reason, when creating the $_cmd
string, it got rid of my escape sequences.
How can I prevent this from happening?
Upvotes: 3
Views: 1410
Reputation: 10333
Use single-quoted here-string for the value so it doesn't get expanded.
$_output_str = @'
~@#$%&*()-_=+{}[]<>?/.,'"`;!
'@
You can also use regular single-quoted strings but keep in mind that you'll have to double any single-quote part of the string.
# The single quote is escaped by doubling it, meaning the final
# representation will be slightly different
$_output_str = '~@#$%&*()-_=+{}[]<>?/.,''"`;!'
# Actual value (the two '' were escaped into a single ')
# '~@#$%&*()-_=+{}[]<>?/.,'"`;!'
It is still better than double-quoted strings in any cases.
When you use a double-quoted strings, everything that can get evaluated get evaluated. Your backticks serves to escape the character right after but they are not part of the final representation of the string.
Double-quoted strings
A string enclosed in double quotation marks is an expandable string. Variable names preceded by a dollar sign ($) are replaced with the variable's value before the string is passed to the command for processing.
...
expressions are evaluated, and the result is inserted in the string.
I recommend you take a look at the official documentation for more information. About_Quoting_Rules
Upvotes: 2