É possível incorporar e executar o VBScript dentro de um arquivo em lotes sem usar um arquivo temporário?

As pessoas incorporam e executam o VBScript em arquivos de lote por um longo tempo. Mas todas as soluções publicadas que vi (no momento em que essa questão foi originalmente colocada) envolvem a gravação de um arquivo VBS temporário. Por exemplo: Incorporar o VBScript dentro do arquivo em lotes do Windows .

É possível executar o VBScript incorporado no lote sem gravar um arquivo temporário?

Nota – pule para a seção UPDATE 2014-04-27 na parte inferior desta resposta para obter a melhor solução.

Eu costumava pensar que a resposta era não. Mas o usuário do DosTips, Liviu, descobriu que o caractere (Ctrl-Z, 0x1A, decimal 26) tem efeitos bizare quando incorporado em um arquivo de lote. Se funciona um pouco como um terminador de linha, é possível que os comandos em lote que seguem um REM (ou um :: observação hack) sejam executados se forem precedidos por Ctrl-Z. http://www.dostips.com/forum/viewtopic.php?p=13160#p13160

Isso foi confirmado no XP Home Edition SP3, no Vista Home Premium SP2 de 64 bits e no Vista Enterprise SP2 de 32 bits. Eu estou supondo que funciona em outras versões do Windows.

Notao código abaixo deve ter caracteres Ctrl-Z incorporados. Eu juro que eu costumava vê-los neste site quando visto com o IE8. Mas eles parecem ter sido perdidos deste post de alguma forma e eu não consigo mais descobrir como publicá-los. Eu substituí os caracteres pela string

 ::echo This will execute in batch, but it will fail as vbs. remecho This will execute in batch, and it is also a valid vbs comment ::'echo This will execute in batch and it is also a valid vbs comment 

Essa é a chave para o sucesso de um lote / vbs híbrido. Contanto que cada comando em lote seja precedido por rem ou ::' , o mecanismo vbs não o verá, mas o comando em lote será executado. Apenas certifique-se de terminar a parte do lote com um EXIT ou EXIT /B Em seguida, o restante do script pode ser normal procurando vbs.

Você pode até ter um label de lote, se necessário. :'Label é um comentário vbs válido e um label de lote válido.

Aqui está um script híbrido trivial. (novamente com no lugar do caractere Ctrl-Z embutido)

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

Atualização 2012-04-15

O jeb encontrou uma solução que evita o desajeitado CTRL-Z, mas imprime o ECHO OFF no início e também define algumas variables ​​estranhas.

Eu encontrei uma solução sem CTRL-Z que elimina as variables ​​estranhas e é mais simples de compreender.

Normalmente os caracteres especiais & | , < , > etc. não funcionam após uma instrução REM em lote. Mas os caracteres especiais funcionam depois do REM. . Eu encontrei este pedaço de informação em http://www.dostips.com/forum/viewtopic.php?p=3500#p3500 . Um teste mostra que REM. ainda é um comentário válido da VBS. EDIT - com base no comentário de jeb, é mais seguro usar REM^ (há um espaço após o cursor).

Então aqui está um híbrido VBS / batch trivial usando o REM^ & . A única desvantagem é que imprime REM & no início, enquanto a solução de jeb imprime ECHO OFF .

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

Aqui está outro exemplo trivial que demonstra vários comandos em lote, incluindo uma CHAMADA para uma sub-rotina rotulada.

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

Eu ainda gosto da solução CTRL-Z porque elimina todas as saídas externas.

ATUALIZAÇÃO 2012-12-17

Tom Lavedas postou um método para executar convenientemente o VBS dynamic a partir de um script em lote nos Grupos do Google: Nenhum script VBS de arquivo híbrido . O método usa mshta.exe (Microsoft HTML Application Host).

Sua solução de lote original contava com um pequeno script VBS.BAT externo para executar o VBS dentro de um FOR / F. Eu modifiquei a syntax ligeiramente para facilitar a incorporação direta em qualquer script em lote.

É muito lento, mas muito conveniente. É restrito a executar uma única linha de VBS.

O VBS é escrito normalmente, exceto que todas as aspas devem ser dobradas: uma aspas que contenham uma string devem ser escritas como "" , e aspas internas a uma string devem ser escritas como """" . Normalmente, o mini script é executado dentro da cláusula IN () de um FOR / F. Pode ser executado diretamente, mas somente se o stdout tiver sido redirecionado ou canalizado.

Ele deve funcionar em qualquer sistema operacional Windows a partir do XP enquanto o IE estiver 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 

ATUALIZAÇÃO 2014-04-27

Em DosTips há um grande compêndio de js / vbs / html / hta híbridos e quimeras em cmd / bat . Muita coisa boa de várias pessoas.

Nesse segmento, o usuário da DosTips Liviu descobriu uma bela solução híbrida VBS / batch que usa o WSF.

   

Eu acho que essa solução é fantástica. As seções batch e WSF são claramente separadas por headers agradáveis. O código do lote é absolutamente normal, sem qualquer syntax ímpar. A única restrição é que o código do lote não pode conter --> .

Da mesma forma, o código VBS no FSM é absolutamente normal. A única restrição é o código VBS não pode conter .

O único risco é o uso indocumentado de "%~f0?.wsf" como o script para carregar. De alguma forma, o analisador localiza e carrega corretamente o script .BAT em execução "%~f0" , e o sufixo ?.wsf instrui misteriosamente o CSCRIPT a interpretar o script como FSM. Espero que a MicroSoft nunca desabilite esse "recurso".

Como a solução usa o WSF, o script em lote pode conter qualquer número de VBS, JScript ou outros trabalhos independentes que possam ser chamados seletivamente. Cada trabalho pode até utilizar vários idiomas.

            

EDIT: Minha primeira resposta foi errada para o VBScript, agora a minha próxima tentativa …

É uma boa idéia usar o CTRL-Z, mas não gosto de caracteres de controle em um arquivo em lotes, pois é problemático copiá-los e colá-los.
Depende do seu navegador, do seu editor, do seu …

Você pode obter um VBScript / Batch híbrido também com caracteres normais e código “normal”.

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

O truque é prefixar cada linha de lote com o set n=n'& é legal para ambos, mas vbs irá ignorar o resto da linha, somente o lote executará o resto da linha.

A outra variante é :'remark ^ , isso é uma observação para ambos, mas para lote isso também observa a próxima linha pelo caractere multilinha.
O VbScript vê então a=1<1 o resto da linha é um comentário '
O lote vê apenas <1' echo off , o primeiro redirecionamento de 1' será substituído pelo segundo , portanto, resulta em apenas echo off < nul .

O único problema remanescente é que você pode ver o primeiro echo off , pois ele não funciona em lote para usar o @ após um redirecionamento.

Para JScript existe uma solução mais simples de script híbrido

E minha tentativa ( primeiro postada aqui ). Ele se assemelha a solução do jeb, mas (pelo menos de acordo comigo) o código é mais legível:

 :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 

E a explicação:

  1. (aspas simples) não é um símbolo proibido como parte de um nome de arquivo no Windows, portanto não há problema em ter um arquivo chamado '.exe
  2. Existem alguns comandos cheios de janelas que não fazem nada sem parâmetros de linha de comando. O mais rápido (em fazer nada) e mais leve como um tamanho (de acordo com os meus testes) são subst.exe e doskey.exe
  3. Então, na primeira linha eu estou lidando com o doskey.exe para '.exe (se já não existir) e, em seguida, continuar usando como '& (como a extensão .exe deve estar em % PATHEXT% ). Isso será tomado como um comentário no VBScript e em lote não fará nada – apenas continuará com o próximo comando na linha.

Existem algumas falhas, é claro. Pelo menos na primeira execução, você precisará de permissions de administrador, pois o enfrentamento em %windir%\System32\ pode ser negado. Para maior robustez, você também pode usar '>nul 2>&1|| copy /Y %windir%\System32\doskey.exe .\'.exe >nul '>nul 2>&1|| copy /Y %windir%\System32\doskey.exe .\'.exe >nul e, em seguida, no final: '& rem del /q .\'.exe

Com '.exe deixado em seu caminho você pode involuntariamente usá-lo de forma inadequada, e a execução em cada linha de’ .exe eventualmente poderia diminuir o desempenho.

..E nos comandos da parte do lote deve ser apenas em uma linha.

Atualização 9.10.13 (.. seguindo a convenção acima)

Aqui está mais uma forma que requer auto-renomeação do arquivo de lote:

 @echo off goto :skip_xml_comment       

E uma breve explicação:

  1. Quando o lote é auto-renomeado e renomeado novamente com o nome antigo, e isso é feito em uma linha (ou entre colchetes) o script será executado sem erros.Neste caso, é adicionado também uma chamada de CSCRIPT.EXE com .WSF Arquivo WSF.A renomeação pode ser um pouco arriscada, mas mais rápida que um arquivo temporário.
  2. O host de script do Windows não se importa muito com itens fora dos dados xml, desde que não haja símbolos xml especiais & <> ; so @echo off e goto podem ser usados ​​sem preocupações. Mas, por segurança, é bom colocar comandos em lote na seção de comentários em xml (ou CDATA) .Para evitar mensagens de erro do lote, eu pulei o

    Eu tentei montar todas as soluções em um script em http://www.dostips.com/forum/viewtopic.php?p=37780#p37780 .

    Há o script em lote que converte os idiomas mais populares em um arquivo em lotes ( .js , .vbs , .ps1 , .wsf , .hta e histórico .pl ).

    Funciona da seguinte maneira:

    
         :: convert nome_do_arquivo1.vbs para o executável nome_do_arquivo1.bat
         cmdize.bat filename1.vbs
    
    
  3. Existe uma solução muito simples para este problema. Basta usar um stream de dados alternativos (ADS) para armazenar o código VBS. Para explicá-lo simplesmente, um ADS é outro lugar onde você pode armazenar outros dados no mesmo arquivo , ou seja, um arquivo é composto de seus dados originais mais qualquer número de ADSs adicionais . Cada ADS é identificado separando seu próprio nome do nome do arquivo original por dois pontos. Por exemplo:

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

    Você pode encontrar uma descrição mais detalhada e abrangente de ADSs na Web, mas é importante mencionar agora que esse recurso funciona apenas em discos NTFS. Agora, vamos ver como usar esse recurso para resolver esse problema específico.

    Primeiro, crie o arquivo de lote original da maneira usual. Você também pode iniciar o notepad.exe a partir da linha de comando:

     notepad test.bat 

    Para o meu exemplo, inseri as seguintes linhas no 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%" 

    Anote o nome do script VBS. Depois que test.bat foi salvo e o Bloco de Notas foi fechado, crie o script VBS usando o Bloco de Notas, portanto, insira este comando na linha de comando:

     notepad test.bat:script_.vbs 

    E crie o script da maneira usual:

     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 

    Salve este arquivo e execute test.bat . Funciona! ;)

    Você pode revisar o arquivo ADS do test.bat por meio do comando /R no comando dir . Você pode ler uma explicação mais detalhada sobre este método e suas limitações neste post .