vbscript batch-file

¿Es posible incrustar y ejecutar VBScript dentro de un archivo por lotes sin usar un archivo temporal?



batch-file (5)

La gente ha estado integrando y ejecutando VBScript dentro de archivos por lotes durante mucho tiempo. Pero todas las soluciones publicadas que he visto (en el momento en que se planteó originalmente esta pregunta) implican escribir un archivo VBS temporal. Por ejemplo: incrustar VBScript dentro del archivo por lotes de Windows .

¿Es posible ejecutar VBScript incorporado dentro de un lote sin escribir un archivo temporal?


Hay una solución muy simple para este problema. Simplemente use un flujo de datos alternativo (ADS) para almacenar el código VBS. Para explicarlo simplemente, un ADS es otro lugar donde puede almacenar otros datos en el mismo archivo , es decir, un archivo se compone de sus datos originales más cualquier cantidad de ADS adicionales . Cada ADS se identifica separando su propio nombre del nombre del archivo original mediante dos puntos. Por ejemplo:

test.bat <- a file called "test.bat" test.bat:script_.vbs <- an ADS of file "test.bat" called "script_.vbs"

Puede encontrar una descripción más detallada y técnica de ADS en la web, pero es importante mencionar ahora que esta característica solo funciona en discos NTFS. Ahora, veamos cómo usar esta característica para resolver este problema en particular.

Primero, crea el archivo por lotes original de la forma habitual. También puede iniciar notepad.exe desde la línea de comandos de esta manera:

notepad test.bat

Para mi ejemplo, test.bat las siguientes líneas en test.bat :

@echo off setlocal For /f "delims=" %%i in (''Cscript //nologo "test.bat:script_.vbs" "Select a folder"'') do Set "folder=%%i" echo Result: "%folder%"

Tenga en cuenta el nombre del script VBS. Después de que se guardó test.bat y se cerró el Bloc de notas, cree el script VBS usando el Bloc de notas, así que ingrese este comando en la línea de comandos:

notepad test.bat:script_.vbs

Y crea el guión de la manera habitual:

Dim objFolder, objShell Set objShell = CreateObject("Shell.Application") Set objFolder = objShell.BrowseForFolder(0, "Select a folder.", &H4000, 0) If Not (objFolder Is Nothing) Then wscript.echo objFolder.Self.path Else wscript.echo 0 End If

Guarde este archivo y ejecute test.bat . ¡Funciona! ;)

Puede revisar los ADS del archivo test.bat través del comando /R switch in dir . Puede leer una explicación más extensa de este método y sus limitaciones en esta publicación .


He intentado reunir todas las soluciones en un script en http://www.dostips.com/forum/viewtopic.php?p=37780#p37780 .

Existe el script por lotes que convierte los idiomas más populares en un archivo por lotes ( .js , .vbs , .ps1 , .wsf , .hta e histórico .pl ).

Funciona de la siguiente manera:

:: convert filename1.vbs to executable filename1.bat cmdize.bat filename1.vbs


Y mi intento ( publicado por primera vez aquí ). Se parece a la solución del jeb, pero (al menos según yo) el código es más legible:

:sub echo(str) :end sub echo off ''>nul 2>&1|| copy /Y %windir%/System32/doskey.exe %windir%/System32/'.exe >nul ''& echo/ ''& cscript /nologo /E:vbscript %~f0 ''& echo/ ''& echo BATCH: Translation is at best an ECHO. ''& echo/ ''& pause ''& rem del /q "%windir%/System32/'.exe" ''& exit /b WScript.Echo "VBScript: Remorse is the ECHO of a lost virtue." WScript.Quit

Y la explicación:

  1. '' (comilla simple) no es un símbolo prohibido como parte de un nombre de archivo en Windows, por lo que no hay problema para tener un archivo llamado ''.exe
  2. Hay pocos comandos cargados con ventanas que no hacen nada sin los parámetros de la línea de comandos. Los más rápidos (al no hacer nada) y la mayoría de la luz (de acuerdo con mis pruebas) son subst.exe y doskey.exe
  3. Entonces, en la primera línea, hago frente a doskey.exe con ''.exe (si aún no existe) y luego continúo usándolo como ''& (ya que la extensión .exe debe estar en % PATHEXT% ). Esto será tomado como comentario en VBScript y en lote no hará nada, simplemente continuará con el siguiente comando en la línea.

Hay algunos defectos, por supuesto. Al menos para la primera ejecución, finalmente necesitarás permisos de administrador ya que se puede denegar la protección en %windir%/System32/ mayor robustez, también puedes usar ''>nul 2>&1|| copy /Y %windir%/System32/doskey.exe ./'.exe >nul ''>nul 2>&1|| copy /Y %windir%/System32/doskey.exe ./'.exe >nul y luego al final: ''& rem del /q ./'.exe

Con ''.exe en tu camino, podrías usarlo de manera poco inteligente, y la ejecución en cada línea de'' .exe eventualmente podría disminuir el rendimiento.

..Y en la parte del lote los comandos deben estar solo en una línea.

Actualización 9.10.13 (... siguiendo la convención anterior)

Aquí hay otra forma que requiere el cambio de nombre del archivo por lotes:

@echo off goto :skip_xml_comment <!-- :skip_xml_comment echo( echo Echo from the batch echo( ( ren %0 %0.wsf cscript %0.wsf ren %0.wsf %0 ) exit /b 0 --> <package> <job id="vbs"> <script language="VBScript"> WScript.Echo "Echo from the VBS" </script> </job> </package>

Y una breve explicación:

  1. Cuando el lote se renombra automáticamente y se renombra de nuevo con el nombre antiguo, y esto se hace en una línea (o entre paréntesis), la secuencia de comandos se ejecutará sin errores. En este caso, también se agrega una llamada de CSCRIPT.EXE con .WSF Archivo .WSF auto-cambio de nombre es un poco arriesgado, pero más rápido que un archivo temporal.
  2. El host de scripts de Windows no se preocupa demasiado por los elementos que están fuera de los datos xml, siempre que no haya símbolos xml especiales & < > ; entonces @echo off y goto se pueden usar sin preocupaciones. Pero para mayor seguridad, es bueno poner los comandos por lotes en la sección xml comment (o CDATA) .Para evitar los mensajes de error del lote, me he saltado el <!-- con goto aquí.
  3. Antes de cerrar el script de lotes de comentarios xml finaliza con exit

Así que lo bueno es que no hay necesidad de escribir todo el código de lote en comandos de una sola línea, no se muestra ningún echo off desagradable, el código jscript y diferentes trabajos podrían agregarse al guión. Tampoco se necesitan símbolos especiales ni creación de archivos exe adicionales. como ''.exe

Por otro lado, el cambio de nombre puede ser arriesgado.


Nota: vaya a la sección ACTUALIZAR 2014-04-27 en la parte inferior de esta respuesta para obtener la mejor solución.

Solía ​​pensar que la respuesta era no. Pero el usuario de DosTips Liviu descubrió que el carácter <SUB> (Ctrl-Z, 0x1A, decimal 26) tiene efectos bizarros cuando está incrustado dentro de un archivo por lotes. Si funciona de forma similar a un terminador de línea, de modo que es posible que los comandos de proceso por lotes sigan un REM (o un :: comentario de corte) para ejecutar si están precedidos por Ctrl-Z. http://www.dostips.com/forum/viewtopic.php?p=13160#p13160

Esto se ha confirmado en XP Home Edition sp3, Vista Home Premium sp2 de 64 bits y Vista Enterprise sp2 de 32 bits. Supongo que funciona en otras versiones de Windows.

Nota : se supone que el código siguiente tiene incrustados caracteres Ctrl-Z. Juro que los veía en este sitio cuando los veía con IE8. Pero parece que se han perdido de este post de alguna manera y no puedo encontrar la manera de publicarlos nunca más. He reemplazado los caracteres con la cadena <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

Esa es la clave de un exitoso híbrido por lotes / vbs. Siempre que cada comando de lote esté precedido por rem<SUB> o ::''<SUB> , el motor vbs no lo verá, pero se ejecutará el comando por lotes. Solo asegúrese de finalizar la porción del lote con una EXIT o EXIT /B Entonces, el resto de la secuencia de comandos puede ser vbs de aspecto normal.

Incluso puede tener una etiqueta de lote si es necesario. :''Label es un comentario válido de vbs y una etiqueta de lote válida.

Aquí hay un guión híbrido trivial. (nuevamente con <SUB> en lugar del carácter incrustado Ctrl-Z)

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

Actualización 2012-04-15

jeb encontró una solución que evita el incómodo CTRL-Z, pero imprime ECHO OFF al inicio y también establece algunas variables extrañas.

He encontrado una solución sin CTRL-Z que elimina las variables extrañas y es más simple de comprender.

Normalmente los caracteres especiales & , | , < , > etc. no funcionan después de una declaración REM en lote. Pero los personajes especiales funcionan después de REM. . Encontré esta pepita de información en http://www.dostips.com/forum/viewtopic.php?p=3500#p3500 . Una prueba muestra que REM. sigue siendo un comentario válido de VBS. EDITAR - basado en el comentario de jeb, es más seguro usar REM^ (hay un espacio después de la intercalación).

Entonces aquí hay un híbrido VBS / batch trivial usando REM^ & . El único inconveniente es que imprime REM & al principio, mientras que la solución de jeb imprime ECHO OFF .

rem^ &@cscript //nologo //e:vbscript "%~f0" & exit /b WScript.Echo "Example of a hybrid VBS / batch file"

Aquí hay otro ejemplo trivial que muestra múltiples comandos por lotes, incluyendo una LLAMADA a una sub-rutina etiquetada.

::'' 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)

Todavía me gusta la solución CTRL-Z porque elimina toda salida extraña.

ACTUALIZACIÓN 2012-12-17

Tom Lavedas publicó un método para ejecutar convenientemente VBS dinámico a partir de un script por lotes en Grupos de Google: sin secuencias de comandos híbridas VBS . El método usa mshta.exe (host de aplicaciones HTML de Microsoft).

Su solución de lote original dependía de un pequeño script externo VBS.BAT para ejecutar el VBS dentro de un FOR / F. Modifiqué la sintaxis ligeramente para hacer que sea conveniente insertar directamente dentro de cualquier secuencia de comandos por lotes.

Es bastante lento, pero muy conveniente. Está restringido a la ejecución de una sola línea de VBS.

El VBS se escribe normalmente, excepto que todas las comillas se deben duplicar: una cita que contenga una cadena se debe escribir como "" , y las comillas internas de una cadena se deben escribir como """" . Normalmente, el mini script se ejecuta dentro de la cláusula IN () de un FOR / F. Se puede ejecutar directamente, pero solo si stdout ha sido redirigido o canalizado.

Debería funcionar en cualquier sistema operativo Windows desde XP en adelante mientras IE esté instalado.

@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

ACTUALIZACIÓN 2014-04-27

En DosTips hay un gran compendio de híbridos js / vbs / html / hta y quimeras en cmd / bat . Muchas cosas buenas de varias personas.

Dentro de ese hilo, el usuario de DosTips Liviu descubrió una hermosa solución híbrida VBS / por lotes que usa WSF.

<!-- : 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>

Creo que esta solución es fantástica. Las secciones de lotes y WSF están claramente separadas por lindos encabezados. El código del lote es absolutamente normal, sin ninguna sintaxis impar. La única restricción es que el código del lote no puede contener --> .

Del mismo modo, el código VBS dentro de WSF es absolutamente normal. La única restricción es que el código VBS no puede contener </script> .

El único riesgo es el uso no documentado de "%~f0?.wsf" como script para cargar. De alguna manera, el analizador encuentra y carga correctamente el script .BAT en ejecución "%~f0" , y el sufijo ?.wsf instruye misteriosamente a CSCRIPT para que interprete el script como WSF. Esperemos que MicroSoft nunca deshabilite esa "característica".

Como la solución usa WSF, la secuencia de comandos por lotes puede contener cualquier cantidad de VBS, JScript u otros trabajos independientes a los que se pueda llamar selectivamente. Cada trabajo puede incluso utilizar múltiples idiomas.

<!-- : 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>


EDITAR: Mi primera respuesta fue incorrecta para VBScript, ahora mi próximo intento ...

Buena idea para usar CTRL-Z, pero no me gustan los caracteres de control en un archivo por lotes, ya que es problemático copiarlos y pegarlos.
Depende de tu navegador, de tu editor, de tu ...

También puede obtener un VBScript / Batch híbrido con caracteres normales y un código "normal".

:''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

El truco es anteponer cada línea de lote con el set n=n''& es legal para ambos, pero vbs ignorará el resto de la línea, solo el lote ejecutará el resto de la línea.

La otra variante es :''remark ^ , esta es una observación para ambos, pero para el lote, esto también indica la siguiente línea del carácter multilínea.
El VbScript ve entonces a=1<1 el resto de la línea es un comentario ''
El lote ve solo <1'' echo off <nul , el primer redireccionamiento desde 1'' será anulado por el segundo <nul , por lo que resulta en solo echo off < nul .

El único problema restante es que puede ver el primer echo off , ya que no funciona por lotes para usar el @ después de una redirección.

Para JScript existe una solución más simple de scripting híbrido