How can I escape a newline in .ps1 files? - powershell

I want to write a PowerShell script that includes a single command that is split over new lines, such as (the actual command I am trying to run is longer):
ssh \
-L 8080:localhost:8080 \
foo#bar.com
However the \ doesn't escape the new line (neither does /).

Use the backtick ( ` ), like this:
Write-Output `
"Hello world!"

Related

Convert a linux script to powershell script [duplicate]

I am following https://docs.docker.com/get-started/06_bind_mounts/#start-a-dev-mode-container on a Windows PC and am stuck here:
Run the following command. We’ll explain what’s going on afterwards:
docker run -dp 3000:3000 \
-w /app -v "$(pwd):/app" \
node:12-alpine \
sh -c "yarn install && yarn run dev"
If you are using PowerShell then use this command:
docker run -dp 3000:3000 `
-w /app -v "$(pwd):/app" `
node:12-alpine `
sh -c "yarn install && yarn run dev"
When using Command Prompt, I get errors (tried multiple variations as shown below), and when using PowerShell, I don't appear to get errors but am not running anything as showed when executing docker ps.
Note that I would rather use Command Prompt and not PowerShell as I could use Linux commands with ComandPrompt on my PC.
What is the significance of backslashes when using Dockers with Command Prompt (and tick marks with PowerShell for that matter)?
I have since found that docker run -dp 3000:3000 -w /app -v "%cd%:/app" node:12-alpine sh -c "yarn install && yarn run dev" works without errors (got rid of backslashes, put on one line, and used %cd% instead of $(pwd)), but would still like to know why using the exact script in the example results in errors.
Using Command Prompt
C:\Users\michael\Documents\Docker\app>docker run -dp 3000:3000 \
docker: invalid reference format.
See 'docker run --help'.
C:\Users\michael\Documents\Docker\app> -w /app -v "$(pwd):/app" \
'-w' is not recognized as an internal or external command,
operable program or batch file.
C:\Users\michael\Documents\Docker\app> node:12-alpine \
The filename, directory name, or volume label syntax is incorrect.
C:\Users\michael\Documents\Docker\app> sh -c "yarn install && yarn run dev"
sh: yarn: command not found
C:\Users\michael\Documents\Docker\app>docker run -dp 3000:3000 \ -w /app -v "$(pwd):/app" \ node:12-alpine \ sh -c "yarn install && yarn run dev"
docker: invalid reference format.
See 'docker run --help'.
C:\Users\michael\Documents\Docker\app>docker run -dp 3000:3000 -w /app -v "$(pwd):/app" node:12-alpine sh -c "yarn install && yarn run dev"
docker: Error response from daemon: create $(pwd): "$(pwd)" includes invalid characters for a local volume name, only "[a-zA-Z0-9][a-zA-Z0-9_.-]" are allowed. If you intended to pass a host directory, use absolute path.
See 'docker run --help'.
C:\Users\michael\Documents\Docker\app>
Using PowerShell
PS C:\Users\michael\Documents\Docker> docker run -dp 3000:3000 `
>> -w /app -v "$(pwd):/app" `
>> node:12-alpine `
>> sh -c "yarn install && yarn run dev"
849af42e78d4ab09242fdd6c3d03bcf1b6b58de984c4485a441a2e2c88603767
PS C:\Users\michael\Documents\Docker> docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
PS C:\Users\michael\Documents\Docker>
would still like to know why using the exact script in the example results in errors.
Because the command with the line-ending \ characters is meant for POSIX-compatible shells such as bash, not for cmd.exe
POSIX-compatible shells (sh, bash, dash, ksh, zsh):
use \ for line-continuation (continuing a command on the following line) and escaping in general.
use $varName to reference both environment and shell-only variables.
support $(...) for embedding the output from a command (...) in command lines (command substitution).
support both double-quoted ("...", interpolating) and single-quoted ('...', verbatim) strings; use '\'' to - in effect - include a ' inside '...'.
(Additionally, in bash, ksh, and zsh, there are the rarely used ANSI C-quoted strings, $'...', and, in bash and ksh, perhaps even more rarely, localizable strings, $"...").
cmd.exe:
uses ^ for line-continuation and escaping in general (in unquoted arguments only).
uses %varName% to reference environment variables (the only variable type supported).
doesn't support command substitutions at all.
supports only "..." strings (interpolating).
PowerShell:
uses ` (the backtick) for line-continuation and escaping in general.
uses $env:varName to reference environment variables, $varName to reference shell-only variables.
supports $(...), called subexpressions, the equivalent of command substitutions (outside of double-quoted strings, (...) is usually sufficient).
supports both double-quoted ("...", interpolating) and single-quoted ('...', verbatim) strings; use '' to embed a ' inside '...'.
Note: A common pitfall is that PowerShell has more metacharacters compared to both POSIX-compatible shells and cmd.exe, notably including # { } , ;, which therefore require individual `-escaping in unquoted arguments or embedding in quoted strings - see this answer.
Potential line-continuation pitfall: in all of the shells discussed, the escape character must be the very last character on the line - not even trailing (intra-line) whitespace is allowed (because the escape character would then apply to it rather than to the newline).
The information above is summarized in the following table:
Feature
POSIX shells                     _
cmd.exe                     _
PowerShell                     _
Line-continuation / escape character
Backslash (\)
Caret (^)
Backtick (`)
Double-quoted strings (interpolating)
✅
✅
✅
Single-quoted strings (verbatim)
✅
❌
✅
Get / set environment variables
$varName /export varName=...
%varName% /set varName=...
$env:varName /$env:varName = ...
Get / set shell-only variables
$varName/varName=...
❌ (no such variables exist, but you can limit the scope of env. vars. with setlocal)
$varName/$varName = ...
Command substitutions, subexpressions
$(...)
❌
(...) / $(...), esp. in strings
Note re setting variables with respect to whitespace on either side of the = symbol:
In POSIX-like shells, there must not be whitespace around =.
In cmd.exe, such whitespace is significant and becomes part of the variable / value name, and is therefore usually to be avoided.
In PowerShell, such whitespace is optional - you may use it to enhance readability; any string value to be assigned requires quoting (e.g., $var = 'hi!')
See also:
https://hyperpolyglot.org/shell for a much more comprehensive juxtaposition of these shells, though note that - as of this writing - the information about PowerShell is incomplete.
Sage Pourpre's helpful answer for links to the line-continuation documentation of the respective shells.
This is character escaping.
The X Character (\ for Bash, backtick for Powershell and ^ for Windows terminal )are used to remove any specific meanings to the next characters.
When used at the end of a line, this mean that the next character (The newline character) is completely ignored.
This keep the command essentially a one-line command from the point of view of the interpreter, but allow you to break it on multiple lines for better readability.
References
Powershell - About special characters
Escape sequences begin with the backtick character [`], known as the grave
accent (ASCII 96), and are case-sensitive. The backtick character can
also be referred to as the escape character.
Bash manual
3.1.2.1 Escape Character
A non-quoted backslash \ is the Bash escape character. It preserves the literal value of the next character that
follows, with the exception of newline. If a \newline pair appears,
and the backslash itself is not quoted, the \newline is treated as a
line continuation (that is, it is removed from the input stream and
effectively ignored).
How-to: Escape Characters, Delimiters and Quotes at the Windows command line
Escaping CR/LF line endings. The ^ escape character can be used to
make long commands more readable by splitting them into multiple lines
and escaping the Carriage Return + Line Feed (CR/LF) at the end of a
line:
ROBOCOPY \\FileServ1\e$\users ^ \\FileServ2\e$\BackupUsers ^ /COPYALL /B /SEC /MIR ^ /R:0 /W:0 /LOG:MyLogfile.txt /NFL /NDL
[...]
A couple of things to be aware of:
A stray space at the end of a line (after the ^) will break the
command, this can be hard to spot unless you have a text editor that
displays spaces and tab characters. If you want comment something out
with REM, then EVERY line needs to be prefixed with REM. Alternatively
if you use a double colon :: as a REM comment, that will still parse
the caret at the end of a line, so in the example above changing the
first line to :: ROBOCOPY… will comment out the whole multi-line
command.

How to escape # within a string in PowerShell?

I'm trying to send a HTML request via cURL in PowerShell. The code in question:
$command = 'curl -d #request.txt -o testoutput.xml -X "POST" -H #header.txt -u "username:password" "URL"'
Invoke-Expression $command
The HTML Body (-d) and Header (-H) need to be read from files, hence the # before the filenames.
In order for this to work, I need to escape the # so PowerShell doesn't interpret it as a splat operator - and that's my problem, nothing I've tried so far worked:
putting it in single quotes
here document (#" "#)
here string (#' '#)
using string templates with placeholders ("{0}request.txt" -f "#")
Unicode escape ("`u{0040}request.txt")
How do I escape the # correctly? Or am I on the wrong path entirely? (I'm new to PowerShell sorry)
Invoke-Expression (iex) should generally be avoided; definitely don't use it to invoke an external program or PowerShell script.
Therefore:
invoke curl directly
and quote PowerShell metacharacters such as # (see this answer for the full list) - either individually, with ` (e.g., `#), or by enclosing the entire argument in quotes ('...' or "...", as appropriate).
curl -d `#request.txt -o testoutput.xml -X "POST" -H #header.txt -u "username:password" "URL"
As for what you tried:
The primary concern about Invoke-Expression use is one of security: unwanted execution of (additional) commands potentially injected into the string passed to it.
In terms of functionality, Invoke-Expression is not only not needed for regular calls to external programs, it can create quoting headaches.
However, given that you're passing a '...' string to Invoke-Expression, quoting the # as `# would have worked, as shown in this simple example:
# OK, but generally do NOT do this.
Invoke-Expression 'Write-Output `#'
Had you used a "..." string, the ` would have been "eaten" by the up-front parsing of such an expandable string, based on the escaping rules explained in the conceptual about_Quoting_Rules help topic:
# BREAKS, because the ` is stripped before Invoke-Expression sees it.
Invoke-Expression "Write-Output `#"

How to use istool command in perl system() function

I am trying to put below command in perl system() function.But getting so many compilation errors (syntax).
./istool export -domain serviceshost:9080 -u dsadm -p password -ar test.isx -pre -ds '-base="ENGINEHOST/Dev_Project" Jobs/Batch/\*.*'
I was using it like in perl:
system("./istool export -domain serviceshost:9080 -u dsadm -p password -ar test.isx -pre -ds '-base="ENGINEHOST/Dev_Project" Jobs/Batch/\*.*'");
can some one guide me exactly how to use it in system function?I tried escaping . also with backslash(\) in front of it.
Replace system with print, and it's obvious you didn't build the string correctly.
If you want to include a " in a string quoted with ", you need to escape it.
If you want to include a \ in a double-quoted string, you need to escape it.

Passing value from TK to a file and replacing a variable

I am trying to interface between tk and cshell-script.
I am able to collect data using tk:
label .firstColumn.s.variable.label -text "myFirstVariable" -background $color3
entry .firstColumn.s.variable.entry -textvariable program
But when I try to run the command it does not work
button .secondColumn.o.buttons.go -text "Run Now" \
-command "exec sed -i {s/ABC/$myFirstVariable/g} runme.sh \
>! runmeNow.sh ; ./runmeNow"
It changes ABC to blank in runmeNow.sh file.
Is there any better way to achieve it?
I want to replace a place-holder predefined in cshell-script (runme.sh). My place holder is ABC. Then I want to pipe it to a different file, then run this file. runme.sh has UNIX based run file.
Seems to me that tk is interpreting $myFirstVariable as a variable of its own, while you'd like it to be forwarded to shell. Escaping the dollar sign with a backslash may not be enough: exec is a Tcl command and doesn't use a shell, so we may have to call one to expand shell variable:
button .secondColumn.o.buttons.go -text "Run Now" \
-command "exec /bin/sh -i {sed "s/ABC/$myFirstVariable/g" runme.sh \
> runmeNow.sh ; ./runmeNow.sh}"

SED substitution for variable

I have a file named check.txt which has the below contents:
$ cat check.txt
~/bin/tibemsadmin -server $URL-user $USER -password $PASWRD
$
I have a main script where the values of $URL, $USER, $PASWRD are obtained from the main script. I want to use the SED utility to replace the $URL, $USER, $PASWRD to the actual values in the check.txt.
I am trying like this but it fails.
emsurl=tcp://myserver:3243
emsuser=test
emspasswd=new
sed s/$URL/${emsurl}/g check.txt >> check_new.txt
sed s/$USER/${emsuser}/g check.txt_new.txt >> check_new_1.txt
sed s/PASWRD/${emspasswd}/g check_new_1.txt >> final.txt
My final.txt output is desired as below:
~/bin/tibemsadmin -server tcp://myserver:3243 -user test -password new
Could you please help me?
You have to be rather careful with your use of quotes. You also need to learn how to do multiple operations in a single pass, and/or how to use pipes.
emsurl=tcp://myserver:3243
emsuser=test
emspasswd=new
sed -e "s%\$URL%${emsurl}%g" \
-e "s%\$USER%${emsuser}%g" \
-e "s%\$PASWRD%${emspasswd}%g" check.txt >final.txt
Your problem is that the shell expanded the '$URL' in your command line (probably to nothing), meaning that sed got to see something other than what you intended. By escaping the $ with the \, sed gets to see what you intended.
Note that I initially used / as the separator in the substitute operations; however, as DarkDust rightly points out, that won't work since there are slashes in the URLs. My normal fallback character is % - as now shown - but that can appear in some URLs and might not be appropriate. I'd probably use a control character, such as control-A, if I needed to worry about that - or I'd use Perl which would be able to play without getting confused.
You can also combine the three separate -e expressions into one with semi-colons replacing them. However, I prefer the clarity of the three operations clearly separated.
You could take a slightly different approach by modifying your main script as follows :-
export URL="tcp://myserver:3243"
export USER=test
export PASWRD=new
. ./check.txt
This sets up the variables and then runs check.txt within the context of your main script
Although you don't say what's failing I guess I see the problems.
I suggest you do this:
sed "s|\$URL|${emsurl}|g"
That is, the first $ needs to be escaped because you want it literally. Then, instead of / I suggest you use | (pipe) as delimiter since it's not used in your strings. Finally, use " to ensure the content is interpreted as string by the shell.
You can then pipe everything together to not need any temporary files:
sed "s|\$URL|${emsurl}|g" | sed "s|\$USER|${emsuser}|g" | sed "s|\$PASSWRD|${emspasswd}|g"
Variable substitution should be outside sed expression and '$' should be escaped; in your case something like this:
sed -e 's/\$URL/'$emsurl'/g' -e 's/\$USER/'$emsuser'/g' -e 's/\$PASSWORD/'$emaspasswd'/g'
Anyway in your place I would avoid using $ to match placeholders in a template file, because it's causing confusion with BASH variables, use a different pattern instead (for instance #URL#).