I have a file hello.bat with the following code:
echo first: %1 and second: %2 > me.txt
I am trying to call this using powershell. When I pass the first parameter it works well:
start-process hello test
However when i try to pass the second parameter like this:
start-process hello test test2
I get this error:
Start-Process : A positional parameter cannot be found that accepts argument 'test2'
You can just try pass the arguments using a comma like this:
start-process hello test,test2
or
start-process hello "test test2"
If you want to know more you can read the documentation here.
I don't know why you're starting a command line from a command line but I think this should work:
Start-Process -FilePath $env:ComSpec -ArgumentList "/c hello.bat test test2"
Don't you think it's time to replace cmd with Powershell?
You might change your bat file as well:
echo %1 > me.txt
echo %2 >> me.txt
Related
In my machine , this location content , windows bat file. "D/too/w.bat". This bat file can run in cmd , like this w.bat I :/ o:/ In Powershell , can run like this "./w.bat i: o:/" . now I , need to run it using some automated .ps script. I try like bellow ,
#
function run--bat {
Write-host "run bat";
Start-Process -File "C:/t/w.bat" "i:/ o:/"
}
but i it not succes. need some expert help to resolve this .
Pass an argument list:
Start-Process C:\t\w.bat -ArgumentList 'i:\','o:\'
The comma operator builds arrays in PowerShell, so 'i:\','o:\' is a two-element array.
Start-Process will join the arguments with spaces in order to create the finalized command line. This means you could also pass both arguments as one string:
Start-Process C:\t\w.bat -ArgumentList 'i:\ o:\'
From w.bat's point of view there will be no difference.
To pass a value that contains spaces - such as a path - as a single argument, you need to wrap it in double quotes:
Start-Process C:\t\w.bat -ArgumentList '"i:\something\with spaces"','o:\'
Then w.bat will see two arguments:
%1 = "i:\something\with spaces" (and %~1 = i:\something\with spaces)
%2 = o:\
Ive got a very basic powershell script which uses Start-Process to start another .sh script, this is working and the scripts do execute but what I need is to be able to capture the output of the called script.
Content of the scripts is below:
main.ps1
Start-Process 'C:\Program Files\Git\git-bash.exe' -ArgumentList '-- C:\test\sub.sh' -Wait -RedirectStandardOutput output.txt
sub.sh
#!/bin/bash
echo "Hello World"
The sub.sh launches and prints out Hello World in its own console, but I really need the output to either go to the calling powershell scripts console window, or to a file. The file I specify in the -RedirectStandardOutput parameter is created, but is empty.
How can I get the sh script to print to standard out to the calling script?
Thank you
git-bash is in a different world than powershell so you can not directly redirect output or use -RedirectStandardOutput.
As you supposed, you can use an temporary file but the trick is to use internal bash operand ">" to redirect output to the file from bash process :
#!/bin/bash
echo "Hello from bash World" > /c/test/tempFile.txt
Then call it from powershell, you might hide the window also :
Start-Process 'C:\Program Files\Git\git-bash.exe' -ArgumentList C:\test\sub.sh -Wait -WindowStyle Hidden
$s = Get-Content c:\test\tempFile.txt
Write-Host "s=$s"
Remove-Item c:\test\tempFile.txt
Note : You have to specifilly fully qualified path.
Another option might be using Windows 10 own bash interpreter : https://stackoverflow.com/a/44359679/11867971
As written in sub.sh, the program to execute sh files is /bin/bash, not git-bash.exe.
$output = & 'C:\Program Files\Git\usr\bin\bash.exe' C:\test\sub.sh
$output
Hello World
Given:
# test1.ps1
param(
$x = "",
$y = ""
)
&echo $x $y
Used like so:
powershell test.ps1
Outputs:
> <blank line>
But then this goes wrong:
test.ps1 -x "Hello, World!" -y "my friend"
Outputs:
Hello,
my
I was expecting to see:
Hello, World! my friend
Well, this is a cmd.exe problem, but there are some ways to solve it.
Use single quotes
powershell test.ps1 -x 'hello world' -y 'my friend'
Use the -file argument
powershell -file test.ps1 -x "hello world" -y "my friend"
Create a .bat wrapper with the following content
#rem test.bat
#powershell -file test.ps1 %1 %2 %3 %4
And then call it:
test.bat -x "hello world" -y "my friend"
One can use a backtick ` to escape spaces:
PS & C:\Program` Files\\....
A possible solution was in my case to nest the single and the double quotes.
test.ps1 -x '"Hello, World!"' -y '"my friend"'
I had a similar problem but in my case I was trying to run a cmdlet, and the call was being made within a Cake script. In this case the single quotes and -file argument did not work:
powershell Get-AuthenticodeSignature 'filename with spaces.dll'
Resulting error: Get-AuthenticodeSignature : A positional parameter cannot be found that accepts argument 'with'.
I wanted to avoid the batch file if possible.
Solution
What did work was to use a cmd wrapper with /S to unwrap outer quotes:
cmd /S /C "powershell Get-AuthenticodeSignature 'filename with spaces.dll'"
How can I use PowerShell's Start-Process cmdlet to start a process using its full command line (with executable path and arguments). For instance let I have the following line
"<dir_path>/myprog.exe" -arg1 "val1" -arg2 "val2"
stored on some string variable and want to run it via Start-Process.
I know that Start-Process -FilePath '<dir_path>/myprog.exe' -ArgumentList '-arg1 "val1" -arg2 "val2"' will work. But the point is that I don't know how to get executable's path and arguments from the full command line.
So is there some way to run process using its full command line via Start-Process, or if there is no such way, then how can I get file path and argument list from the command line?
Do you need start-process? Can you invoke the executable directly?
& "C:\Dir 1\Dir 2\executable.exe" -arg1 "value 1" -arg2 "value 2"
See help about_Operators and for info on & (call) operator.
Bill
Is there some reason you have your heart set on Start-Process? If not, you can do this:
Invoke-Expression "& $command"
where $command is the variable that stores the full command line.
I'm creating a Powershell script to deploy some code and part of the process is to call a command-line compression tool called RAR.EXE to back-up some folders.
I'm attempting to dynamically build out the parameters and then have powershell call the command with the variables but I'm running into trouble. It isn't working...
Run the following script and you should see what I'm talking about. The parameters being passed in as a variable are being mangled. If I pass the entire command + parameters in I get the infamous "is not recognized as a cmdlet..." message.
Thanks for any help!
echo "this should succeed"
& cmd /c echo foo
echo "why does this echo out an additional double quote?"
$param = "/c echo foo"
& cmd "$param"
echo "this does the same"
$param = "/c echo foo"
& cmd $param
echo "escaping the slash doesn't work either..."
$param = "`/c echo foo"
& cmd $param
echo "this fails, but why?"
$cmd = "cmd /c echo foo"
&$cmd
The call operator '&' is unnecessary in this case. It is used to invoke a command in a new scope. This is typically used to invoke a command specified by a string or scriptblock. It also has the side benefit that any variables created in say a PowerShell script are discarded after the command finishes and the scope goes away.
However since the cmd is an EXE it executes in a completely different process. FWIW, you get similar output directly from cmd.exe:
> cmd "/c echo foo"
foo"
So the extra quote on the end is a cmd.exe issue. Typically you need to keep the command separate from the parameters when PowerShell is doing the parsing to invoke the command e.g.
45> & { $foo = "foo" }
46> $foo # Note that $foo wasn't found - it went away with the scope
47> . { $foo = "foo" } # dotting executes in the current scope
48> $foo
foo
The notable exception here is that Invoke-Expression behaves like an "evaluate this string" function. Use with care, especially if the user provides the string. Your day could suck if they provided "ri C:\ -r".
In this case, as others have suggested I would pull the /c out of the string $param string and specify it e.g.:
cmd /c $param
Or use Invoke-Expression but use with care. BTW when you are trying to debug issues with sending arguments to EXE from PowerShell, check out the echoargs utility in PowerShell Community Extensions (http://pscx.codeplex.com). It is very handy:
49> $param = "/c echo foo"
50> echoargs $param
Arg 0 is </c echo foo>
This shows that cmd.exe receives "/c echo foo" as a single argument. "/c" should be a separate argument from "echo foo" (the command to execute).
I have had problems with the & call operator in the past when trying to invoke executable type commands like you are trying. Not sure I understand why. Invoke-Expression however, always seems to work in this context:
PS C:\> $cmd = "cmd /c echo foo"
PS C:\> Invoke-expression $cmd
foo
One other way I found to do this was to create an array of arguments for the command line and use that with the apersand & call operator. Something like this:
$exe = "cmd";
[Array]$params = "/c", "echo", "foo";
& $exe $params;
It's worked well for me.
I originally found this technique here:
http://techstumbler.blogspot.com/2009/12/windows-commands-with-arguments-in.html
Your last example if failing because "&" treats the string as one argument, so it is looking for a program named "cmd /c echo foo.exe". :)
This works:
& $cmd $params
As for the double quote issue, it does seem that cmd does not like the quotes around arguments that PowerShell puts. It gets this:
cmd "/c echo foo"
So I think it treats everything after /c as the exact command, so like so:
echo foo"
Some command line programs and funky parsing of the command line (that is why PowerShell takes over this job for functions and cmdlets). In the case of cmd, I would suggest this:
$param = "echo foo"
& cmd /c $param
it's an artifact of using cmd /c, I think. running
$param = "echo foo"
cmd /c $param
works fine. Unless you have a real code example, it's a bit hard to trouble shoot.
Args are treated differently when they are contained in a String:
PS D:\> echo "1 2 3"
1 2 3
PS D:\> echo 1 2 3
1
2
3
The same results occur when you use a variable for the args:
PS D:\> $param = "1 2 3"
PS D:\> echo $param
1 2 3
The SOLUTION is to use an Array:
PS D:\> $param = #(1,2,3)
PS D:\> echo $param
1
2
3