web-dev-qa-db-fra.com

Est-il possible d'incorporer et d'exécuter VBScript dans un fichier batch sans utiliser de fichier temporaire?

Les gens intègrent et exécutent VBScript dans des fichiers de commandes depuis longtemps. Mais toutes les solutions publiées que j'ai vues (au moment où cette question a été posée à l'origine) impliquent l'écriture d'un fichier VBS temporaire. Par exemple: Intégrer VBScript dans le fichier batch de Windows .

Est-il possible d'exécuter VBScript incorporé dans un lot sans écrire de fichier temporaire?

38
dbenham

Remarque - passez au MISE À JOUR 2014-04-27section au bas de cette réponse pour la meilleure solution.

Je pensais que la réponse était non. Mais alors l'utilisateur de DosTips Liviu a découvert que le <SUB> le caractère (Ctrl-Z, 0x1A, décimal 26) a des effets bizarres lorsqu'il est incorporé dans un fichier de commandes. Si fonctionne un peu comme un terminateur de ligne de sorte qu'il est possible pour les commandes batch qui suivent un REM (ou un hack :: remarque)) de s'exécuter si elles sont précédées de Ctrl-Z. http://www.dostips.com/forum/viewtopic.php?p=13160#p1316

Cela a été confirmé sur XP Home Edition sp3, Vista Home Premium sp2 64 bits et Vista Enterprise sp2 32 bits. Je suppose que cela fonctionne sur d'autres versions de Windows.

Remarque - le code ci-dessous est censé contenir des caractères Ctrl-Z. Je jure que je les voyais sur ce site lorsqu'ils sont consultés avec IE8. Mais ils semblent avoir été perdus de cette façon et je ne sais plus comment les publier. J'ai remplacé les caractères par la chaîne <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

C'est la clé d'un hybride batch/vbs réussi. Tant que chaque commande batch est précédée de rem<SUB> ou ::'<SUB>, le moteur vbs ne le verra pas, mais la commande batch sera exécutée. Assurez-vous simplement de terminer la partie de lot avec un EXIT ou EXIT /B. Ensuite, le reste du script peut être des vbs d'apparence normale.

Vous pouvez même avoir une étiquette de lot si nécessaire. :'Label est à la fois un commentaire VBS valide et une étiquette de lot valide.

Voici un script hybride trivial. (à nouveau avec <SUB> à la place du caractère Ctrl-Z intégré)

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

Mise à jour 2012-04-15

jeb a trouvé une solution qui évite le CTRL-Z maladroit, mais il imprime ECHO OFF au début et définit également des variables étrangères.

J'ai trouvé une solution sans CTRL-Z qui élimine les variables étrangères et est plus simple à comprendre.

Normalement, les caractères spéciaux &, |, <, > etc. ne fonctionne pas après une instruction REM en batch. Mais les caractères spéciaux fonctionnent après REM.. J'ai trouvé cette pépite d'informations sur http://www.dostips.com/forum/viewtopic.php?p=3500#p35 . Un test montre que REM. est toujours un commentaire VBS valide. [~ # ~] modifier [~ # ~] basé sur le commentaire de jeb, il est plus sûr à utiliser REM^ (il y a un espace après le curseur).

Voici donc un hybride VBS/batch trivial utilisant REM^ &. Le seul inconvénient est qu'il imprime REM & au début, alors que la solution de jeb imprime ECHO OFF.

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

Voici un autre exemple trivial qui illustre plusieurs commandes batch, y compris un appel à une sous-routine étiquetée.

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

J'aime toujours la solution CTRL-Z car elle élimine toute sortie étrangère.

MISE À JOUR 2012-12-17

Tom Lavedas a publié une méthode pour exécuter facilement VBS dynamique à partir d'un script batch sur Google Groupes: Pas de script hybride VBS de fichier . La méthode utilise mshta.exe (Microsoft HTML Application Host).

Sa solution par lots d'origine reposait sur un petit script VBS.BAT externe pour exécuter le VBS dans un FOR/F. J'ai légèrement modifié la syntaxe pour la rendre pratique à intégrer directement dans un script batch donné.

C'est assez lent, mais très pratique. Il est limité à l'exécution d'une seule ligne de VBS.

Le VBS est écrit normalement, sauf que toutes les citations doivent être doublées: Une citation contenant une chaîne doit être écrite comme "", et les guillemets internes à une chaîne doivent être écrits comme """". Normalement, le mini script est exécuté dans la clause IN () d'un FOR/F. Il peut être exécuté directement, mais uniquement si stdout a été redirigé ou canalisé.

Il devrait fonctionner sur n'importe quel système d'exploitation Windows à partir de XP en avant tant que IE est installé.

@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

MISE À JOUR 2014-04-27

Chez DosTips, il existe un grand recueil de hybrides et chimères js/vbs/html/hta en cmd/bat . Beaucoup de bonnes choses de diverses personnes.

Dans ce fil, Liviu, utilisateur de DosTips, a découvert une solution magnifique hybride VBS/batch qui utilise 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>

Je pense que cette solution est fantastique. Les sections batch et WSF sont clairement séparées par des en-têtes Nice. Le code batch est absolument normal, sans aucune syntaxe étrange. La seule restriction est que le code de lot ne peut pas contenir -->.

De même, le code VBS dans WSF est absolument normal. La seule restriction est que le code VBS ne peut pas contenir </script>.

Le seul risque est l'utilisation non documentée de "%~f0?.wsf" comme script à charger. L'analyseur recherche et charge correctement le script .BAT en cours d'exécution "%~f0", et le ?.wsf le suffixe demande mystérieusement à CSCRIPT d'interpréter le script comme WSF. Espérons que Microsoft ne désactivera jamais cette "fonctionnalité".

Étant donné que la solution utilise WSF, le script de commandes peut contenir n'importe quel nombre de travaux VBS, JScript ou autres indépendants pouvant être appelés de manière sélective. Chaque travail peut même utiliser plusieurs langues.

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

EDIT: Ma première réponse était incorrecte pour VBScript, maintenant mon prochain essai ...

Belle idée d'utiliser CTRL-Z, mais je n'aime pas les caractères de contrôle dans un fichier de commandes, car il est problématique de les copier-coller.
Cela dépend de votre navigateur, de votre éditeur, de votre ...

Vous pouvez également obtenir un VBScript/Batch hybride avec des caractères normaux et un code "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

L'astuce consiste à ajouter à chaque ligne de lot set n=n'& c'est légal pour les deux, mais vbs ignorera le reste de la ligne, seul le batch exécutera le reste de la ligne.

L'autre variante est :'remark ^, il s'agit d'une remarque pour les deux, mais pour le lot, cette remarque concerne également la ligne suivante par le caractère multiligne.
Le VbScript voit alors a=1<1 le reste de la ligne est une remarque '
Le lot ne voit que <1' echo off <nul, la première redirection de 1' sera remplacé par le deuxième <nul, il en résulte que echo off < nul.

Le seul problème restant est que vous pouvez voir le premier echo off, car cela ne fonctionne pas en batch pour utiliser le @ après une redirection.

Pour JScript existe une solution plus simple script hybride

11
jeb

J'ai essayé d'assembler toutes les solutions dans un seul script à http://www.dostips.com/forum/viewtopic.php?p=37780#p3778 .

Il y a le script batch qui convertit les langues les plus populaires en un fichier batch (. Js , . Vbs , . ps1 , . wsf , . hta et historique . pl ).

Cela fonctionne comme suit:

 
 :: convertir filename1.vbs en exécutable filename1.bat 
 cmdize.bat filename1.vbs 
 
3
jsxt

Et ma tentative ( d'abord posté ici ). Cela ressemble à la solution du jeb, mais (au moins selon moi) le code est plus lisible:

: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

Et l'explication:

  1. ' (guillemet simple) n'est pas un symbole interdit dans le cadre d'un nom de fichier dans Windows, donc il n'y a pas de problème d'avoir un fichier appelé '.exe
  2. Il y a peu de commandes emballées avec des fenêtres qui ne font rien sans paramètres de ligne de commande. Les plus rapides (à ne rien faire) et les plus légères en taille (selon mes tests) sont subst.exe et doskey.exe
  3. Donc, à la première ligne, je fais face à la doskey.exe à '.exe (s'il n'existe pas déjà), puis continuez à l'utiliser comme '& (comme l'extension .exe devrait être dans % PATHEXT% ). Cela sera considéré comme un commentaire dans VBScript et dans le lot ne fera rien - va simplement continuer avec la prochaine commande sur la ligne.

Il y a bien sûr quelques défauts. Au moins pour la première exécution, vous aurez éventuellement besoin d'autorisations d'administrateur en tant que coping dans %windir%\System32\ peut être refusé. Pour la robustesse, vous pouvez également utiliser '>nul 2>&1|| copy /Y %windir%\System32\doskey.exe .\'.exe >nul puis à la fin: '& rem del /q .\'.exe

Avec '.exe laissé sur votre chemin, vous pourriez involontairement l'utiliser de manière incorrecte, et l'exécution sur chaque ligne de '.exe pourrait éventuellement diminuer les performances.

..Et dans le lot, les commandes ne doivent être que sur une seule ligne.

Mise à jour 9.10.13 (..suivant la convention ci-dessus)

Voici une autre façon qui nécessite l'auto-renommage du fichier batch:

@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>

Et une courte explication:

  1. Lorsque le lot est auto-renommé et renommé à nouveau avec l'ancien nom, et cela se fait sur une seule ligne (ou entre crochets), le script sera exécuté sans erreur.Dans ce cas, un appel de CSCRIPT.EXE avec .WSF fichier. L'auto-renommage est un peu risqué, mais plus rapide qu'un fichier temporaire.
  2. L'hôte de script Windows ne se soucie pas beaucoup des éléments en dehors des données xml tant qu'il n'y a pas de symboles xml spéciaux & < > ; donc @echo off et goto peuvent être utilisés sans soucis. Mais pour des raisons de sécurité, il est bon de mettre des commandes par lots dans la section des commentaires xml (ou CDATA). Pour éviter les messages d'erreur du lot, j'ai ignoré le <!-- avec goto ici.
  3. Avant de fermer le script batch de commentaires xml se termine par exit

Donc, les bonnes choses sont qu'il n'est pas nécessaire d'écrire tout le code batch dans des commandes sur une seule ligne, il n'y a pas de _ echo off affiché, du code jscript et différents travaux peuvent être ajoutés au script.Pas besoin de symboles spéciaux et de création de fichiers exe supplémentaires comme '.exe

En revanche, l'auto-renommage peut être risqué.

3
npocmaka

Il existe une solution très simple à ce problème. Utilisez simplement un Autre flux de données (ADS) pour stocker le code VBS. Pour l'expliquer simplement, un ADS est un autre endroit où vous pouvez stocker d'autres données dans le même fichier, c'est-à-dire qu'un fichier est composé de ses données d'origine plus n'importe quel nombre de ADS supplémentaires. Chaque ADS est identifié en séparant son propre nom du nom de fichier d'origine via deux points. Par exemple:

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

Vous pouvez trouver une description plus technique et détaillée des ADS sur le Web, mais il est important de mentionner maintenant que cette fonctionnalité fonctionne sur les disques NTFS seulement. Maintenant, voyons comment utiliser cette fonctionnalité pour résoudre ce problème particulier.

Commencez par créer le fichier batch d'origine de la manière habituelle. Vous pouvez également démarrer notepad.exe à partir de la ligne de commande de cette façon:

notepad test.bat

Pour mon exemple, j'ai inséré les lignes suivantes dans 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%"

Notez le nom du script VBS. Après test.bat a été enregistré et le Bloc-notes fermé, créez le script VBS à l'aide du Bloc-notes, entrez donc cette commande sur la ligne de commande:

notepad test.bat:script_.vbs

Et créez le script de la manière habituelle:

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

Enregistrez ce fichier et exécutez test.bat. Ça marche! ;)

Vous pouvez consulter les ADS de test.bat fichier via le /R basculez dans la commande dir. Vous pouvez lire une explication plus détaillée de cette méthode et de ses limites à ce post .

2
Aacini