How to properly escape an ampersand in an execution statement - powershell

Quick question regarding the proper way to escape the ampersand in my statement below, which is just a command-line execution.
& $CmdLine -f:passwordFile.txt /A:Coreplan /U:admin /D:BalSheet /R:global_General_Assets_P&E
I have tried a number of different iterations of quotes with no luck.
Thanks in advance!

PowerShell's escape character is the backquote (`), so try changing /R:global_General_Assets_P&E to /R:global_General_Assets_P`&E:
& $CmdLine -f:passwordFile.txt /A:Coreplan /U:admin /D:BalSheet /R:global_General_Assets_P`&E
If that doesn't work: please update your question with the error message you're getting.

Ampersand does not require special escaping if it is in a single- or double-quoted string.
& $CmdLine -f:passwordFile.txt /A:Coreplan /U:admin /D:BalSheet '/R:global_General_Assets_P&E'
or
& $CmdLine -f:passwordFile.txt /A:Coreplan /U:admin /D:BalSheet "/R:global_General_Assets_P&E"
should work. This is assuming $cmdline contains just the path to an exe. Make sure $cmdLine does not contain any additional arguments...
And like Ansgar suggests, please provide the error details if these approaches don't work.

I am going to assume that $CmdLine is an executable or batch file you are wanting call and the rest of the line is the set of parameters you want to send to $CmdLine.
You can try something like this:
& $CmdLine "-f:passwordFile.txt" "/A:Coreplan" "/U:admin" "/D:BalSheet" "/R:global_General_Assets_P&E"

Related

sqlplus - No characters are allowed after a here-string header but before the end of the line

I'm trying to use sqlplus to do an Oracle query for the first time in a PowerShell script. I get this error message:
At line:1 char:73
+ ... user/pw#RRRPRD.company.net:1521/RRRPRDC #"C:\Users\ ...
+ ~
No characters are allowed after a here-string header but before the end of the line.
It seems to be pointing to the C: after #". Any ideas? I seem to be doing what is at this example. I get the same error when I try to do echoargs of the connection info.
This is my powershell code I am testing at the command line since it hangs forever running the program:
sqlplus user/pw#RRRPRD.company.net:1521/RRRPRDC #"C:\Users\me\Documents\2021\temp endToEnd\short.sql"
This is using powershell 5.1. Any ideas? I see here string header, but since I am following the example that was accepted in the link for sqlplus above, it's unclear to me what's wrong with it.
Replace
#"C:\Users\me\Documents\2021\temp endToEnd\short.sql"
with any of the following:
`#"C:\Users\me\Documents\2021\temp endToEnd\short.sql"
"#C:\Users\me\Documents\2021\temp endToEnd\short.sql"
'#C:\Users\me\Documents\2021\temp endToEnd\short.sql'
Note: Using a verbatim (single-quoted) string ('...') is arguably the best choice here, given that the path contains no variable references; if it did, a expandable (double-quoted) string ("...") would be equired.
All variations end up passing the following string verbatim to sqlplus, which I presume is your intent:
#C:\Users\me\Documents\2021\temp endToEnd\short.sql
Presumably, you're trying to pass # as a verbatim part of an argument to sqlplus - a common convention among CLIs is to use #<file-path> to request that argument data be taken from a file rather than using the argument value itself.
However, unlike in other shells, # is a metacharacter in PowerShell that serves a variety of purposes.
Thus, a # that should be a verbatim character at the start of an argument must either be escaped (with `) or part of a quoted string, as shown above. See the conceptual about_Special_Characters help topic.
If an unescaped argument-initial # is followed by " or ', PowerShell thinks you're trying to create a here-string, which has special, multi-line syntax requirements; the error message indicates that they're not met.

How do I run this in Powershell?

Here is the command that works in command prompt.
C:\Temp\Agent.exe CustomerId={9c0-4ab1-123-102423a} ActivationId={9c0-4ab1-123-102423a} WebServiceUri=https://Agent/
Here is the error. (I have tried invoke-command and arguments but I think the { is causing issues.
Error:
Agent.exe: The command parameter was already specified.
You are certainly not required to use Start-Process (although it may "work," with some limitations, in some scenarios). The simplest and most straightforward answer is to quote the arguments:
C:\Temp\Agent.exe 'CustomerId={9c0-4ab1-123-102423a}' 'ActivationId={9c0-4ab1-123-102423a}' 'WebServiceUri=https://Agent/'
If the executable you want to run is in a path that contains spaces (or the executable filename itself contains spaces), quote the command and use the & (call/invocation) operator; e.g.:
& 'C:\Temp Dir\Agent.exe' 'CustomerId={9c0-4ab1-123-102423a}' 'ActivationId={9c0-4ab1-123-102423a}' 'WebServiceUri=https://Agent/'
Remarks:
If you need string interpolation (i.e., automatic expansion of $variable names inside strings), then use " instead of ' as your quote character. Use ' instead of " (as in the examples above) to prevent string interpolation.
Parameter quoting in this case is required because the { and } symbols have special meaning in PowerShell.
The proper way to run external programs is to use Start-Process. It gives you a couple of additional options like a separate ArgumentList parameter, running-as another user, or redirecting outputs:
Start-Process -FilePath 'C:\Temp\Agent.exe' -ArgumentList #(
# Arguments are space-separated when run. You could also just use one big string.
'CustomerId={9c0-4ab1-123-102423a}',
'ActivationId={9c0-4ab1-123-102423a}',
'WebServiceUri=https://Agent/'
)

Build up a string to be passed to call operator

I need to build a string that is actually a command-line, and then execute the contents of that command-line. I'd hoped the call operator (&) would help, but it appears not. Here is a simple contrived example. The following works as expected, it pings a website:
$command = "ping"
$website = "www.bbc.co.uk"
& $command $website
however if I change it to this:
$command = "ping"
$website = "www.bbc.co.uk"
$cmd = "$command $website"
& $cmd
I get an error:
The term 'ping www.bbc.co.uk' is not recognized as the name of a
cmdlet, function, script file, or operable program.
Is there a way to dynamically build up a command-line as a string, and then execute it?
Yes, but you need to use Invoke-Expression (which is just like eval), instead of the call operator. Note that you also need to ensure that all your quoting is correct in that case. E.g.
$cmd = "'$command' '$website'"
would work in your trivial example, unless $command or $website contained single quotes. The problem here is essentially that everything you put into the string is subject to the usual parsing rules of PowerShell.
Generally, if you can, stay as far away from Invoke-Expression as you can. There are a few problems that need it, but invoking external programs ... not so much.
A much better alternative, especially if you have an arbitrary number of arguments, is to just collect the arguments in an array and use the splat operator (note the # in the code example below):
$command = 'ping'
$arguments = '-t','www.bbc.co.uk'
&$command #arguments
This ensures that arguments are properly quoted when necessary and generally avoids a lot of headaches you're going to get with Invoke-Expression.
(Side note: Whenever you have a problem in PowerShell and think »Oh, I'm just going to use a string«, it's often time to rethink that. This includes handling file names, or command lines. PowerShell has objects, reducing it to the capabilities of earlier shells just yields the same pain you have elsewhere too, e.g. multiple levels of escaping, sometimes with different syntaxes, etc. And most of the time there are better ways of solving the problem.)

Command line passing quotes within quotes

I've been searching for a solution to this but couldn't find one. Not sure if its possible.
Can I pass into command-line execution that passes a in a bat file which has an input file as its arguments?
So from the command-line it'll look like this:
C:\run.exe "C:\space folder\run.bat "C:\space folder\input.txt""
The problem is with the folders that has spaces so the
quotes are required to be in there.
Try this:
C:\run.exe "C:\space folder\run.bat \"C:\space folder\input.txt\""
And here is a link that you can see all escape characters
http://www.robvanderwoude.com/escapechars.php
I know it's an old topic, but I found the answer and would like to share.
In Windows you don't have to escape the quotes. Just use them normally.
In this case:
C:\run.exe ""C:\space folder\run.bat" "C:\space folder\input.txt""
In the end, all I needed was quotes.
winrs -r:MACHINE001 ""C:\Program Files\MyApp\My App.exe" -x "LOTS OF PARAMETERS""

Powershell remove quotes when start process

Let's look at the code below
$SBK="0x1682CCD8 0x8A1A43EA 0xA532EEB6 0xECFE1D98"
./windows/nvflash/nvflash.exe --sbk 0x1682CCD8 0x8A1A43EA 0xA532EEB6 0xECFE1D98
./windows/nvflash/nvflash.exe --sbk "0x1682CCD8 0x8A1A43EA 0xA532EEB6 0xECFE1D98"
./windows/nvflash/nvflash.exe --sbk $SBK
I have define a string var $SBK and then I'm going to pass it for some app. The first process call is working properly. The second one fails and therefore application doesn't accepts quotes. But the third call is failed too with the same error. It seems that powershell passes quotes, those are causing errors. But how to eliminate them? Thanks beforehand.
Try doing
iex "./windows/nvflash/nvflash.exe --sbk $SBK"
Also, get echoargs.exe from PowerShell Community Extensions to see how args are passed from Powershell to commands etc.
You should probably not use Invoke-Expression (see This Post from the PowerShell Team)
Instead, you can create an array of arguments, and then pass them using the call operator. See this post of mine on the subject for more details.
In your case, it would look something like this:
$SBKArgs="--sbk", "0x1682CCD8", "0x8A1A43EA", "0xA532EEB6", "0xECFE1D98"
$cmd = Get-Command ./windows/nvflash/nvflash.exe
& $cmd $sbkargs
Hope this Helps