是否可以在批处理文件中嵌入和执行VBScript而不使用临时文件?

dbe*_*ham 38 vbscript batch-file

人们已经在批处理文件中嵌入和执行VBScript很长一段时间了.但是我所看到的所有已发布的解决方案(在此问题最初提出时)都涉及编写临时VBS文件.例如:在Windows批处理文件中嵌入VBScript.

是否可以在批处理中执行嵌入式VBScript而无需编写临时文件?

dbe*_*ham 52

注意 - 跳转到 本答案底部UPDATE 2014-04-27 部分以获得最佳解决方案.

我曾经认为答案是否定的.但随后DosTips用户Liviu发现,<SUB>当嵌入批处理文件中时,该字符(Ctrl-Z,0x1A,十进制26)具有奇特效应.如果函数有点像行终止符,那么如果它们前面有Ctrl-Z,则可以执行跟随REM(或:: remark hack)的批处理命令.http://www.dostips.com/forum/viewtopic.php?p=13160#p13160

这已在XP Home Edition sp3,Vista Home Premium sp2 64位和Vista Enterprise sp2 32位上得到确认.我假设它适用于其他Windows版本.

注意 -下面的代码应该包含嵌入的Ctrl-Z字符.我发誓我曾经在IE8上查看过这个网站.但他们似乎已经不知何故从这篇文章中丢失了,我无法弄清楚如何发布它们了.我用字符串替换了字符<SUB>

::<sub>echo This will execute in batch, but it will fail as vbs.
rem<SUB>echo This will execute in batch, and it is also a valid vbs comment
::'<SUB>echo This will execute in batch and it is also a valid vbs comment
Run Code Online (Sandbox Code Playgroud)

这是成功批量/ vbs混合的关键.只要每个批处理命令前面都有rem<SUB>::'<SUB>,那么vbs引擎就不会看到它,但批处理命令将会运行.只需确保使用EXIT或终止批次部分EXIT /B.然后脚本的其余部分可以是正常的vbs.

如果需要,您甚至可以拥有批次标签.:'Label既是有效的vbs注释,也是有效的批处理标签.

这是一个简单的混合脚本.(再次<SUB>代替嵌入式Ctrl-Z字符)

::'<SUB>@cscript //nologo //e:vbscript "%~f0" & exit /b
WScript.Echo "Example of a hybrid VBS / batch file"
Run Code Online (Sandbox Code Playgroud)

更新2012-04-15

jeb找到了一个避免尴尬的CTRL-Z的解决方案,但它在开始时打印出ECHO OFF并设置了一些无关的变量.

我找到了一个没有CTRL-Z的解决方案,可以消除无关的变量并且更容易理解.

通常情况下,特殊字符&,|,<,>等不要在工作后,REM在批处理语句.但是这些特殊角色确实起作用了REM..我在http://www.dostips.com/forum/viewtopic.php?p=3500#p3500上找到了这些信息.测试显示REM.仍然是有效的VBS评论.编辑 - 基于jeb的评论,它使用更安全REM^(插入后有一个空格).

所以这里是一个简单的VBS /批量混合使用REM^ &.唯一的缺点是它REM &在开始时打印,而jeb的解决方案打印ECHO OFF.

rem^ &@cscript //nologo //e:vbscript "%~f0" & exit /b
WScript.Echo "Example of a hybrid VBS / batch file"
Run Code Online (Sandbox Code Playgroud)

这是演示多个批处理命令的另一个简单示例,包括对标记子例程的CALL.

::' VBS/Batch Hybrid

::' --- Batch portion ---------
rem^ &@echo off
rem^ &call :'sub
rem^ &exit /b

:'sub
rem^ &echo begin batch
rem^ &cscript //nologo //e:vbscript "%~f0"
rem^ &echo end batch
rem^ &exit /b

'----- VBS portion ------------
wscript.echo "begin VBS"
wscript.echo "end VBS"
'wscript.quit(0)
Run Code Online (Sandbox Code Playgroud)

我仍然喜欢CTRL-Z解决方案,因为它消除了所有无关的输出.

更新2012-12-17

Tom Lavedas发布了一种方法,可以通过Google Groups上的批处理脚本方便地运行动态VBS:无文件VBS混合脚本.该方法使用mshta.exe(Microsoft HTML Application Host).

他最初的批处理解决方案依赖外部小型VBS.BAT脚本在FOR/F中执行VBS.我稍微修改了语法,以便在任何给定的批处理脚本中直接嵌入.

这很慢,但非常方便.它仅限于执行单行VBS.

VBS是正常写入的,除了所有引号必须加倍:包含字符串的引号必须写为"",并且字符串内部的引号必须写为"""".通常,迷你脚本在FOR/F的IN()子句中执行.它可以直接执行,但只有在重定向或管道传输stdout时才能执行.

只要安装了IE,它就可以在XP以后的任何Windows操作系统上运行.

@echo off
setlocal
:: Define simple batch "macros" to implement VBS within batch
set "vbsBegin=mshta vbscript:Execute("createobject(""scripting.filesystemobject"")"
set "vbsBegin=%vbsBegin%.GetStandardStream(1).write("
set ^"vbsEnd=):close"^)"

:: Get yesterday's date
for /f %%Y in ('%vbsBegin% date-1 %vbsEnd%') do set Yesterday=%%Y
set Yesterday
pause
echo(

:: Get pi
for /f %%P in ('%vbsBegin% 4*atn(1) %vbsEnd%') do set PI=%%P
set PI
pause
echo(

set "var=name=value"
echo Before - %var%
:: Replace =
for /f "delims=" %%S in (
  '%vbsBegin% replace(""%var%"",""="","": "") %vbsEnd%'
) do set "var=%%S"
echo After  - %var%
pause
echo(

echo Extended ASCII:
for /l %%N in (0,1,255) do (

  %=  Get extended ASCII char, except can't work for 0x00, 0x0A.  =%
  %=  Quotes are only needed for 0x0D                             =%
  %=    Enclosing string quote must be coded as ""                =%
  %=    Internal string quote must be coded as """"               =%
  for /f delims^=^ eol^= %%C in (
    '%vbsBegin% """"""""+chr(%%N)+"""""""" %vbsEnd%'
  ) do set "char.%%N=%%~C"

  %=  Display result  =%
  if defined char.%%N (
    setlocal enableDelayedExpansion
    echo(   %%N: [ !char.%%N! ]
    endlocal
  ) else echo(   %%N: Doesn't work :(
)
pause
echo(

:: Executing the mini VBS script directly like the commented code below 
:: will not work because mshta fails unless stdout has been redirected
:: or piped.
::
::    %vbsBegin% ""Hello world"" %vbsEnd%
::

:: But this works because output has been piped
%vbsBegin% ""Hello world"" %vbsEnd% | findstr "^"
pause
Run Code Online (Sandbox Code Playgroud)

更新2014-04-27

在DosTips上有一个很好的js/vbs/html/hta杂交和cmd/bat嵌合体的概要.来自不同人的很多好东西.

在该线程中,DosTips用户Liviu发现了一个使用WSF 的漂亮的VBS /批处理混合解决方案.

<!-- : Begin batch script
@echo off
cscript //nologo "%~f0?.wsf"
exit /b

----- Begin wsf script --->
<job><script language="VBScript">
  WScript.Echo "VBScript output called by batch"
</script></job>
Run Code Online (Sandbox Code Playgroud)

我认为这个解决方案太棒了.批处理和WSF部分明确地用漂亮的标题分隔.批处理代码绝对正常,没有任何奇怪的语法.唯一的限制是批处理代码不能包含-->.

同样,WSF中的VBS代码绝对正常.唯一的限制是VBS代码不能包含</script>.

唯一的风险是未"%~f0?.wsf"加载使用的脚本作为加载脚本.不知何故,解析器正确地找到并加载正在运行的.BAT脚本"%~f0",并且?.wsf后缀神秘地指示CSCRIPT将脚本解释为WSF.希望MicroSoft永远不会禁用该"功能".

由于该解决方案使用WSF,因此批处理脚本可以包含任意数量的独立VBS,JScript或可以选择性调用的其他作业.每项工作甚至可以使用多种语言.

<!-- : Begin batch script
@echo off
echo batch output
cscript //nologo "%~f0?.wsf" //job:JS
cscript //nologo "%~f0?.wsf" //job:VBS
exit /b

----- Begin wsf script --->
<package>
  <job id="JS">
    <script language="VBScript">
      sub vbsEcho()
        WScript.Echo "VBScript output called by JScript called by batch"
      end sub
    </script>
    <script language="JScript">
      WScript.Echo("JScript output called by batch");
      vbsEcho();
    </script>
  </job>
  <job id="VBS">
    <script language="JScript">
      function jsEcho() {
        WScript.Echo("JScript output called by VBScript called by batch");
      }
    </script>
    <script language="VBScript">
      WScript.Echo "VBScript output called by batch"
      call jsEcho
    </script>
  </job>
</package>
Run Code Online (Sandbox Code Playgroud)

  • 使用`REM.'的第二个解决方案也很好,但有一个缺点.如果存在名为"REM"(没有扩展名)的文件,则"REM."会导致"找不到文件"错误.但你可以使用`REM ^:`代替,这似乎总能奏效.(也是`REM ^,``REM ^;`,`REM ^`) (3认同)
  • @Paul - 信不信由你,该行是一个有效的批次标签.CMD.EXE充满了这样的特质.冒号前面的字符是可以出现在批处理标签之前的少数字符之一 - 这是jeb在DosTips上发现并发布的地方.如果你愿意走下兔子洞,那么你可以在http://www.dostips.com/forum/viewtopic.php?f=3&t=3803上阅读一系列疯狂的标签规则. (2认同)

jeb*_*jeb 11

编辑:我的第一个回答是错误的VBScript,现在我的下一次尝试...

使用CTRL-Z的好主意,但我不喜欢批处理文件中的控制字符,因为复制和粘贴它们是有问题的.
这取决于您的浏览器,编辑器,...

您可以使用普通字符和"普通"代码获得混合VBScript/Batch.

:'VBS/Batch Hybrid
:
:
:'Makes the next line only visible for VBScript ^
a=1_
<1' echo off <nul 

set n=nothing' & goto :'batchCode & REM Jump to the batch code

'VBScript-Part
wscript.echo "VB-Start"
wscript.echo "vb-End"
wscript.quit(0)

'Batch part
:'batchCode
set n=n'& echo Batch-Start
set n=n'& echo two
set n=n'& echo Batch-End
set n=n'& cscript /nologo /E:vbscript vbTest.bat
Run Code Online (Sandbox Code Playgroud)

诀窍是在每个批处理行前加上set n=n'&它是合法的,但是vbs将忽略该行的其余部分,只有批处理将执行该行的其余部分.

另一个变体是:'remark ^,这是两者的注释,但对于批处理,这个备注也是多行字符的下一行.
然后VbScript看到a=1<1该行的其余部分是备注'
批处理只看到<1' echo off <nul,第一个重定向1'将被第二个重写<nul,因此它只会产生结果echo off < nul.

唯一剩下的问题是你可以看到第一个echo off,因为它不能批量使用@重定向后使用.

对于JScript,存在一种更简单的解决方案混合脚本