PowerShell: String expansion in command mode - powershell

What are the rules of string expansion in command mode? If on cmd.exe, I would write this:
c:\asdoc.exe -doc-sources+=src
I need to convert this to a string where the actual source path ("src") is computed so somewhere above this line, $sourcePath = "src" is executed. Now I need to transform that cmd.exe command to PowerShell command. I have tried the following but it doesn't work:
& c:\asdoc.exe -doc-sources+=$sourcePath # does NOT work
& c:\asdoc.exe -doc-sources+="$sourcePath" # does NOT work
& c:\asdoc.exe -doc-sources+=($sourcePath) # does NOT work
I used the EchoArgs utility and it gives me these results:
Arg 0 is <-doc-sources+=$sourcePath> # case 1
Arg 0 is <-doc-sources+=$sourcePath> # case 2
Arg 0 is <-doc-sources+=> # case 3
Arg 1 is <src path>
How do I make the string expand "correctly" in this example?

If i understand you properly you want everything expanded and as a single argument. Try to "collect" the argument with quotes.
PS > $sourcepath = "src"
PS > & EchoArgs.exe "-doc-sources+=$($sourcePath)"
Arg 0 is <-doc-sources+=src>
So try this:
& c:\asdoc.exe "-doc-sources+=$($sourcePath)"
The example below will also works AS LONG as you want to expand a variable an not a property inside a variable (ex $myobject.sourcepath)
& c:\asdoc.exe "-doc-sources+=$sourcePath"

Related

How to escape these character in powershell [], "", |

I would like to pass the below entry to cmd line from PowerShell. What to do?
["192.168.10.1|443|Atulkatiyar|passw$h"]
How to write in PowerShell command and can execute in command line?
cmd --% /c ["192.168.10.1|443|Atulkatiyar|passw$h"]
--% is an escape sequence, everything after it is passed to the executable unmodified
cmd.exe /C "echo `[`"192.168.10.1`|443`|Atulkatiyar`|passw`$h`"`]"
It's unclear what you mean by "pass to cmd line".
From PowerShell's perspective, if you want the string in your question to be treated as a literal, simply enclose it in '...' (single quotes; enclose embedded single quotes, if any, as ''):
> '["192.168.10.1|443|Atulkatiyar|passw$h"]'
["192.168.10.1|443|Atulkatiyar|passw$h"]
If you want to pass this literal to cmd.exe, the standard command processor, the same applies:
> cmd /c echo '["192.168.10.1|443|Atulkatiyar|passw$h"]'
["192.168.10.1|443|Atulkatiyar|passw$h"]
That said, your string contains $h, which looks like a reference to a PowerShell variable - if you want that reference expanded (interpolated) first, a different approach is needed; in the following commands, string concatenation with binary operator + is used:
> $h = 'Hi!'
> ('["192.168.10.1|443|Atulkatiyar|passw' + $h + '"]' )
["192.168.10.1|443|Atulkatiyar|passwHi!"]
> cmd /c echo ('["192.168.10.1|443|Atulkatiyar|passw' + $h + '"]' )
["192.168.10.1|443|Atulkatiyar|passwHi!"]
Alternatively, and generally, you can use double-quoted strings to embed variable references ($<varName>) and subexpression ($(...)) that should be expanded (interpolated: replaced by their value) - in that event, use `(the backtick) to escape embedded " (and $ characters, if needed):
> "[`"192.168.10.1|443|Atulkatiyar|passw$h`"]"
["192.168.10.1|443|Atulkatiyar|passwHi!"]
> cmd /c echo "[`"192.168.10.1|443|Atulkatiyar|passw$h`"]"
["192.168.10.1|443|Atulkatiyar|passwHi!"]
Other options:
You can use the binary -f operator for string formatting, where the LHS contains placeholders such as {0} (the first operand) that are instantiated with the value on the RHS (based on the .NET framework's String.Format method - see also here):
> ('["192.168.10.1|443|Atulkatiyar|passw{0}"]' -f $h)
["192.168.10.1|443|Atulkatiyar|passwHi!"]
> cmd /c echo ('["192.168.10.1|443|Atulkatiyar|passw{0}"]' -f $h)
["192.168.10.1|443|Atulkatiyar|passwHi!"]
In PSv3+, as mentioned, the special --% "stop-parsing" switch allows you to pass the remaining parameters through to cmd.exe as-is, except for cmd.exe-style environment-variable references such as %PATH%; note that this means that PowerShell variable references and subexpressions are then not expanded.

Comma separate input parameters?

I have a script foo.cmd:
echo %1 %2
In PowerShell I run:
foo.cmd "a,b" "c"
Expected output: a,b c
Actual output: a b
Why?
The double quotes are removed after PowerShell parsed the command line and passes it to CMD for execution, so CMD actually sees a statement
foo.cmd a,b c
Since the comma is one of CMD's delimiter characters that statement is equivalent to
foo.cmd a b c
To avoid this behavior you need to ensure that the double quotes are preserved when passing the arguments to CMD. There are several ways to achieve this. For instance, you could put the double quoted arguments in single qoutes:
foo.cmd '"a,b"' "c"
and change the positional parameters in the batch script to %~1, %~2 so that CMD removes the double quotes from the arguments.
If you have PowerShell v3 or newer you can use the "magic parameter" --% to avoid the nested quotes:
foo.cmd --% "a,b" "c"
You still need %~1 and %~2 in the batch script, though.

How to install a Windows Service in Powershell when the commandline has quotes in it?

I have a service I need to install that has a commandline that looks something like this:
d:\My Service\service.exe /AsService /Config="d:\Config Files\TheConfig.config"
This is pretty much the worst-case scenario for a commandline. The issue I have is with the double quotes in the args.
This is what I've tried that is close but not quite:
$cmd = "create ""$ServiceName"" binPath= $FullServicePath start= $StartMethod"
Invoke-Expression "cmd.exe /c sc.exe $cmd" | Write-Host
Where $FullServicePath is:
d:\My Service\service.exe /AsService /Config="d:\Config Files\TheConfig.config"
Suggestions? I'm open to anything. WMI. Whatever.
Help!
If you're 100% sure that you need quotes, then you have to escape them with \:
&'d:\My Service\service.exe' '/AsService' '/Config=\"d:\Config Files\TheConfig.config\"'
Echoargs output:
Arg 0 is </AsService>
Arg 1 is </Config="d:\Config Files\TheConfig.config">
But probably this will work too and it's much easier:
&'d:\My Service\service.exe' #('/AsService', '/Config=d:\Config Files\TheConfig.config\')
Echoargs output:
Arg 0 is </AsService>
Arg 1 is </Config=d:\Config Files\TheConfig.config>
Try declaring $FullServicePath like this:
$FullServicePath = "d:\My Service\service.exe /AsService /Config=`"d:\Config Files\TheConfig.config`""
This uses the escape character ` to tell it to process the quotes as text. (The escape character is the back tic next to the 1 key on most keyboards)
I believe you can also use this syntax:
$FullServicePath = $('d:\My Service\service.exe /AsService /Config="d:\Config Files\TheConfig.config"')
Both created the variable without a problem on my system.
When you call the $FullServicePath do it like this: $($FullServicePath)
This is a method i used .
Installing a service in powershell

Using command line arguments in VBscript

How can I pass and access command line arguments in VBscript?
Set args = Wscript.Arguments
For Each arg In args
Wscript.Echo arg
Next
From a command prompt, run the script like this:
CSCRIPT MyScript.vbs 1 2 A B "Arg with spaces"
Will give results like this:
1
2
A
B
Arg with spaces
If you need direct access:
WScript.Arguments.Item(0)
WScript.Arguments.Item(1)
...

How to use the # character in PowerShell

I am trying to do the following - for each *.sql file in the current directory run
sqlplus username/password#connect_identifier_specified_in_argument #file_name
Here is what I have so far:
$scripts = dir *.sql
foreach($script in $scripts) {
Write-Host sqlplus username/password"#"$args "#"$script.Name
}
(I know Write-Host outputs it to the screen; I'm just trying to debug for now.)
However, there is something funky with how PowerShell treats the # character and when I run this I always get something like:
PS C:\code\scripts> C:\utils\run_sql_scripts_on.ps1 identifier
sqlplus username/password#identifier # ALERTS.sql
See that space after the "#"? What gives?
Escape the # with a backtick (`).
Write-Host sqlplus username/password`#$args `#$script.Name
PowerShell Community Extensions has a handy little utility (echoargs) for debugging this sort of problem:
5>echoargs username/password"#"$args "#"$script.Name
Arg 0 is <username/password#>
Arg 1 is <#>
Arg 2 is <test.txt>
Try escaping with a backtick:
6>echoargs "username/password`#$args" "`#$($script.Name)"
Arg 0 is <username/password#>
Arg 1 is <#test.txt>