Daten|teiler
Kopieren als Kulturtechnik

Wie man in der Batch professionelle Fenster erzeugt

29. Dezember 2011 von Christian Imhorst

Trotz Powershell wird es noch einige Zeit dauern, bis das Batch Scripting mit der cmd.exe ausstirbt. Bis dahin eignet es sich gut dazu, kleine Programme für die Steuerung von Windows zu erstellen. Als Systemverwalter, Entwickler oder Power-User kann man durch den Einsatz von Batch-Skripten einfach und schnell Zeit sparen. Da wir in einer Welt wunderbarer Aufklapp- und Popup-Menüs leben, wünschen sich viele Anwender diese Funktionen auch in der Shell, was die cmd.exe aber nicht bietet. Es gibt allerdings einen Trick, indem man ein temporäres VBScript erstellt, das dann ein Fenster erzeugt. Damit sorgt man in seinem Batchprogramm nicht nur für mehr Übersicht und mehr Professionalität in den Augen des Anwenders, man kann auch Variablen zwischen dem VBScript umd dem Batchprogramm austauschen.

@echo off
title Demo um Variablen von VBScript an CMD zuzuweisen
color 2F
mode 55,9

:: Set variable for InputBox:
set myMessage=Hallo, wie ist dein Name?
set myTitle=Bitte Namen eingeben
call :subInputBox

:: Display variable
if "%flag%"=="false" (
	set myMessage=Es wurde nichts eingegeben, oder die Eingabe abgebrochen.
	set myTitle=Keine Eingabe
	call :subMsgBox
) else (
	set myMessage=Hallo %cmdText%!
	set myTitle=Begrüßung
	call :subMsgBox
)
goto End

:: Start subroutine subInputBox
:subInputBox
set VBS="%Temp%\vbsInputBox.vbs"
set CMD="%Temp%\cmdVar.bat"
 
>> %VBS% echo Option Explicit 
>> %VBS% echo Dim strText  
>> %VBS% echo Dim objShell : Set objShell = CreateObject("Wscript.Shell")  
>> %VBS% echo Dim objFSO   : Set objFSO = CreateObject("Scripting.FileSystemObject") 
>> %VBS% echo Dim objFile  : Set objFile = objFSO.CreateTextFile(%CMD%) 
:: Pass variable from batch to VBScript
>> %VBS% echo strText = InputBox("%myMessage%", "%myTitle%")
>> %VBS% echo if strText = vbNullString then 
:: Create batch file
>> %VBS% echo objFile.WriteLine "@echo off"
>> %VBS% echo objFile.WriteLine "set flag=false" 
>> %VBS% echo else 
>> %VBS% echo objFile.WriteLine "@echo off"
:: Set variable in batch file
>> %VBS% echo objFile.WriteLine "set cmdText=" ^& strText  
>> %VBS% echo end if 
>> %VBS% echo objFile.Close  
 
cscript %VBS% > NUL
call %CMD% > NUL
 
del %CMD%
del %VBS%
 
goto :EOF
:: End subroutine subInputBox

:: Start subroutine subMsgBox
:subMsgBox
>> %Temp%\MsgBox.vbs echo MsgBox "%myMessage%", VbInformation + VbOKOnly, "%myTitle%" 
cscript %Temp%\MsgBox.vbs > NUL
del %Temp%\MsgBox.vbs
goto :EOF
:: End of subroutine subMsgBox

:: End of batch file
:End

Schauen wir uns das Skript Stück für Stück an, allerdings um ein paar Kommentare gekürzt, die mit den beiden Doppelpunkten :: beginnen.

@echo off
title Demo um Variablen von VBScript an CMD zuzuweisen
color 2F
mode 55,9

Das @-Zeichen ganz am Anfang des Skripts stellt die Ausgabe der Befehlszeile auf dem Bildschirm für den aktuellen Befehl aus. In diesem Fall ist es echo off, der die Befehlszeile für alle nachfolgenden Befehle ausschaltet, zumindest solange, bis ein echo on kommt. Danach werden Titel, Farbe und Form der aktuellen cmd.exe festgelegt.

set myMessage=Hallo, wie ist dein Name?
set myTitle=Bitte Namen eingeben
call :subInputBox

Mit set werden zwei Variablen myMessage und myTitle definiert, die den beschreibenden Text für die InputBox des VBScripts beinhalten. Anschließend wird mit call die Subroutine subInputBox aufgerufen. Seit Windows 2000 sind einfache Subroutinen in der Windows Shell möglich, indem vor der Subroutinen eine Sprungmarke definiert wird. Mit dem Aufruf call :<lable> wird der Ablauf des Skripts zum angegebenen Sprungziel geleitet. Nachdem die Ausführung in der Subroutine durch goto :EOF beendet wird, springt der Ablauf auf die Zeile hinter call :<lable> zurück und wird dort fortgesetzt. Um den logischen Ablauf des Skripts zu folgen, springen wir jetzt auch dort hin:

:: Start subroutine subInputBox
:subInputBox
set VBS="%Temp%\vbsInputBox.vbs"
set CMD="%Temp%\cmdVar.bat"
 
>> %VBS% echo Option Explicit 
>> %VBS% echo Dim strText  
>> %VBS% echo Dim objShell : Set objShell = CreateObject("Wscript.Shell")  
>> %VBS% echo Dim objFSO   : Set objFSO = CreateObject("Scripting.FileSystemObject") 
>> %VBS% echo Dim objFile  : Set objFile = objFSO.CreateTextFile(%CMD%) 
>> %VBS% echo strText = InputBox("%myMessage%", "%myTitle%")
>> %VBS% echo if strText = vbNullString then 
>> %VBS% echo objFile.WriteLine "@echo off"
>> %VBS% echo objFile.WriteLine "set flag=false" 
>> %VBS% echo else 
>> %VBS% echo objFile.WriteLine "@echo off"
>> %VBS% echo objFile.WriteLine "set cmdText=" ^& strText  
>> %VBS% echo end if 
>> %VBS% echo objFile.Close  
 
cscript %VBS% > NUL
call %CMD% > NUL
 
del %CMD%
del %VBS%
 
goto :EOF
:: End subroutine subInputBox

Am Anfang steht die Sprungmarke :subInputBox, zu der uns der Call-Aufruf geführt hat. Danach werden die Variablen VBS und CMD mit den Dateinamen gesetzt in denen der Code für das VBScript und die Batchdatei geschrieben werden. Durch die Umgebungsvariable %Temp% werden die beiden Dateien auch gleich in den temporären Ordner gespeichert. Dann wird jede einzelne Zeile des VBScripts mit Hilfe der Ausgabeumleitung >> der Reihe nach in die VBS-Datei geschrieben, deren Name zusammen mit den Pfad in der Variable %VBS% gespeichert wurde. Dabei sind folgende Zeilen interessant:

>> %VBS% echo Dim objFile  : Set objFile = objFSO.CreateTextFile(%CMD%) 
>> %VBS% echo strText = InputBox("%myMessage%", "%myTitle%")

Über die Batch-Variablen %CMD%, %myMessage% und %myTitle% werden Variablen bzw. deren Inhalt im VBScript gesetzt. In einer Zeile weiter unten ist das ganze dann andersherum: Eine Variable wird vom VBScript zurück in die Batchdatei geschrieben.

>> %VBS% echo objFile.WriteLine "set cmdText=" ^& strText

Dabei muss man allerdings darauf achten, dass das &-Zeichen mit einem ^ maskiert wird. Wenn man ein für die Batchdatei besonderes Zeichen benutzt, muss man es mit dem sogenannten Escape-Zeichen kennzeichnen, was auch quoten genannt wird. Auf diese Weise kann man auch XML-Dateien erzeugen, obwohl die Symbole für die Ein- und Ausgabeumleitung für Dateien < und > schon belegt sind.

Wenn das VBScript erstellt ist, wird es mit cscript %VBS% aufgerufen. Dabei startet cscript das Skript mit dem Windows Scripting Host im Kontext der Kommandozeile. Sollte dabei irgendeine Ausgabe auf der Konsole erfolgen wird das Ergebnis mit der Umleitung > nul ins Nirwana geschickt. Danach ruft call %CMD% die Batchdatei auf, die das VBScript erstellt hat. Wenn das erledigt ist, räumt der Befehl del auf, indem die beiden Dateien wieder gelöscht werden. Mit goto :EOF wird die Subroutine verlassen und zurück zum Ausgangspunkt gesprungen.

if "%flag%"=="false" (
	set myMessage=Es wurde nichts eingegeben, oder die Eingabe abgebrochen.
	set myTitle=Keine Eingabe
	call :subMsgBox
) else (
	set myMessage=Hallo %cmdText%!
	set myTitle=Begrüßung
	call :subMsgBox
)
goto End

Weiter geht es mit einer If-Bedingung. Der Inhalt der Variable %flag% wurde durch das VBScript an die temporäre Batchdatei cmdVar.bat übergeben, die dadurch den Weg in die aktuelle Batchdatei gefunden hat. Man könnte auch auf die Idee kommen, statt eines Flags eine Sprungmarke mit goto zu verwenden. Dummerweise lassen sich keine Sprungmarke von einer Batchdatei in eine andere übertragen.

Mit der If-Bedingung kann man anhand des Flags entscheiden, welcher Knopf in der InputBox gedrückt worden ist, OK oder Abbruch. Wurde Abbruch geklickt bzw. im Eingabefeld nichts eingegeben wird die Flag-Variable auf False gesetzt und der If-Zweig ausgeführt. Andernfalls kommt der Else-Zweig zum Einsatz. Mehrere Befehle können durch runde Klammern gruppiert werden, um den Code besser zu strukturieren. Zeilenumbrüche und Einrückungen sind dabei in Ordnung, wobei man beachten muss, dass die öffnende Klammer in der gleichen Zeile steht wie der If-Befehl, und dass vor dem Else-Befehl die schließende und danach wieder die öffnende Klammer in derselben Zeile stehen müssen. Hinter der schließenden und vor der öffnenden Klammer muss ein Leerzeichen sein, sonst funktioniert es nicht.

:: Start subroutine subMsgBox
:subMsgBox
>> %Temp%\MsgBox.vbs echo MsgBox "%myMessage%", VbInformation + VbOKOnly, "%myTitle%" 
cscript %Temp%\MsgBox.vbs > NUL
del %Temp%\MsgBox.vbs
goto :EOF
:: End of subroutine subMsgBox

In beiden Zweigen der If-Bedingung werden mit set Variablen definiert und danach die Subroutine subMsgBox aufgerufen, mit der wiederum ein VBScript erstellt wird, um eine MessageBox zu erzeugen. Nach dem Aufruf der MessageBox wird die temporäre Datei gelöscht und die Subroutine mit goto :EOF wieder verlassen. Das sich anschließende goto End überspringt die beiden Subroutinen und führt den Programmablauf an das Ende der Batchdatei.

:: End of batch file
:End

Es ist natürlich einfacher, die ganze Geschichte gleich in VBScript zu programmieren, doch es geht hier um die Demonstration professionell aussehende Fenster in einer Batchdatei zu erstellen und den Inhalt von Variablen aus der Batchdatei in diese Fenster zu übergeben und umgekehrt.

Literatur:

Geschrieben in Windows