web-dev-qa-db-ja.com

一時ファイルを使用せずにバッチファイル内にVBScriptを埋め込み、実行することはできますか?

長い間、人々はバッチファイル内にVBScriptを埋め込み、実行してきました。しかし、私が見たすべての公開されたソリューション(この質問が最初に提起された時点)は、一時的なVBSファイルの書き込みを伴います。例: Windowsバッチファイル内にVBScriptを埋め込む

一時ファイルを書き込まずにバッチ内で埋め込みVBScriptを実行することは可能ですか?

38
dbenham

注-にジャンプPDATE 2014-04-27セクション最良の解決策については、この回答の最下部。

答えはノーだと思っていました。しかし、その後DosTipsユーザーLiviuは、<SUB>文字(Ctrl-Z、0x1A、10進数26)がバッチファイルに埋め込まれた場合に奇妙な効果があることを発見しました。 REM(または::リマークハック)に続くバッチコマンドがCtrl-Zの前にある場合に実行できるように、ラインターミネーターのような機能がある場合。 http://www.dostips.com/forum/viewtopic.php?p=13160#p1316

これは、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

これがバッチ/ vbsハイブリッドの成功の鍵です。各バッチコマンドの前にrem<SUB>または::'<SUB>が付いている限り、vbsエンジンはそれを認識しませんが、バッチコマンドは実行されます。 EXITまたはEXIT /Bでバッチ部分を終了してください。その後、スクリプトの残りの部分は通常のvbsになります。

必要に応じて、バッチラベルを持つこともできます。 :'Labelは、有効なvbsコメントと有効なバッチラベルの両方です。

これは簡単なハイブリッドスクリプトです。 (埋め込みCtrl-Z文字の代わりに<SUB>を使用)

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

2012-04-15の更新

jebは、厄介なCTRL-Zを回避するソリューションを見つけましたが、開始時にECHO OFFを出力し、いくつかの無関係な変数を設定します。

CTRL-Zを使用せずに、無関係な変数を排除し、理解しやすいソリューションを見つけました。

通常、特殊文字&|<>などは、バッチのREMステートメントの後では機能しません。ただし、REM.の後でも特殊文字は機能します。 http://www.dostips.com/forum/viewtopic.php?p=3500#p35 でこの一連の情報を見つけました。テストは、REM.がまだ有効なVBSコメントであることを示しています。 [〜#〜] edit [〜#〜]-jebのコメントに基づいて、より安全ですREM^を使用します(キャレットの後にスペースがあります)。

そこで、REM^ &を使用した簡単なVBS /バッチハイブリッドを示します。唯一の欠点は、最初にREM &を出力するのに対して、jebのソリューションはECHO OFFを出力することです。

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

次に、ラベル付きサブルーチンへの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)

CTRL-Zソリューションは、余分な出力をすべて排除するため、今でも気に入っています。

PDATE 2012-12-17

Tom Lavedasは、Googleグループでバッチスクリプトから動的VBSを便利に実行するメソッドを投稿しました: No file VBS hybrid scripting 。このメソッドは、mshta.exe(Microsoft HTML Application Host)を使用します。

彼の元のバッチソリューションは、外部の小さなVBS.BATスクリプトに依存して、FOR/F内でVBSを実行していました。特定のバッチスクリプト内に直接埋め込むのが便利になるように、構文を少し変更しました。

かなり遅いですが、とても便利です。 VBSの単一行の実行に制限されています。

VBSは、すべての引用符を二重にする必要があることを除き、通常どおりに記述されます。文字列を囲む引用符は""として記述し、文字列内部の引用符は""""として記述します。通常、ミニスクリプトはFOR/FのIN()句内で実行されます。直接実行できますが、stdoutがリダイレクトまたはパイプされた場合のみです。

XPがインストールされている限り、IE以降のWindows OSで動作するはずです。

@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

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

このソリューションは素晴らしいと思います。バッチセクションとWSFセクションは、ニースヘッダーによって明確に区切られています。バッチコードは、異常な構文のない、まったく正常なものです。唯一の制限は、バッチコードに-->を含めることができないことです。

同様に、WSF内のVBSコードはまったく正常です。唯一の制限は、VBSコードに</script>を含めることができないことです。

唯一のリスクは、ロードするスクリプトとして"%~f0?.wsf"の文書化されていない使用です。どういうわけか、パーサーは実行中の.BATスクリプト"%~f0"を適切に検出してロードし、?.wsf接尾辞はスクリプトをWSFとして解釈するようにCSCRIPTに不可思議に指示します。マイクロソフトがその「機能」を無効にしないことを願っています。

ソリューションは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>
52
dbenham

編集:最初の答えは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

トリックは、各バッチ行にset n=n'&を追加することです。両方に有効ですが、vbsは残りの行を無視し、バッチのみが残りの行を実行します。

もう1つのバリアントは:'remark ^です。これは両方のコメントですが、バッチの場合、これは複数行の文字による次の行もコメントします。
VbScriptはa=1<1を確認し、残りの行は注釈'
バッチは<1' echo off <nulのみを認識し、1'からの最初のリダイレクトは2番目の<nulによってオーバーライドされるため、結果はecho off < nulのみになります。

残りの唯一の問題は、リダイレクト後にecho offを使用するバッチでは機能しないため、最初の@が表示されることです。

JScriptには、より単純なソリューションが存在します ハイブリッドスクリプト

11
jeb

http://www.dostips.com/forum/viewtopic.php?p=37780#p3778 の1つのスクリプトですべてのソリューションをアセンブルしようとしました。

最も一般的な言語をバッチファイルに変換するバッチスクリプトがあります(。js。vbs。ps1。wsf。htaおよび歴史的。pl)。

次のように機能します。

 
 :: filename1.vbsを実行可能なfilename1.bat 
 cmdize.bat filename1.vbs 
 
に変換します
3
jsxt

この問題には非常に簡単な解決策があります。 Alternate Data Stream(ADS)を使用してVBSコードを保存するだけです。簡単に説明すると、ADSは別の場所で、他のデータを保存できます同じファイルに、つまり、ファイルは元のデータと任意の数の追加のADS。各ADSは、コロンを介して元のファイル名から独自の名前を分離して識別されます。例えば:

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

WebでADSのより技術的で詳細な説明を見つけることができますが、この機能がNTFSディスクで動作することを言及することが重要ですonly。次に、この機能を使用してこの特定の問題を解決する方法を見てみましょう。

まず、通常の方法で元のバッチファイルを作成します。この方法でコマンドラインからnotepad.exeを起動することもできます。

notepad test.bat

私の例では、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%"

VBSスクリプトの名前に注意してください。 test.batを保存してメモ帳を閉じた後、メモ帳を使用してVBSスクリプトを作成するため、コマンドラインで次のコマンドを入力します。

notepad test.bat:script_.vbs

そして、通常の方法でスクリプトを作成します。

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

このファイルを保存して、test.batを実行します。できます! ;)

dirコマンドのtest.batスイッチを使用して、/RファイルのADSを確認できます。 this post で、このメソッドとその制限のより広範な説明を読むことができます。

2
Aacini