js/vbs/html/hta and more hybrids and chimeras in cmd/bat

Discussion forum for all Windows batch related topics.

Moderator: DosItHelp

Message
Author
siberia-man
Posts: 208
Joined: 26 Dec 2013 09:28
Contact:

Re: js/vbs/html/hta hybrids and chimeras in cmd/bat

#31 Post by siberia-man » 03 Nov 2014 17:00

I decided come back to this thread attempting to cover most of issues in one solution =)

I spent few minutes thinking how to name the script. There were three possible candidates:
-- any2bat or every2bat (similar to pl2bat or js2bat, but "any" or "every" don't cover everything)
-- cmdify (this neologism stands for "do cmd-like" similar to "stringify" standing for "do string-like" in some programming languages)
-- cmdize (practically the same as above; it stands for "do cmd" as "analyze" stands for "do analysis")

I decided to leave the last item because (in my opinion) it is much closer to outcomes

Code: Select all

:: USAGE
::     cmdize name [...]
::
:: This tool converts a supported code into a batch file that can be
:: executed without explicit invoking the executable engine. The script
:: creates new file and places it under the same directory as the original
:: one with the same name, replacing the original extension with ".bat".
:: The content of the new file consists of the original file and the
:: special header that being the "polyglot" and having some tricks to be a
:: valid code in batch file and the wrapped code at the same time.
::
:: FEATURES
:: It does comment on "Option Explicit" in VBScript.
:: "<?xml?>" declaration for wsf-files is expected.
:: "Option Explicit" and "<?xml?>" in a single line only are supported.
:: BOM is not supported at all.
::
:: It is possible to select an engine for JavaScript, VBScript and WSF via
:: the command line options /E. If it is not pointed especially, CSCRIPT
:: is used as the default engine for all JavaScript, VBScript and WSF
:: files. Another valid engine is WSCRIPT. Additionally for JavaScript
:: files it is possible to set another engine such as NodeJS, Rhino etc.
:: The predefined option /E DEFAULT resets any previously set engines to
:: the default value.
::
:: SEE ALSO
:: Proceed the following links to learn more the origins
::
:: .js
:: http://forum.script-coding.com/viewtopic.php?pid=79210#p79210
:: http://www.dostips.com/forum/viewtopic.php?p=33879#p33879
:: https://gist.github.com/ildar-shaimordanov/88d7a5544c0eeacaa3bc
::
:: .vbs
:: http://www.dostips.com/forum/viewtopic.php?p=33882#p33882
:: http://www.dostips.com/forum/viewtopic.php?p=32485#p32485
::
:: .pl
:: For details and better support see "pl2bat.bat" from Perl distribution
::
:: .sh, .bash
:: http://forum.script-coding.com/viewtopic.php?id=11535
:: http://www.dostips.com/forum/viewtopic.php?f=3&t=7110#p46654
::
:: .ps1
:: http://blogs.msdn.com/b/jaybaz_ms/archive/2007/04/26/powershell-polyglot.aspx
:: http://stackoverflow.com/a/2611487/3627676
::
:: .py
:: http://stackoverflow.com/a/29881143/3627676
:: http://stackoverflow.com/a/17468811/3627676
::
:: .hta and .html?
:: http://forum.script-coding.com/viewtopic.php?pid=79322#p79322
::
:: .wsf
:: http://www.dostips.com/forum/viewtopic.php?p=33963#p33963
::
:: COPYRIGHTS
:: Copyright (c) 2014, 2015, 2016 Ildar Shaimordanov

@echo off

if "%~1" == "" (
   for /f "usebackq tokens=* delims=:" %%s in ( "%~f0" ) do (
      if /i "%%s" == "@echo off" goto :EOF
      echo:%%s
   )
   goto :EOF
)

:cmdize.loop.begin
if "%~1" == "" goto :cmdize.loop.end

if /i "%~1" == "/e" (
   set "CMDIZE_ENGINE="
   if /i not "%~2" == "default" set "CMDIZE_ENGINE=%~2"
   shift
   goto :cmdize.loop.continue
)

if not exist "%~f1" (
   echo:%~n0: File not found: "%~1">&2
   goto :cmdize.loop.continue
)

for %%x in ( .js .vbs .pl .sh .bash .ps1 .py .hta .htm .html .wsf ) do (
   if /i "%~x1" == "%%~x" (
      call :cmdize%%~x "%~1" >"%~dpn1.bat"
      goto :cmdize.loop.continue
   )
)

echo:%~n0: Unsupported extension: "%~1">&2

:cmdize.loop.continue

shift

goto :cmdize.loop.begin
:cmdize.loop.end

goto :EOF


:: Convert the javascript file.
:: The environment variable %CMDIZE_ENGINE% allows to declare another
:: engine (cscript, wscript, node etc).
:: The default value is cscript.
:cmdize.js
if not defined CMDIZE_ENGINE set "CMDIZE_ENGINE=cscript"
set "CMDIZE_ENGINE_OPTS="
for %%e in ( "%CMDIZE_ENGINE%" ) do (
   if /i "%%~ne" == "cscript" set "CMDIZE_ENGINE_OPTS=//nologo //e:javascript"
   if /i "%%~ne" == "wscript" set "CMDIZE_ENGINE_OPTS=//nologo //e:javascript"
)

echo:0^</*! ::
echo:@echo off
echo:%CMDIZE_ENGINE% %CMDIZE_ENGINE_OPTS% "%%~f0" %%*
echo:goto :EOF */0;
type "%~f1"
goto :EOF


:: Convert the vbscript file.
:: The environment variable %CMDIZE_ENGINE% allows to declare another
:: engine (cscript or wscript).
:: The default value is cscript.
:: The next label is duplicated intentionally to avoid error if this
:: script was saved in unix mode (EOL=LF).
:cmdize.vbs.h
:cmdize.vbs.h
set /p "=::'" <nul
type "%TEMP%\%~n0.$$"
echo:%*
goto :EOF


:cmdize.vbs
if not defined CMDIZE_ENGINE set "CMDIZE_ENGINE=cscript"

copy /y nul + nul /a "%TEMP%\%~n0.$$" /a 1>nul

call :cmdize.vbs.h @echo off
call :cmdize.vbs.h %CMDIZE_ENGINE% //nologo //e:vbscript "%%%%~f0" %%%%*
call :cmdize.vbs.h goto :EOF

del /q "%TEMP%\%~n0.$$"
rem type "%~f1"
for /f "tokens=1,* delims=]" %%r in ( ' call "%windir%\System32\find.exe" /n /v "" ^<"%~f1" ' ) do (
   rem Filtering and commenting "Option Explicit".
   rem This ugly code tries as much as possible to recognize and
   rem comment this directive. It fails if "Option" and "Explicit"
   rem are located on two neighbor lines, consecutively, one by one.
   rem But it is too hard to imagine that there is someone who
   rem practices such a strange coding style.
   for /f "usebackq tokens=1,2" %%a in ( '%%s' ) do if /i "%%~a" == "Option" for /f "usebackq tokens=1,* delims=:'" %%i in ( 'x%%b' ) do if /i "%%~i" == "xExplicit" (
      echo:%~n0: Commenting Option Explicit in "%~1">&2
      echo:rem To prevent compilation error due to embedding into a batch file,
      echo:rem the following line was commented automatically.
      set /p "=rem " <nul
   )
   echo:%%s
)
goto :EOF


:: Convert the perl file.
:cmdize.pl
if /i "%CMDIZE_ENGINE%" == "cmd" (
   echo:@echo off
   echo:perl -x -S "%%~dpn0.pl" %%*
   goto :EOF
)

echo:@rem = '--*-Perl-*--
echo:@echo off
echo:perl -x -S "%%~f0" %%*
echo:goto :EOF
echo:@rem ';
echo:#!perl
type "%~f1"
goto :EOF


:: Convert Bourne shell and Bash scripts.
:cmdize.sh
:cmdize.bash
echo:: ^<^< '____CMD____'
echo:@echo off
echo:bash "%%~f0" %%*
echo:goto :eof
echo:____CMD____
type "%~f1"
goto :EOF


:: Convert the powershell file.
:cmdize.ps1
echo:^<# :
echo:@echo off
echo:setlocal
echo:set "POWERSHELL_BAT_ARGS=%%*"
echo:if defined POWERSHELL_BAT_ARGS set "POWERSHELL_BAT_ARGS=%%POWERSHELL_BAT_ARGS:"=\"%%"
echo:endlocal ^& powershell -NoLogo -NoProfile -Command "$_ = $input; Invoke-Expression $( '$input = $_; $_ = \"\"; $args = @( &{ $args } %%POWERSHELL_BAT_ARGS%% );' + [String]::Join( [char]10, $( Get-Content \"%%~f0\" ) ) )"
echo:rem endlocal ^& powershell -NoLogo -NoProfile -Command "$input | &{ [ScriptBlock]::Create( ( Get-Content \"%%~f0\" ) -join [char]10 ).Invoke( @( &{ $args } %%POWERSHELL_BAT_ARGS%% ) ) }"
echo:goto :EOF
echo:#^>
type "%~f1"
goto :EOF


:: Convert the python file.
:cmdize.py
:: Ascetic way is shorter but less flexible
:: Uncomment the following 3 lines if it is more preferrable
:: echo:@python -x "%%~f0" %%* ^& @goto :EOF
:: type "%~f1"
:: goto :EOF
echo:0^<0# : ^^
echo:"""
echo:@echo off
echo:python "%%~f0" %%*
echo:goto :EOF
echo:"""
type "%~f1"
goto :EOF


:: Convert the html file.
:: Supportable file extensions are .hta, .htm and .html.
:cmdize.hta
:cmdize.htm
:cmdize.html
echo:^<!-- :
echo:@echo off
echo:start "" mshta "%%~f0" %%*
echo:goto :EOF
echo:--^>
type "%~f1"
goto :EOF


:: Convert the wsf file.
:: The environment variable %CMDIZE_ENGINE% allows to declare another
:: engine (cscript or wscript).
:: The default value is cscript.
:cmdize.wsf
if not defined CMDIZE_ENGINE set "CMDIZE_ENGINE=cscript"

for /f "usebackq tokens=1,2,* delims=?" %%a in ( "%~f1" ) do for /f "tokens=1,*" %%d in ( "%%b" ) do (
   rem We use this code to transform the "<?xml?>" declaration
   rem located at the very beginning of the file to the "polyglot"
   rem form to do it acceptable by the batch file.
   echo:%%a?%%d :
   echo:: %%e ?^>^<!--
   echo:@echo off
   echo:%CMDIZE_ENGINE% //nologo "%%~f0?.wsf" %%*
   echo:goto :EOF
   echo:: --%%c
   more +1 <"%~f1"
   goto :EOF
)
goto :EOF


rem EOF


Hope, there are no mistakes in the description (typos or bad phrases). Please let me do it better.
Last edited by siberia-man on 21 Jul 2016 09:22, edited 12 times in total.

bars143
Posts: 87
Joined: 01 Sep 2013 20:47

Re: js/vbs/html/hta hybrids and chimeras in cmd/bat

#32 Post by bars143 » 03 Nov 2014 20:25

hi siberia-man,

your script work when my vbs file converted to .bat with one error corrected as describe below in a comment:

pinger.vbs file:

Code: Select all

' dont name this file as   ping.vbs  --it will loop infinitely
' make "Option Explicit" as a comment -- it will not work on cmdize.bat

' Option Explicit
Dim wshShell
On Error Resume Next
   Set wshShell = WScript.CreateObject("WSCript.shell")
   If Err.Number <> 0 Then
      Wscript.Quit
   End If
   wshShell.Run  "cmd.exe /C cd C:\WINDOWS\system32 & ping.exe google.com -t"
On Error Goto 0


resulting file named pinger.bat :

Code: Select all

::'@echo off
::'"%windir%\System32\cscript.exe" //nologo //e:vbscript "%~f0" %*
::'goto :EOF
' dont name this file as   ping.vbs  --it will loop infinitely
' make "Option Explicit" as a comment -- it will not work on cmdize.bat

' Option Explicit
Dim wshShell
On Error Resume Next
   Set wshShell = WScript.CreateObject("WSCript.shell")
   If Err.Number <> 0 Then
      Wscript.Quit
   End If
   wshShell.Run  "cmd.exe /C cd C:\WINDOWS\system32 & ping.exe google.com -t"
On Error Goto 0


edited to included comment in pinger.bat content:

' make "Option Explicit" as a comment -- it will not work on cmdize.bat

:) :)

Bars

windows xp sp3 32-bit user.

siberia-man
Posts: 208
Joined: 26 Dec 2013 09:28
Contact:

Re: js/vbs/html/hta hybrids and chimeras in cmd/bat

#33 Post by siberia-man » 03 Nov 2014 21:01

bars143
You are right. The script produces non-working script when the original vbs-file has "Option Explicit". I found it, as well, when I asked myself "what if I code using this directive?" I have modified the "cmdize" script but the solution is so ugly and so funny.

Update your copy of the cmdize script from my previous message updated there in place.

This version tries to find this directive and comment it. And the script tries to be clever.

However this fix fails in the case when "Option Explicit" is placed on two lines. I commented this stuff

siberia-man
Posts: 208
Joined: 26 Dec 2013 09:28
Contact:

Re: js/vbs/html/hta hybrids and chimeras in cmd/bat

#34 Post by siberia-man » 06 Nov 2014 01:40

fixes and improvements to the code above. The message was updated.

Feature list:
-- It does comment on "Option Explicit" in VBScript.
-- "<?xml?>" declaration for wsf-files is expected.
-- "Option Explicit" and "<?xml?>" in a single line only are supported.
-- BOM is not supported at all.

siberia-man
Posts: 208
Joined: 26 Dec 2013 09:28
Contact:

Re: js/vbs/html/hta hybrids and chimeras in cmd/bat

#35 Post by siberia-man » 09 Nov 2014 08:24

The post viewtopic.php?p=37780#p37780 was updated.

Now the script is able to produce working wrapper for powershell script. Now the hybrid is able to read stdin on the same way as the original powershell script.

siberia-man
Posts: 208
Joined: 26 Dec 2013 09:28
Contact:

Re: js/vbs/html/hta hybrids and chimeras in cmd/bat

#36 Post by siberia-man » 22 Mar 2015 17:49

The post viewtopic.php?p=37780#p37780 was updated.

Now the powershell-to-bat portion is still better.

1. the code is little bit shorter now (approx. on 50-60 bytes)
2. the trick with $input variable has been removed because scriptblock allows to pass data from STDIN directly (invoke-expression doesn't allow).
3. with scriptblock it is possible to describe input arguments within "param()" block.
4. it is possible to wrap arguments with double quotes " (there is only option in dos) and single quotes ' (that is possible in powershell)


Aacini
Expert
Posts: 1885
Joined: 06 Dec 2011 22:15
Location: México City, México
Contact:

Re: js/vbs/html/hta hybrids and chimeras in cmd/bat

#38 Post by Aacini » 27 May 2015 10:24

Interesting method!

Code: Select all

0</* :hello
@ECHO Hello, batch!
@cscript /nologo /E:jscript %~f0 %*
@goto :EOF
*/0;
WScript.Echo('Hello, jscript!');

The first line can be just:

Code: Select all

0</* :

Here it is another method:

Code: Select all

@set @code=@Batch /*
@ECHO Hello, batch!
@cscript /nologo /E:jscript "%~F0" %*
@goto :EOF        */
WScript.Echo('Hello, jscript!');


Antonio

siberia-man
Posts: 208
Joined: 26 Dec 2013 09:28
Contact:

Re: js/vbs/html/hta hybrids and chimeras in cmd/bat

#39 Post by siberia-man » 28 May 2015 03:09

npocmaka_ wrote:just found this :

https://gist.github.com/yaauie/959862


Cool!

So I know how to embed node-js code into batch!

Code: Select all

0</*! ::

@echo off

echo:batch file

node "%~f0"

echo:batch again

goto :EOF

*/0

console.log("Hello World");

npocmaka_
Posts: 512
Joined: 24 Jun 2013 17:10
Location: Bulgaria
Contact:

Re: js/vbs/html/hta hybrids and chimeras in cmd/bat

#40 Post by npocmaka_ » 28 May 2015 04:50

siberia-man wrote:So I know how to embed node-js code into batch!
..


I'd expected one redundant `false` , but it works fine :)

siberia-man
Posts: 208
Joined: 26 Dec 2013 09:28
Contact:

Re: js/vbs/html/hta hybrids and chimeras in cmd/bat

#41 Post by siberia-man » 29 May 2015 08:07

I have extended that suggested gist at https://gist.github.com/ildar-shaimorda ... 0eeacaa3bc. I am thinking to improve my cmdize script with this solution later.

siberia-man
Posts: 208
Joined: 26 Dec 2013 09:28
Contact:

Re: js/vbs/html/hta hybrids and chimeras in cmd/bat

#42 Post by siberia-man » 29 May 2015 19:12

siberia-man wrote:I am thinking to improve my cmdize script with this solution later.


Ok. I did it.

Script

Code: Select all

// example.js

if ( this.WScript ) {
   WScript.Echo('hello, jscript!');
} else {
   console.log('hellow, nodejs!');
}


Hybridization
C:\>cmdize example.js
C:\>example.bat
hello, jscript!


C:\>cmdize /e node example.js
C:\>example.bat
hello, nodejs!


Proceed to this post

Ed Dyreen
Expert
Posts: 1569
Joined: 16 May 2011 08:21
Location: Flanders(Belgium)
Contact:

Re: js/vbs/html/hta hybrids and chimeras in cmd/bat

#43 Post by Ed Dyreen » 14 Jun 2015 19:42

Liviu wrote:
siberia-man wrote:html in cmd/bat
the second version found by the programmer from Russia is the best. http://forum.script-coding.com/viewtopic.php?pid=79317#p79317

Code: Select all

<!-- :
@echo off
start "" mshta.exe "%~f0"
exit /b
-->
[... html code here ...]

Cool trick, that XML '<!-- -->' comment crossed with a CMD '<etc :' redirected label.

A variation on the same idea seems to work for the cmd/wsf hybrid below - CMD can call embedded JS and VBS, and those two can call each other within a given <job>. Checked ok under xp.sp3 and win7x64.sp1.

Code: Select all

<?xml : version="1.0" encoding="UTF-8" ?> ^<!------------------------- cmd ----
@echo off
echo cmd
cscript //nologo "%~f0?.wsf" //job:JS //job:VBS
exit /b
---------------------------------------------------------------------- wsf --->
<package>
  <job id="JS"> <!----------------------------------------------------- js --->
    <script language="VBScript"><![CDATA[
      sub vbsEcho() : WScript.Echo "cmd.js.vbs" : end sub
    ]]></script>
    <script language="JScript"><![CDATA[
      WScript.Echo("cmd.js");
      vbsEcho();
    ]]></script>
  </job>
  <job id="VBS"> <!--------------------------------------------------- vbs --->
    <script language="JScript"><![CDATA[
      function jsEcho() { WScript.Echo("cmd.vbs.js"); }
    ]]></script>
    <script language="VBScript"><![CDATA[
      WScript.Echo "cmd.vbs"
      call jsEcho
    ]]></script>
  </job>
</package>

Code: Select all

C:\tmp>cmd-wsf.cmd
cmd
cmd.js
cmd.js.vbs
cmd.vbs
cmd.vbs.js

Leaving aside the multi-language and CDATA complications, this also works to embed straight VBScript code into a batch file.

Code: Select all

<!-- : --------------------------------------------------------------- cmd ----
@cscript //nologo "%~f0?.wsf" & exit /b & rem ------------------------ vbs --->
<job><script language="VBScript">
WScript.Echo "cmd.vbs - no CDATA so <" & "/script> would cause XML error here"
</script></job>

Code: Select all

C:\tmp>cmd-vbs.cmd
cmd.vbs - no CDATA so </script> would cause XML error here

FWIW the oddities that make the above work are:
- cscript identifies ".wsf" files by extension alone, it has no documented switch or override like it has for individual //E scripting engines - however, appending "?.wsf" to the full filename appears to work i.e. the filename before "?" is loaded but still treated as an ".wsf" type (and even more odd '?' works but '*:\;etc' don't);
- .wsf appears to require an explicit <?xml version="1.0" ?> in order to recognize <![CDATA[ ]]> syntax, and per XML standards that has to be the first line of the file - however, the MS parser allows an ":" to be inserted in <?xml : version="1.0" ?> without complaining, and the batch interpreter doesn't complain either about an '?' in the presumed "<" filename.

Liviu
It's cool but now it won't accept any arguments anymore

Code: Select all

@echo off
Cscript //nologo tst.cmd.wsf /test:HIIIII
pause
exit

Code: Select all

Invoerfout: Kan scriptbestand Z:\ED\VIP\PROJ\DEV\doskit\doskitXPx86 v20150525\He
llo world !\tst.cmd.wsf niet vinden.
Druk op een toets om door te gaan. . .
it works if I change the extension to wsf, disabling the trick :(

Code: Select all

@echo off
Cscript //nologo tst.wsf /test:HIIIII
pause
exit

Code: Select all

<package>
<job id="DoneInVBS">
<?job debug="true"?>

<runtime>
<named
name="test"
helpstring="Text to display"
type="string"
required="true"
/>
</runtime>

<script language="VBScript">
function HelloWorld(pMsg)
MsgBox (pMsg)
End Function

strText=WScript.Arguments.Named.Item("test")

CALL HelloWorld(strText)
</script>
</job>
</package>
a window says HIII

dbenham
Expert
Posts: 2461
Joined: 12 Feb 2011 21:02
Location: United States (east coast)

Re: js/vbs/html/hta hybrids and chimeras in cmd/bat

#44 Post by dbenham » 14 Jun 2015 20:57

@Ed Dyreen :? :?:

I don't see anything hybrid about the code you posted, and you are missing the critical (and undocumented) ? before the .wsf

Passing command line arguments works perfectly for me.


Dave Benham

Ed Dyreen
Expert
Posts: 1569
Joined: 16 May 2011 08:21
Location: Flanders(Belgium)
Contact:

Re: js/vbs/html/hta hybrids and chimeras in cmd/bat

#45 Post by Ed Dyreen » 15 Jun 2015 05:45

I thought the question mark was part of the token expansion and I misread "%~f0?.wsf" as "%~f?.wsf".

Code: Select all

cScript.EXE //noLogo "!$function.fullPathFile!?.WSF" //job:JS /arg0:sleep_ /arg1:!$time!
Thanks dave for pointing that out, but now I have a different problem

Code: Select all

:: ( disable embedded WSF comment -->

   <job id="javaScript">

      <script language="JScript">

WScript.Echo( "hi" );


      </script>
   </job>

   <job id="VBScript"><script language="VBScript">

   </script></job>

<!-- : Enable embedded WSF comment :: )

Code: Select all

function.CMD?.WSF(9065, 4) Windows Script Host: Onverwachte code
 - slechts één 'job'- of 'package'-code is toegestaan op het hoogste niveau : job
In english;

Code: Select all

function.CMD?.WSF(9065, 4) Windows Script Host: Unexpected code
 - only one 'job'- or 'package'-code is allowed at the highest level : job

Post Reply