Launch EXE from a batch with Powershell

Discussion forum for all Windows batch related topics.

Moderator: DosItHelp

Post Reply
Message
Author
sambul35
Posts: 192
Joined: 18 Jan 2012 10:13

Launch EXE from a batch with Powershell

#1 Post by sambul35 » 13 Jun 2016 09:08

I need to start a program from a batch with arguments. The program seems to require keeping its console window open while running, but it can be hidden in the background (not minimized). Several approaches were discussed elsewhere, like using a 2nd user account to start the program from Task Scheduler with option "Run whether user is logged on or not", or starting the exe with JScript, Powershell or VBS from a hybrid batch to hide its window. I appreciate the authors of these methods.

Still I wonder if Powershell approach would allow to avoid restarting the batch from within or using a VBS script file, i.e. would only start hidden microApache, then return control to the batch for other tasks? But its hard to find a suitable example on the web. In Cmd the task is done like this, but it leaves an open program console window:

Code: Select all

@echo off
setlocal EnableExtensions EnableDelayedExpansion
set "img="C:\Program Files (x86)\some_program\microapache\mapache.exe""
set "dir="C:\Program Files (x86)\some_program\microapache""
set "conf=C:/Users/user/AppData/some_program/microApache/httpd_conf.txt"

:: more unrelated code

start "" /d %dir% /b %img% -f %conf% 2>nul

:: more unrelated code
exit /b


What shortest Powershell command would start the program from the batch hidden in the background and return control to the batch once done, ideally without relaunching the batch, using extra files, or notably changing the batch structure, since it performs various other tasks?

aGerman
Expert
Posts: 4678
Joined: 22 Jan 2010 18:01
Location: Germany

Re: Launch EXE from a batch with Powershell

#2 Post by aGerman » 13 Jun 2016 10:09

I'm not that familiar with PS but out of what I found in the internet and what was already posted about PS hybrids here at DosTips I'd guess something like that should meet your requirement ...

Code: Select all

<# :: batch portion

@echo off
PowerShell -NoProfile -ExecutionPolicy Bypass -Command "Invoke-Expression (${%~fs0} | Out-String)"
pause
exit /b


powershell portion #>

Start-Process -WindowStyle hidden -FilePath "C:\Program Files (x86)\some_program\microapache\mapache.exe" -WorkingDirectory "C:\Program Files (x86)\some_program\microapache" -ArgumentList "-f `"C:/Users/user/AppData/some_program/microApache/httpd_conf.txt`""

Regards
aGerman

//Edit:
Since the PS process inherits the environment from the calling Batch process you could keep your variables. (note that I removed the extra quotes in your SET statements)

Code: Select all

<# :: batch portion

@echo off
set "img=C:\Program Files (x86)\some_program\microapache\mapache.exe"
set "dir=C:\Program Files (x86)\some_program\microapache"
set "conf=C:/Users/user/AppData/some_program/microApache/httpd_conf.txt"

PowerShell -NoProfile -ExecutionPolicy Bypass -Command "Invoke-Expression (${%~fs0} | Out-String)"
pause
exit /b


powershell portion #>

Start-Process -WindowStyle hidden -FilePath "$env:img" -WorkingDirectory "$env:dir" -ArgumentList "-f `"$env:conf`""

sambul35
Posts: 192
Joined: 18 Jan 2012 10:13

Re: Launch EXE from a batch with Powershell

#3 Post by sambul35 » 13 Jun 2016 14:33

Thanks for the sample. The above script does work, but your similar JScript works a lot faster. What I was trying to avoid is changing overall batch structure, since the batch performs various functions, and usually started with certain arguments. Does JScript also inherit batch arguments?

I used Powershell from a batch before like here etc., and it usually didn't require to restart the batch from within, though slow for some reason compare to other methods. I wonder if similar "no restart" approach is possible here, since it doesn't require to use hybrid structure,? Why restarting the batch is important here, despite I'm trying to start another program, not related to this batch?

aGerman
Expert
Posts: 4678
Joined: 22 Jan 2010 18:01
Location: Germany

Re: Launch EXE from a batch with Powershell

#4 Post by aGerman » 13 Jun 2016 16:15

I wonder if similar "no restart" approach is possible here

You mean something like that?

Code: Select all

PowerShell -NoProfile -ExecutionPolicy Bypass -Command "& {Start-Process -WindowStyle hidden -FilePath '%img%' -WorkingDirectory '%dir%' -ArgumentList '-f ""%conf%"""'}"

I don't think that would be much faster.

Does JScript also inherit batch arguments?

Every child process inherits the environment from its parent process (which has nothing to do with arguments though). Of course different languages have their own methods to access it. (Only in a CMD process regular variables are also environment variables.)
In order to access the process environment in JScript you may use an object that references it.

Code: Select all

var objEnv = WScript.CreateObject('WScript.Shell').Environment('PROCESS');

A certain variable can be accessed by passing its name as string, e.g.

Code: Select all

objEnv('img')

Regards
aGerman

sambul35
Posts: 192
Joined: 18 Jan 2012 10:13

Re: Launch EXE from a batch with Powershell

#5 Post by sambul35 » 13 Jun 2016 18:42

Thanks for the comments. Similarly, the VBS method posted here allows a VBS script to access arguments of Cscript command calling the script:

Code: Select all

Set args = WScript.Arguments
SoundFilePath = args.Item(0)

It looks, your above example has similar purpose to access JScript command arguments and batch variables?

Code: Select all

var objEnv = WScript.CreateObject('WScript.Shell').Environment('PROCESS');
:: passing var
objEnv('img')

However, I was able to directly execute your JScript code with batch variables without declaring such an object.

Your above "no restart" Powershell command works well. I wonder though, why Powershell scripts are so slow to execute, even when running same command several times in the same batch?

EDIT: found some PS performance tips and code. PS slow startup seems to be caused by loading .NET modules.

"Ngen.exe creates native images, which are files containing compiled processor-specific machine code, and installs them into the native image cache on the local computer. The runtime can use native images from the cache instead of using the just-in-time (JIT) compiler to compile the original assembly."

aGerman
Expert
Posts: 4678
Joined: 22 Jan 2010 18:01
Location: Germany

Re: Launch EXE from a batch with Powershell

#6 Post by aGerman » 14 Jun 2016 00:50

It looks, your above example has similar purpose to access JScript command arguments and batch variables?

While the environment contains variables that are inherited from the parent process, arguments are passed in the command line.
I'll try to give you an example in order to see the difference between.

Code: Select all

@if (@a)==(@b) @end /*

@echo off

:: define environment variables
set "var1=value1"
set "var2=value2"

:: pass arguments to the JScript
cscript //nologo //e:jscript "%~fs0" "value3" "value4"

pause
exit /b
*/

// environment variables are accessed by their name
var objEnv = WScript.CreateObject('WScript.Shell').Environment('PROCESS');
WScript.Echo('Values of var1 and var2:\n' + objEnv('var1') + '\n' + objEnv('var2') + '\n\n');

// arguments are accessed by their index
WScript.Echo('Number of passed arguments: ' + WScript.Arguments.Count() + '\nThese are:');
for (var i = 0; i < WScript.Arguments.Count(); ++i){
  WScript.Echo(WScript.Arguments.Item(i));
}


However, I was able to directly execute your JScript code with batch variables without declaring such an object.

Yes, have a look at what happens there. The JScript inherits the environment from the calling Batch. The Run method starts another cmd.exe process that inherits the environment from the JScript. That's the reason why it works. The JScript itself would not be able to expand strings like %img% to their value without additional methods.

Regards
aGerman

foxidrive
Expert
Posts: 6031
Joined: 10 Feb 2012 02:20

Re: Launch EXE from a batch with Powershell

#7 Post by foxidrive » 14 Jun 2016 23:58

sambul35 wrote:

Code: Select all

set "dir="C:\Program Files (x86)\some_program\microapache""



This breaks when the string contains poison characters because the first " and the the next " are opening and then closing the protective effect of double quotes.

Simply remove the outer double quotes completely in a situation like this.

aGerman
Expert
Posts: 4678
Joined: 22 Jan 2010 18:01
Location: Germany

Re: Launch EXE from a batch with Powershell

#8 Post by aGerman » 15 Jun 2016 03:45

I do it the other way around :) It's one of my own rules to always quote the assignment instead of the values. That way I avoid problems with special characters and with unseen spaces at the end of the line. Following this rule I always know that every value in my variables is unquoted and I rather quote the variable if needed instead of confusing myself if one variable already contains quotes and the next variable doesn't :wink:

Regards
aGerman

sambul35
Posts: 192
Joined: 18 Jan 2012 10:13

Re: Launch EXE from a batch with Powershell

#9 Post by sambul35 » 15 Jun 2016 05:53

I experimented with this earlier, the result depends on a particular command, where an argument contains a file path. For example, I didn't have any success with using a path with spaces for a Robocopy log in example like this one. Can you suggest how to do it?

aGerman
Expert
Posts: 4678
Joined: 22 Jan 2010 18:01
Location: Germany

Re: Launch EXE from a batch with Powershell

#10 Post by aGerman » 15 Jun 2016 08:44

Code: Select all

::quoted assignment ...
set "var=a b&c"
:: ... plus quoted variable if required (e.g. if var contains a path) ...
echo "%var%"
:: ... is how I would do it

Code: Select all

::unquoted assignment but quoted value ...
set var="a b&c"
:: ... plus unquoted variable (because the value already contains the quotes) ...
echo %var%
:: ... is what foxidrive suggested

:wink:

foxidrive
Expert
Posts: 6031
Joined: 10 Feb 2012 02:20

Re: Launch EXE from a batch with Powershell

#11 Post by foxidrive » 29 Jun 2016 12:35

aGerman wrote:I do it the other way around :) It's one of my own rules to always quote the assignment instead of the values. That way I avoid problems with special characters and with unseen spaces at the end of the line. Following this rule I always know that every value in my variables is unquoted


I agreed with you and didn't comment aGerman, this is a far better technique to adopt.

My explanation was intended to outline how double quotes toggle on and off the protection for poison characters such as &

There are those tricky situations where a string contains several sets of double quotes with poison characters inside them. On limited occasions you need to append variables together - which is when the toggling of double quotes becomes a thing that's important to be aware of.

It's rare that I've needed to fiddle with strings in this way and so rare that I can't recall an example to illustrate this. Or I dreamed it all in one of my batch file dreams. ;)

aGerman
Expert
Posts: 4678
Joined: 22 Jan 2010 18:01
Location: Germany

Re: Launch EXE from a batch with Powershell

#12 Post by aGerman » 29 Jun 2016 14:31

It's rare that I've needed to fiddle with strings in this way and so rare that I can't recall an example to illustrate this.

Just to leave such an example for the readers ...

Code: Select all

@echo off &setlocal
set myCommand1=echo Yesterday I was watching tv.^&echo "Tom & Jerry" is one of my favorite cartoons.
set "myCommand2=echo Yesterday I was watching tv.&echo "Tom ^& Jerry" is one of my favorite cartoons."

%myCommand1%
%myCommand2%

pause

Poison characters that are not enclosed in a pair of quotes have to be escaped.

set myCommand1=echo Yesterday I was watching tv.^&echo "Tom & Jerry" is one of my favorite cartoons.
set "myCommand2=echo Yesterday I was watching tv.&echo "Tom ^& Jerry" is one of my favorite cartoons."

foxidrive
Expert
Posts: 6031
Joined: 10 Feb 2012 02:20

Re: Launch EXE from a batch with Powershell

#13 Post by foxidrive » 29 Jun 2016 20:55

aGerman wrote:Just to leave such an example for the readers ...

That is a perfect example of the problem aGerman with surrounding qoutes in an unusual string.

Just to continue the chatter with toggling of qoutes being important: in the case below inside a loop the surrounding quotes leave the & unprotected.

Code: Select all

@echo off

set myCommand3=Yesterday I was watching "Tom & Jerry" and was hoping Tom got mouse sandwich for a change.

echo %myCommand3%
pause

for /L %%a in (1,1,1) do set "myCommand4=%myCommand3%"
echo %myCommand4%
pause


Which results in this: where escaping isn't quite so easy in a loop.

Yesterday I was watching "Tom & Jerry" and was hoping Tom got mouse sandwich for a change.
Press any key to continue . . .
'Jerry" and was hoping Tom got mouse sandwich for a change."' is not recognized as an internal or external command, operable program or batch file.
Yesterday I was watching
Press any key to continue . . .




I was more a fan of Bugs and Daffy Duck, and Marvin the Martian :)

Post Reply