Home > Artikel > Ausgabe 4/2015 > Nützliche Helferlein per VBScript

Nützliche Helferlein per VBScript

Achtung: Sie sind nicht angemeldet. Wenn Sie Abonnent sind und sich anmelden, lesen Sie den kompletten Artikel, laden das PDF herunter oder probieren die Beispieldatenbank aus (sofern vorhanden).

Das Entwickeln von Access-Anwendungen ist das eine, der Umgang mit der Peripherie derselben das andere. So will Ihre Anwendung erst verteilt werden, oder Sie benötigen Systemaktionen, die sich unter Access nicht so ohne weiteres ausführen lassen. Dann könnten Ihnen möglicherweise extern gestartete Skripte weiterhelfen. Solche Skripte schauen wir uns in diesem Beitrag an.

Beispieldatenbank

Die Beispiele dieses Artikels finden Sie in der Datenbank 1504_ScriptingDemo.zip und den enthaltenen Dateien.

Script-Sprachen

Wenn Sie sich nach Möglichkeiten umsehen, um abseits von Access- und VBA-Programmierung unter Windows Makros auszuführen, so bieten sich etwa Batch-Dateien mit der Endung bat oder cmd an, die Kommandozeilenaktionen starten. Viel Freude werden Sie dabei wahrscheinlich nicht haben, da der Sprachumfang reichlich beschränkt ist und zudem die Kenntnis zahlreicher Kommandozeilenparameter erfordert. Erheblich ausgefeilter kommt da die Windows-Powershell daher, über die sich fast alles realisieren lässt. Sie verlangt Ihnen jedoch noch mehr Einarbeitung ab, die zudem wegen des objektorientierten Ansatzes nicht gerade leicht fällt.

So bleibt als leistungsfähiger Ausweg das standardmäßig unter Windows installierte Visual Basic Scripting, kurz VBScript. Das Gute an der Sache: Wenn Sie sich halbwegs mit VBA-Programmierung auskennen, so wird ihnen das Erstellen von VBScripten leicht von der Hand gehen, denn Syntax und Sprachumfang sind nahezu identisch. Auf einige Unterschiede gehen wir noch ein.

VBScripte

VBScript-Dateien sind einfache Textdateien mit der Endung vbs, die VBA-Code enthalten und von der Windows-Scripting-Engine ausgeführt werden. Diese Dateiendung ist automatisch mit einem der beiden Script-Prozessoren wscript.exe oder cscript.exe verknüpft.

Doppelklicken Sie also auf eine vbs-Datei, so startet in der Regel die wscript.exe, welche die Anweisungen dann abarbeitet. Dabei nimmt sich die Engine den Code zunächst genau unter die Lupe und testet ihn auf Syntaxfehler. Im Fehlerfall wird eine entsprechende Meldung geöffnet. Danach kompiliert sie ihn und startet die Prozedur. Aber auch dann, wenn die Syntax stimmt, kann es zu Fehlern etwa infolge falscher Parameter oder inkorrekter Objektansprache kommen. Dann ereignet sich ebenfalls eine Fehlermeldung und das Script wird an dieser Stelle abgebrochen.

An dieser Stelle ein Hinweis: VBScript ist an sich noch kein Sicherheitsrisiko, arbeitet jedoch nicht in abgeschotteter Umgebung. Zwar können Windows-API-Funktionen nicht aufgerufen – hier ein Unterschied zu VBA –, dafür aber beliebige ActiveX-Komponenten erzeugt werden, die ihrerseits allerlei Unbill hervorzubringen imstande wären. Aus diesem Grund werden die Script-Engines von Administratoren zuweilen gesperrt und die Ausführung von vbs-Dateien verhindert. Inzwischen kommt das immer seltener vor, denn über VBA-Programmierung, die ja Bestandteil von beliebigen Access-, Word- oder Excel-Dateien sein kann, sind noch viel mehr unheilvolle Aktionen möglich. Und diese Dateien werden ja auch nicht gesperrt.

VBScripte erzeugen

Nicht einfacher, als das! Legen Sie eine neue Textdatei an und speichern sie unter der Endung vbs ab. Schreiben Sie nur diese eine Zeile in sie:

Msgbox "Hallo! Bin ein VBScript!"

Doppelklicken Sie auf die dergestalt modifizierte Datei, und schon werden Sie mit dem Meldungsfenster beglückt, wenn Scripting nicht auf Ihrem System deaktiviert ist.

Die Tatsache, dass es sich nur um Textdateien handelt, eröffnet die Möglichkeit, Scripte auch aus Access heraus zu erstellen. Dazu wird der Code in eine String-Variable geschrieben und diese in das Dateisystem abgespeichert, wie etwa in der Prozedur in Listing 1. Der Variablen sScript wird die Codezeile von oben zugewiesen und über die Open-Anweisung eine Datei mit dem Namen test.vbs angelegt, wobei als Pfad das Verzeichnis der Datenbank (CurrentProject.Path) verwendet wird. Anschließend wird die vbs-Datei über die Script-Engine (wscript.exe) und die Shell-Anweisung aufgerufen.

Sub CreateVBScript()

     Dim sScript As String

     Dim sVBSFile as string

     sVBSFile = CurrentProject.Path & "\test.vbs"

     sScript = "Msgbox ""Ich bin ein VBScript!"""

     Open sVBSFile For Binary As #1

     Put #1, , sScript

     Close #1

     DoEvents

     Shell "wscript.exe " & sVBSFile

End Sub

Listing 1: Aus VBA heraus erzeugte VBS-Datei

Rufen Sie einfach die Prozedur CreateVBScript aus dem VBA-Direktfenster heraus auf und überzeugen Sie sich vom Erfolg der Routine.

Anwendungsfälle

Warum sollte man aus Access heraus ein VBScript aufrufen? Schließlich lässt sich ja über VBA dasselbe erreichen, wie über ein externes Skript. Das stimmt jedoch nicht immer. Manche Aufgaben können nur über administrative Rechte erledigt werden – etwa das Setzen von bestimmten Registry-Schlüsseln. Und da Access nun Mal nur unter normalen Benutzerrechten ausgeführt wird, kann derlei nicht vollzogen werden. Von der Lösung, Access dennoch als Administrator auszuführen, sollten Sie besser die Finger lassen, weil dann die Add-Ins von Access und VBA durcheinander geraten können.

Hier hilft ein VBScript aus, das Aufgaben unter erhöhten Benutzerrechten ausführt. Den dafür benötigten Code schauen wir uns später an.

Oft gebraucht wird ein Skript, das Ihre Datenbank überhaupt erst installiert. Nehmen wir an, Sie hätten alle Teile Ihrer Anwendung in einer Zip-Datei untergebracht. Da wäre es schön, wenn ein Script auf einem Zielrechner etwa folgende Aufgaben erledigen würde:

Entpacken des Archivs; Anlegen von Zielverzeichnissen; Kopieren von Dateien in die Zielverzeichnisse; Setzen des Vertrauenswürdigen Orts für die Datenbank; Anlegen einer Verknüpfung auf dem Desktop; und eventuell noch das Registrieren benötigter ActiveX-Komponenten. Auch hierfür gibt es ein umfangreiches Beispiel-Skript, welches auf den folgenden Seiten erläutert wird.

VBScript vs. VBA

Unter VBScript brauchen Sie, wie wir weiter oben bereits gesehen haben, keine Prozedur zu deklarieren. Das Script selbst stellt schon eine Prozedur dar. Sie können gleich zu Beginn im Code mit der ersten Anweisung beginnen. Es ist Ihnen jedoch unbenommen, trotzdem Prozeduren auf die gleiche Weise anzulegen, wie unter VBA. Solche Sub- oder Function-Prozeduren sind dann sinnvoll, wenn sie als Unterroutinen im Code öfters aufgerufen werden.

Variablen müssen unter VBScript nicht deklariert werden. Dies kommt dem Verhalten von VBA gleich, wenn kein Option Explicit im Modulkopf steht. VBScript-Variablen sind immer vom Typ Variant, was aber nicht bedeutet, dass ihr Sub-Typ nicht von Belang wäre. Funktionen etwa, die einen String als Parameter erwarten, kann kein Long-Wert übergeben werden. So eine Konversion nimmt VBS nicht automatisch vor.

Wenn Sie es gewohnt sind, unter VBA in For..Next-Schleifen die Zählervariable namentlich einzusetzen, so müssen Sie unter VBScript davon Abstand nehmen.

For i = 0 To 10

...

Next i

führt zu einem VBScript-Syntaxfehler. Korrekt wäre

For i = 0 To 10

...

Next

Darüber hinaus unterstützt VBScript nicht die Deklaration von API-Funktionen. Windows- oder andere DLLs können damit nicht angesprochen werden.

Außerdem fehlt ausgerechnet eine ganze Reihe von Datei-Anweisungen, wie Dir, FileCopy, FileLen oder FileDateTime. Auch der Befehl Shell zum Ausführen anderer Anwendungen existiert nicht. Solche Operationen müssen durch COM-Objekte ersetzt werden, die sich per CreateObject erzeugen lassen. Die am häufigsten verwendeten Objekte sind das FileSystemObject, das Shell-Objekt aus shell32 und andere speziell für VBScript entwickelte Komponenten, wie der Windows Scripting Host (wshom.ocx). All diesen Objekten begegnen Sie noch bei der Besprechung des Installations-Skripts.

Zusammenfassend kann man feststellen, dass sich VBA-Code zu großen Teilen direkt in ein VBScript übernehmen lässt. Entwickeln und debuggen Sie ihren Code unter VBA und ändern Sie ihn nach Übernahme in ein VBScript überall da, wo es notwendig ist.

VBScripte debuggen

Leider ist der Komfort, wie Sie ihn von VBA her kennen, beim Debuggen von VBScripten nicht vorhanden. Der Debugger zeigt lediglich eine Meldung an, wenn sich ein Fehler ereignet. Bild 1 ist ein Beispiel für einen Syntaxfehler, Bild 2 eines für einen Fehler bei der Ansprache eines Objekts. Der Debugger zeigt immerhin die Code-Zeile und die Spalte an, in der sich der Fehler zutrug. Was genau dort schiefging, bleibt aber weitgehend verborgen. Eine Inspektion von Variablen oder Haltepunkte bleibt außen vor. Meist streut man dann diverse Message-Boxen in den Code ein, die die Werte von Variablen anzeigen, um dem Fehler auf die Schliche zu kommen. Wer viel mit vbs-Dateien hantiert kann als Power User zu Visual Studio greifen, oder zu einem Tool, wie dem kostenpflichtigen VBSEdit (http://www.vbsedit.com). Eine freie Alternative stellt der freie Admin Script Editor (http://www.itninja.com/community/admin-script-editor ) dar. Diese können alle den Script-Code auf ähnliche Weise debuggen, wie VBA.

Fehlermeldung der Script-Engine bei einem Syntaxfehler

Bild 1: Fehlermeldung der Script-Engine bei einem Syntaxfehler

Fehlermeldung der Script-Engine bei einem Objektfehler

Bild 2: Fehlermeldung der Script-Engine bei einem Objektfehler

Hilfsbibliotheken für VBScript

Wo Funktionen für bestimmte Aufgaben im Sprachumfang von VBScript fehlen, greift man zu zusätzlichen Bibliotheken. Unter VBA tun Sie ja Ähnliches, indem Sie zusätzliche Verweise in das VBA-Projekt einklinken. VBScript allerdings sieht das so nicht vor, kann aber fast alle Objekte erzeugen, die in der Registry unter dem Zweig HKEY_CLASSES_ROOT zu finden sind. Also jene, die eine ProgId aufweisen und durch einen mit Punkt getrennten Begriff gekennzeichnet sind, wie zum Beispiel Access.Application.

Die wichtigsten Aufgaben lassen sich mit zwei Bibliotheken erledigen, der Shell32-Bibliothek und dem Windows Scripting Host. Um sich über deren Inhalt zu informieren, laden Sie unter VBA Verweise auf die Bibliotheken Microsoft Shell Controls And Automation (Shell32) und Windows Script Host Object Model (IWshRuntimeLibrary) und inspizieren sie im VBA-Objektkatalog. Die Syntax für das Anlegen der wichtigsten Objekte unter VBA und VBScript finden Sie hier im Vergleich:

VBA:

Set oShell = New Shell32.Shell

Set oShell2 = New WshShell

Set fso = New FileSystemObject

VBScript:

Set oShell = CreateObject _

   ("Shell.Application)

Set oShell2 = CreateObject _

   ("WScript.Shell")

Set fso = CreateObject _

("Scripting.FileSystemObject")

Über die so instanzierten Objekte lassen sich alle Aufgaben durchführen, die auch VBA ermöglicht. Das wären vor allem die Datei- und Verzeichnisoperationen über das FileSystemObject und das WshShell-Objekt. Aber auch die Registry lässt sich lesend und schreibend mit sehr einfachen Einzeilern ansprechen.

Öffnen Sie die Beispieldatenbank, in der die erwähnten Verweise bereits gesetzt sind. Im Modul mdlScripting finden Sie verschiedene Prozeduren, die die Ansprache der Objekte verdeutlichen.

Script als Administrator starten

Kommen wir nach den theoretischen Ausführungen zu einem praktischen Beispiel. Für viele Dateioperationen ist es notwendig, dass das ablaufende Skript Administratorrechte besitzt. Sei es, um Dateien in geschützte Verzeichnisse zu kopieren oder darin zu löschen, oder, um Rechte auf Ordner zu setzen. Doppelklicken Sie jedoch auf eine vbs-Datei, so wird das Skript unter normalem Benutzerkontext gestartet. Im Prinzip müssten Sie die wscript.exe Als Administrator ausführen und ihr als Argument den Pfad der vbs-Datei mitteilen. Das ist etwas umständlich. Mit einem Trick lässt sich das aber auch innerhalb der vbs-Datei selbst bewerkstelligen. Nehmen Sie den Code des Beispielskripts setpermission.vbs in Listing 2.

Set oShell = CreateObject("Shell.Application")

If (WScript.Arguments.Count = 1) Then ElevateUAC

Sub ElevateUAC

      sCommand = WScript.Arguments(0)

     'oShell.ShellExecute "c:\windows\syswow64\wscript.exe", _

' WScript.ScriptFullName & " | " & sCommand, , "runas", 1

'-> unter Winx64

oShell.ShellExecute "c:\windows\system32\wscript.exe", _

WScript.ScriptFullName & " | " & sCommand, , "runas", 1

WScript.Quit

End Sub

sFolder = WScript.Arguments(1)

Msgbox "Berechtigungen werden gesetzt auf " & sFolder

oShell.ShellExecute "Icacls.exe ", sFolder & " /grant Jeder:F /T", , "open", 1

Listing 2: Das Skript startet als Adminstrator und setzt dann Berechtigungen

Zunächst wird ein Shell-Objekt oShell erzeugt, welches für das Ausführen anderer Dateien über seine Methode ShellExecute benötigt wird. Das ist in etwa ein Ersatz für die Shell-Anweisung von VBA. WScript ist eine Objektvariable, die in einem VBScript immer automatisch zur Verfügung steht und die Scripting-Engine symbolisiert. Ihre Auflistungsmethode Arguments enthält die Kommandozeilenparameter, welche der Skript-Datei übergeben wurden. Das Skript erwartet nämlich als Parameter die Angabe eines Verzeichnispfades, auf den Vollberechtigungen für den Benutzer Jeder gesetzt werden sollen. Diesen Vorgang kann in der Regel das verwendete Kommandozeilen-Tool Icacls von Windows nur unter Admin-Rechten durchführen.

Das Skript ermitteln nun per Count, wie viele Parameter ihm übergeben wurden. Ist es genau einer, so wird die Unterroutine ElevateUAC angesprungen. Sie sehen hier, dass eine Sub- oder Function-Prozedur mitten im Code an beliebiger Stelle stehen kann. Dennoch setzt das Skript die Ausführung nach diesem Prozedureinschub unbeirrt weiter fort. Die Subroutine speichert jetzt den übergebenen Parameter, also den Ordnerpfad, in der String-Variablen sCommand. Und nun wird die wscript.exe über ShellExecute erneut aufgerufen, wobei ihr aber nun zwei Parameter übergeben werden: ein Pipe-Zeichen und der Inhalt der Variablen sCommand. Die Scripting-Engine sieht Leerzeichen als Trenner für Parameter an. Zu achten ist außerdem darauf, dass unter 64-bit-Systemen der Ort der wscript.exe ein anderer ist, als unter Windows x32.

Fullname ist eine Eigenschaft des WScript-Objekts, die den Pfad der eben ausgeführten vbs-Datei wiederspiegelt. Diese wird nun gestartet, wobei ShellExecute trickreich als Aktionsparameter der Ausdruck runas übergeben wird. Das entspricht dem Starten einer ausführbaren Datei als Administrator. Danach wird das laufende Skript selbst über die Quit-Methode beendet. Das Skript wurde nun also erneut gestartet, diesmal jedoch administrativ und mit zwei Parametern. Arguments.Count ist deshalb 2 und nicht 1, weshalb das Anspringen der Subroutine ElevateUAC übergangen wird und die Hauptroutine mit den Anweisungen nach ihr fortfährt. In sFolder wird der zweite Parameter eingelesen, der ja den gewünschten Ordner enthält - der erste Parameter ist das Pipe-Zeichen als Dummy. Schließlich wird Icacls per ShellExecute aufgerufen, wobei der Ordner angegeben und die Berechtigung für Jeder gesetzt wird.

Da das Skript universell verwendbar sein und einen Ordner-Parameter annehmen soll, muss es indirekt gestartet werden, in einer Batch-Datei etwa einfach über einen solchen Ausdruck:

setpermission.vbs c:\data

Verwenden des WMI

Das Windows Management Instrumentarium (WMI) ist das leistungsfähigste Tool, um jegliche Informationen über das System zu erhalten. Es kann in VBScript als Objekt angesprochen und über seine eingebaute Abfragesprache die gewünschte Info ermittelt werden. Listing 3 zeigt ein Beispiel.

Set oWMI = GetObject("winmgmts:{impersonationLevel=impersonate}!.\root\cimv2")

Set oResult = oWMI.ExecQuery ("Select Version from Win32_OperatingSystem")

For Each itm In oResult

lWinVers = itm.Version

lWinVersInt = Int(Left(lWinVers,1))

Next

Set oResult = oWMI.ExecQuery ("Select AddressWidth from Win32_Processor")

For Each itm In oResult

Is64 = (Int(itm.AddressWidth)=64)

Next

If Is64 = 0 Then

Msgbox "Windows-Version: " & lWinVers & " 32-bit"

Else

Msgbox "Windows-Version: " & lWinVers & " 64-bit"

End If

Listing 3: Verwenden des WMI zum Auslesen der Windows-Version

Das WMI-Objekt oWMI erhält man über einen etwas kryptischen Ausdruck in GetObject, der mit winmgmts: eingeleitet wird. Das Objekt befragt man über ExecQuery, wobei zunächst die Sparte Win32_OperatingSystem gewählt wird und darin nur das Feld Version. Die Ergebnismenge oResult muss in einer Schleife abgearbeitet werden, obwohl hier nur ein Ergebnissatz enthalten ist. Die Variable lWinVers nimmt den String für die Versionsnummer von Windows auf, etwa 7.0.526, lWinVersInt als Integer-Variable nur die Hauptnummer 7.

Leider sagt die Versionsnummer von Windows nichts darüber aus, ob es sich um ein 64- oder 32-bit-System handelt. Darum wird eine neue Abfrage abgesetzt, die diesmal die Rubrik Win32_Prozessor befragt. Steht deren Feld AddressWidth auf 64, so haben wir ein 64-bit-System vor uns. Das wird in der Bool-Variablen Is64 festgehalten. Am Schluss gibt eine Messagebox in Abhängigkeit dieser Variablen das Ergebnis wieder.

Wichtig ist diese Routine deshalb, weil die UAC erst ab Version 6 von Windows eingeführt wurde. Das Elevieren des Skript-Prozesses, wie im vorigen Beispiel geschehen, ist so nur dann nötig, wenn die Windows-Version größer als 5 ist. Da nun auch bekannt ist, ob ein 64-bit-OS läuft, kann der Ort bestimmter Verzeichnisse bestimmt werden. Das Systemverzeichnis kann sich unterscheiden und einmal den Pfad c:\windows\system32 haben, oder c:\windows\SysWOW64.

Standardpfade ermitteln

Es gibt aber auch noch alternative Wege, um den Systempfad und andere Standardverzeichnisse zu erfahren. Das Shell-Objekt ermittelt über die Methode NameSpace alle möglichen Spezialordner, indem ihr als Parameter bestimmte ID-Zahlenwerte übergeben werden:

Set oShell = CreateObject _

    ("Shell.Application")

Msgbox oShell.NameSpace(0)

Die 0 ist die ID für den Desktop. Die Messagebox gibt darum den Ausdruck Desktop aus. Das ist allerdings erst die Bezeichnung des Spezialordners. NameSpace gibt nämlich nicht etwa einen String zurück, sondern ein Folder-Objekt, dessen Standardeigenschaft Title ist. Möchten Sie aber den Verzeichnispfad bekommen, so muss eine andere Eigenschaft angesprochen werden:

Set oFolder = oShell.NameSpace (0)

sFolder = oFolder.Self.Path

Msgbox sFolder

Welche IDs mit welchen Windows-Spezialordnern korrelieren, erfahren Sie, indem Sie die Prozedur GetSpecialFolders der Beispieldatenbank aufrufen. Sie gibt im VBA-Direktfenster alle IDs, deren Bezeichnung und Pfad aus. Auszug:

36 Windows C:\Windows

37 System32 C:\Windows\System32

38 Program Files C:\Program Files

39 Bilder C:\Users\Sascha\Pictures

40 Sascha C:\Users\Sascha

Sie haben das Ende des frei verfügbaren Teil dieses Artikels erreicht!

Wenn Sie mehr lesen und auf viele weitere Artikel zugreifen möchten, melden Sie sich als Abonnent unter Login an. Falls nicht, bestellen Sie doch einfach ein Jahresabonnement!