execute WshShell command from a batch script
Asked Answered
M

4

4

I've got a simple question:

What's the best way to execute a single WshShell command from a Windows batch (.bat) script?

(hopefully it's not creating a new file with VB code)

Musset answered 1/3, 2013 at 22:12 Comment(0)
S
8

You can access WshShell via VBScript or Jscript. Both can be embedded within a batch file, but JScript is much cleaner.

Most people execute VBScript within batch by writing a temporary VBS file. But it is possible to do it without a temporary file. See Is it possible to embed and execute VBScript within a batch file without using a temporary file? for various options.

Embedding JScript within batch is quite easy. See https://mcmap.net/q/22647/-is-there-a-short-cut-for-desktop-folder-in-windows-batch. I use a very slight variation of that technique.

@if (@X)==(@Y) @end /* Harmless hybrid line that begins a JScript comment

:: ******* Begin batch code *********
@echo off
:: Your batch logic goes here

:: At any point you can execute the following to access your JScript
cscript //E:JScript //nologo "%~f0" yourJscriptParametersGoHere

:: Be sure to terminate your script so that 
:: it does not fall through into the JScript code
exit /b

********* Begin JScript code **********/
var WshShell=WScript.CreateObject("WScript.Shell")

/* do whatever with your WshShell object */

Explanation:

The key to the technique is the first line. It must be a line that has valid syntax for both JScript and batch.

Batch sees the first line as a simple IF command that always evaluates to false, so it never executes the non-existent @end command, and no harm is done. The following lines are all normal batch code until exit /b is reached, at which point batch processing terminates and the remaining lines are ignored.

JScript sees the first line as an empty conditional compilation block, followed by the beginning of a multi-line comment. JScript ignores the following batch code because it is all part of the comment. The comment ends with */, and then normal JScript code follows.

The only thing that could fail is if your batch code must have */ within it, because that would terminate the JScript comment prematurely. But that can be solved by putting something between the * and / that disappears after batch parsing. If the code is not quoted, then you can simply escape the slash as follows: *^/. If the code is quoted, then you can expand an undefined variable: *%=%/. A variable named = is guaranteed not to be defined.

Sonar answered 2/3, 2013 at 1:38 Comment(1)
Not that I'll be using this method much, but how does your script work?Dunsinane
L
7

This is the method I use to write a Batch-JScript hybrid script:

@if (@CodeSection == @Batch) @then

:: The first line above is...
:: in Batch: a valid IF command that does nothing.
:: in JScript: a conditional compilation IF statement that is false,
::             so this section is omitted until next "at-sign end".


@echo off

rem EXPR.BAT: Evaluate a JScript (arithmetic) expression
rem Antonio Perez Ayala

rem Define an auxiliary variable to call JScript
set JSCall=Cscript //nologo //E:JScript "%~F0"

rem Do Batch business here, for example:
%JSCall% %1
goto :EOF

End of Batch section


@end


// JScript section

WScript.Echo(eval(WScript.Arguments.Unnamed.Item(0)));

For example:

EXPR 1/3

EDIT: If you want a simpler/shorter method, use this one:

@set @a=0  /*
@cscript //nologo //E:JScript "%~F0" "%~1"
@goto :EOF */

WScript.Echo(eval(WScript.Arguments(0)));

Again, the first @set @a=0 /* is a valid statement/command in both JScript and Batch that is only used to insert the start of a JScript comment (/*), so the Batch section be ignored by JScript. The comment is closed (*/) after the final goto :EOF.

EDIT: An even simpler method...

@set @a=0 // & cscript //nologo //E:JScript "%~F0" "%~1" & goto :EOF

WScript.Echo(eval(WScript.Arguments(0)));
Lemnos answered 2/3, 2013 at 15:24 Comment(1)
Ahh, that's the explanation I was looking for on your answer to my question. Going to edit your response and copy the comment lines over.Leilani
R
2

Thanks the above for inspiring me to do a slight modification.

@if (false)==nul ======= CMD code =======
@echo off
::code before Cscript
cscript //nologo //e:jscript "%~f0" %*
echo it returns: %errorlevel%
::code after Cscript 
exit /b
=================================
Freedom Land ^o^
======= J/VB Script code ======
@end
// Start Cscript
WScript.Echo("wsh says: Hello, Universe!");
WScript.Quit(123.456)
Rauwolfia answered 12/7, 2014 at 17:29 Comment(0)
S
0

You can also use this method that is applicable for node.js:

0</* ::

@echo off

    echo hello from batch

    rem -- CALLING NODE
    ::node "%~f0" %*

    rem -- CALLING CSCRIPT
    cscript //E:JScript //nologo "%~f0" %*

exit /b %errorlevel%


*/0;

// -- NODE CODE
//console.log('Hello from Node');

// -- JScript CODE 
WScript.Echo("Hello from JSCript")
Symphonize answered 26/4, 2020 at 13:33 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.