CDdurchsuchen.vbs - Skript erstellen
Einleitung
Speziell für Umsteiger, Einsteiger und Anfänger ist dieser Text
gedacht, in dem an einem Beispiel jeder Schritt erklärt wird, wie
ich ein neues Skript schreibe.
Vorausgehend sollte
dse-wsh-lernen.html
gelesen werden. Wie dort beschrieben, wird zunächst ein Skript kopiert
und umbenannt, das als Ausgangsbasis dienen soll.
Die Überschriften sind Links und verweisen auf eine Datei,
die die Veränderungen zeigt, die nach der jeweiligen Überschrift erklärt werden.
In dem Skript sind gelöschte Zeilen auskommentiert (mit einem Hochkomma) und
rot dargestellt;
Änderungen sind blau
und eingefügte Zeichen oder Zeilen
grün.
Markiert man alle Zeilen, kopiert diese und fügt sie in eine
.VBS-Datei ein (Copy & Paste), erhält man ein lauffähiges Skript.
Die Aufgabe
Dazu möchte ich auf eine E-Mail verweisen, die ich Anfang Juli 2003
erhielt (etwas gekürzt):
Hallo Dieseyer,
meine Vorgehensweise ist so zwar wohl nicht vorgesehen, andererseits
offensichtlich aber auch nicht ganz ausgeschlossen.
Nachstehend 2 Batches, die ich jetzt gerne umstellen möchte. Kannst
Du mir da bitte mal Hilfestellung geben?
. . . fällt es schon schwer, mal was ganz Neues anzufangen. Aber mit
nachvollziehbarer Hilfestellung wird es mir dann schon möglich sein,
andere Aufgaben umzustellen oder neu zu schreiben.
Ich habe mich auch durch das empfohlene Forum gehangelt, habe da aber
nichts entsprechendes gefunden.
Ansonsten, ... , nichts für ungut und entschuldige bitte.
Vor etwas mehr als einem Jahr (Anfang 2002) bin ich von .BAT zu .VBS umgestiegen.
Mein größtes Problem war das, was als objektorientiertes Programmieren (OOP)
bezeichnet wird. Andererseits ist es auch nicht selten, dass ich auf Befehlszeilenkommandos
(dir, attrib, ping . . .; unter WinNT/2k/XP gibt's keine DOS-Kommandos, das
sind dann Befehlszeilenkommandos) zurückgreife, weil diese eben viel
schneller sind (und ich weiß, wie die funktionieren). Die jungen (Skript-Kiddis)
müssen (oder wollen) ein 'DIR /S' (Vergl. dateinamenlangdir.vbs) unbedingt als
Skript nach bauen (und finden das dann einfach viel zu langsam).
Die erste der beiden .BAT-Dateien, die ich mit dieser E-Mail erhalten habe,
wird mit dem Laufwerksbuchstaben des CD-Laufwerks gestartet.
'Dir /s > cd.txt' schreibt dann eine
Dateiliste in die Datei CD.TXT. Die zweite .BAT-Datei muss mit zwei
Parametern gestartet werden: 'bat2 XYZ cd.txt', um in der
Textdatei nach 'XYZ' zu suchen.
Über den Sinn der beiden .BAT-Dateien und ob es lohnendere Aufgaben gibt,
verliere ich kein Wort.
Denn im folgenden soll das ganze nur 'zeitgemäßer' in einem Skript
nachgebildet werden.
Vorüberlegungen
Als Ausgangspunkt für das Skript habe ich mir überlegt, dass man beides in
ein Skript packen sollte. Ruft man das Skript mit einem Doppelklick auf,
sucht es das CD-Laufwerk und schreibt die Inhaltsliste in eine Datei, die
dann in dem Verzeichnis liegt, in dem sich das Skript befindet.
Zieht man eine Inhaltsliste auf das Skript, öffnet sich ein Fenster,
in dem man den Suchbegriff eingeben kann.
Da möglicherweise Inhaltslisten verschiedener CD's abgespeichert
werden sollen, muss man sich was für den Dateinamen einfallen lassen.
Fortlaufend nummerieren oder Datum und Uhrzeit halte ich für wenig geeignet,
da man (per Hand) eine Liste führen müsste, um die Inhaltslisten
den jeweiligen CD's zuordnen zu können. Es muss also ein Weg gesucht werden,
wie man den im Explorer angezeigten Namen (Label) verwenden kann.
In den ersten Zeilen des Skripts muss also der Laufwerksbuchstabe des
CD-Laufwerkes eingetragen sein und der übergebene Parameter
(wenn man eine Datei auf das Skript zieht) erfasst werden.
Andererseits, um das Skript so universell wie möglich zu gestalten,
sollte es selbst das (erste) CD-Laufwerk finden. Und da selbst gebrannte
CD's mitunter immer wieder den selben Namen (Label) erhalten, ist eine
fortlaufende Nummerierung (der gleichen Namen) erforderlich.
CDdurchsuchen0 - Skriptauswahl
Wenn ich nun die Liste meiner alten Skripte durchgehe, entscheide ich
mich für LaufWerkListe.vbs als Ausgangsbasis.
Dieses Skript kopiere ich in mein
Arbeitsverzeichnis und nenne es in CDdurchsuchen.vbs um.
Neben einer Versionsnummer ist im ersten Block der Skriptname auszutauschen
und anschließend eine kurze Skriptbeschreibung zu verfassen.
Welche Zeilen des alten Skripts werden auch weiterhin benötigt
und welche sind zu löschen?
Mit Option Explicit ist festgelegt, dass nur Variable im Skript benutzt
werden, die mit DIM-Anweisungen deklariert sind. Vertippt man sich bei
der Eingabe von Variablen, wird das mit einer Fehlermeldung angezeigt.
(Würde man versehentlich MsgBox Txet statt MsgBox Text
schreiben, würde ohne Option Explicit eine leere MsgBox erscheinen.)
Zur Vereinfachung des Zugriffs auf Objekte werden mit Set = einigen Variablen
Verweise auf Objekte zugewiesen: Objektverweise. Für ein Popup bedeutet das statt
WScript.CreateObject("WScript.Shell").Popup "Meldung"
nach dem Objektverweis auf die Variable 'WS'
Set WS = WScript.CreateObject("WScript.Shell")
nur noch:
WS.Popup "Meldung"
Da WS auch auf WScript verweisen könnte, verwende ich WSHShell; andere
Programmierer nehmen lieber oWSHShell als Variable.
Eine Protokolldatei ist unnötig => 3 Zeilen löschen.
Von den möglichen Laufwerkstypen interessiert nur das CD-Laufwerk => 5 Zeilen löschen.
Text1 und Text3 scheint auch nicht sonderlich wichtig => 8 Zeilen löschen.
Da zu jedem If .. ein End If und zu jedem
For .. ein Next gehört, bleiben die beiden Zeilen
stehen; die beiden dazwischen und die folgende => 3 Zeilen löschen.
Das Skript
speichern und ausführen - auf Grund der letzten Zeile dürfte nur
'Text2' als Meldung zu sehen sein.
Alle Variablen bzw. deren Namen sind frei erfunden . . . aber die Ähnlichkeit mit
realen Dingen ist nicht rein zufällig, sondern beabsichtigt. Um das Skript
lesbar zu gestalten, empfehlen sich sinnvolle Variablen. Hat man ein Skript
einige Zeit nicht mehr verwendet und will es dann doch noch einmal ändern,
erleichtert dies die Einarbeitung. Um auch anderen den Zugang zu
eigenen Skripten zu erleichtern, habe ich mir angewöhnt, die Variablen
aus der 'Windows Script'-Hilfe zu übernehmen.
Im Skript
verweist die Variable fso durch Set fso
auf das FileSystemObject. Über das FileSystemObject lassen
sich verschiedene Eigenschaften abrufen und Dateien und
Verzeichnisse manipulieren. Unter anderem kann über die Eigenschaft
.Drives auf die Liste der (verbundenen) Laufwerke zugegriffen
werden.
Auf welche Eigenschaften und Methoden über das FileSystemObject
zugegriffen werden kann, läßt sich über die Hilfe herausfinden.
Da ich immer wieder verwechsle, ob die Existenz einer Datei
oder eines Verzeichnis über FileExists oder ExistsFile getestet wird,
suche ich in der Hilfe garantiert das erste mal mit dem falschen Suchbegriff.
Um dies zu umgehen, habe ich den FileSystemObject-Beispielcode der Hilfe
(fso-beispielcode.vbs)
in meine Skriptsammlung aufgenommen und suche dort.
Auch eine Suche nach 'ready' ist dann erfolgreich, wenn mir
entfallen ist, dass es eigentlich 'IsReady' heißen müsste.
Um dem geneigten Leser auch für diesen Text die Möglichkeit einer
Volltextsuche zu geben, ist dieser komplette Text in nur einer Datei
(mit über 40KB für das Internet eigentlich zu groß) gespeichert.
Hier könnte eine Vereinfachung durchgeführt werden,
da die .Drives-Eigenschaft nur einmal erforderlich ist.
Set fso = CreateObject("Scripting.FileSystemObject")
Set DriveList = fso.Drives
läßt sich zusammenfassen:
Set DriveList = CreateObject("Scripting.FileSystemObject").Drives
Da das fso noch für das Einlesen und Durchsuchen der Inhaltsliste
nötig ist, bleibt alles es unverändert.
Also: DriveList verweist auf die Drives-Eigenschaft
des FileSystemObject. Um jedes Laufwerk zu testen, ob
es ein CD-Laufwerk ist, muss für jedes (For .. Each i) Laufwerk
der Laufwerksliste (DriveList) ein Test gemacht werden.
Diese Form der variablen For .. Next-Schleifen
mit unbekanntem Ende (je nach dem, wie viele Laufwerke auf einem PC zur Verfügung stehen),
werden in 'Windows Script' häufig verwendet.
Die Variable i enthält aber keinen Zähler (1, 2, 3, ...)
sondern einen (Objekt-) Verweis auf ein Laufwerk (Laufwerksbuchstabe; z.B. C:).
Über die Eigenschaft .DriveType des jeweiligen Laufwerkes läßt
sich ermitteln, ob es sich um ein CD-Laufwerk handelt und mit .IsReady
ob es bereit, also eine CD eingelegt ist.
CDdurchsuchen1 - CD-Laufwerke finden
Die folgenden zwei Zeilen werden zusammen gefasst (und
in der ersten der beiden Zeilen einiges gelöscht):
if 4 = i.DriveType Then Text1 = "CD-Lw. " & vbTab & i.DriveLetter & ": " & vbTab
if If i.IsReady Then
In der entstandenen If-Anweisung müssen beide Fragen
4=i.DriveType und i.IsReady mit 'richtig' (True) beantwortet werden,
damit die Folgezeile abgearbeitet wird; sonst geht es erst bei End If.
if 4 = i.DriveType AND i.IsReady Then
Eigentlich hätte die Zeile sogar so aussehen müssen:
if 4 = i.DriveType AND True = i.IsReady Then
Wenn man richtig
if True = i.IsReady Then
liest, bedeutet das: Wenn i.IsReady gleich True ist, ist der Vergleich
True (und die If-Bedingung erfüllt).
An dieser Stelle der Skriptentwicklung fällt mir ein, dass im Explorer
bei eingelegter CD der CD-Name angezeigt wird; ähnlich dem Label, das ich
einer Festplatte oder Diskette beim Formatieren geben kann. Also gebe ich in
der 'Windows Script'-Hilfe und gebe als Suchbegriff Label ein und
finde . . . nichts.
Da das nicht sein kann, wäre ein anderer Suchbegriff sinnvoll - aber
welcher?
Ich suche eine Information über das Laufwerk bzw. dessen Inhalt.
Eigentlich müsste es, ähnlich wie i.IsReady auch i.Label
(oder so) geben. Also suche ich in der Hilfe mal nach 'IsReady', vielleicht
steht in der Nähe dann das, was ich brauche. 'IsReady' wird natürlich
sofort in der Hilfe gefunden und unter 'siehe auch' steht 'VolumeName' als
weitere Eigenschaft (statt wie dem von mir erwarteten 'Label').
MsgBox i.VolumeName im
Skript
soll diese Information anzeigen.
CDdurchsuchen2 - Text 'zusammen bauen'
Mittlerweile gibt es immer mehr Computer, die mehr als ein CD-Laufwerk
eingebaut haben. Man könnte von jedem CD-Laufwerk eine Inhaltsliste
erstellen und anschließend über eine Dateiauswahl die 'richtige' auswählen.
Der Nachteil: Das Erstellen einer Inhaltsliste kann recht lange dauern und
sollte deshalb nur erfolgen, wenn die Liste auch wirklich benötigt wird.
Also muss erst eine Laufwerksauswahl erfolgen.
Alle CD-Laufwerke (die bereit sind bzw. in die eine CD eingelegt ist)
werden aufgelistet und der Benutzer gibt als Auswahl einen
Laufwerksbuchstaben ein. Dazu wird eine Variable CDlw eingefügt,
die die Informationen der CD-Laufwerke sammelt:
CDlw = CDlw & vbTab & i.DriveLetter & vbTab & i.VolumeName & vbCRLF
Die .DriveLetter-Eigenschaft findet man, wie weiter
ober die .VolumeName-Eigenschaft zu finden war.
Im einzelnen:
Die Variable CDlw wird aus ihrem bisherigen Inhalt und ( & )
weiteren Informationen zusammengesetzt. Da die Variable CDlw
neu im Skript ist, muss eine Dim -Zeile erweitert werden
(Komma nicht vergessen!). Um den gesammelten Text etwas zu formatieren,
werden die Informationen durch jeweils ein Tabulator-Zeichen
( vbTab ) auf Abstand zueinander gehalten.
Bei jedem Durchlauf der For .. Each- Schleife
wird die Variable CDlw um die Informationen eines weiteren
CD-Laufwerkes erweitert. Damit diese nicht alle in einer Zeile stehen,
wird bei jedem Durchlauf die Zeile durch einen Zeilenumbruch
( vbCRLF ) unterbrochen.
Zeilenumbruch: Das kommt noch aus der Zeit der Schreibmaschinen. Durch einen
Hebel (nach rechts bewegen) wurde der Wagen, in dem das Papier transportiert
wird, so bewegt, dass am Zeilenanfang (links auf dem Papier)
ein Zeichen angeschlagen werden kann: Wagenrücklauf = CarrigeReturn = CR.
Sobald der Hebel über den Anschlag hinaus bewegt wurde, drehte sich die Walze
mit dem Papier (einzeilig, anderthalbzeilig, zweizeilig; je nach Einstellung)
weiter: Zeilenvorschub = LineFeed = LF.
IBM hat früher sein Geld u.a. mit Schreibmaschinen verdient und diesen
Zeilenumbruch als CRLF in die Computer übernommen. (Nähere Informationen
zu dieser und weiteren Konstanten sind in der 'Windows Script'-Hilfe mit
dem Suchwort 'Zeichenfolgenkonstanten' zu finden.)
Natürlich soll der Inhalt der Variable CDlw auch angezeigt werden.
Aus diesem Grund wird aus
MsgBox "Text2", , WScript.ScriptName
die Zeile
MsgBox CDlw, , WScript.ScriptName
Wie aus der Hilfe zu entnehmen ist, können einer MsgBox
verschiedene Parameter übergeben werden. Vor dem ersten Komma sollte
ASCII-Text, der mit je einem Anführungszeichen beginnt und endet,
oder eine Variable (mit Text) stehen.
Als zweiter Parameter (nach dem ersten Komma) kann man die Box
mit einem Symbol etwas gestalten und entscheiden, welche Buttons
angezeigt werden.
Nach dem zweiten Komma lässt sich der Titel der Box (Text im oberen
blauen Balken) bestimmen. Ich verwende hier immer den Skriptnamen,
der von der Eigenschaft .ScriptName des WScript-Objekts
zurück gegeben wird.
Beim Ausführen des
Skripts
ist festzustellen, dass bei dem Laufwerksbuchstaben der Doppelpunkt
fehlt.
CDdurchsuchen3 - InputBox
Zunächst wird die Zeile
CDlw = CDlw & vbTab & i.DriveLetter & vbTab & i.VolumeName & vbCRLF
um einen Doppelpunkt für den Laufwerksbuchstaben erweitert:
CDlw = CDlw & ":" & vbTab & i.DriveLetter & vbTab & i.VolumeName & vbCRLF
Um das Skript möglichst universell zu gestalten,
sollte es auch auf Computern, die z.B. 14 (SCSI-) CD-Laufwerke
zur Verfügung stellen, funktionieren.
Für eine Auswahl müssen entsprechende Benutzereingaben vorgenommen
werden können. In 'Windows Script' bieten sich dafür MsgBox, PopUp und
InputBox an, wobei die ersten beiden nur klickbare Buttons haben.
Mit InputBox lassen sich ganze Zeichenketten an ein Skript
übergeben.
Der von der InputBox angezeigte Text soll noch etwas 'verfeinert'
werden. Vor der Anzeige der CD-Laufwerke wird die Variable CDlw
mit diesem Text vor der For .. Each-Schleife
'vorbelegt':
CDlw = "Die CD-Laufwerke enthalten folgende CD's:" & vbCRLF & vbCRLF
Will man diese Zeile hinter die For .. Each-Schleife
schreiben, würde der gesammelte Inhalt von CDlw verloren gehen - daher:
CDlw = "Die CD-Laufwerke enthalten folgende CD's:" & vbCRLF & vbCRLF & CDlw
Die Variable CDlw muss nun noch (durch eine weitere Zeile)
um eine Frage erweitert werden:
CDlw = CDlw & "Von welchem Laufwerk soll eine Inhaltsliste erzeugt werden?"
Entsprechend der 'Windows Script'-Hilfe sieht die InputBox-Zeile dann so aus:
CDlw = InputBox( CDlw, WScript.ScriptName)
Da der Inhalt der Variable CDlw mit ihrem Inhalt nicht mehr
benötigt wird, habe ich mich entschieden, diese Variable für das
Ergebnis der InputBox zu verwenden.
Wird das Skript jetzt ausgeführt, sieht man, dass es neben
dem [OK]-Button einen [Abbrechen]-Button gibt. Wird dieser betätigt,
ist die folgende MsgBox-Anzeige leer - was auch zu erwarten war.
Da das Skript nicht 'weiter zu arbeiten' braucht, erfolgt (nach einem Test)
der Skriptabbruch:
If CDlw = "" then
MsgBox ". . . das ist das Ende!", , Wscript.ScriptName
Wscript.Quit
End If
Oder alles in einer Zeile:
If CDlw = "" then MsgBox ". . . das ist das Ende!", , Wscript.ScriptName : Wscript.Quit
Durch einen Doppelpunkt lassen sich mehrere Befehle hintereinander in eine
Zeile schreiben; gleichzeitig geht aber häufig die Lesbarkeit des Skripts zurück.
Hier, in diesem speziellen Fall, wird durch die ersten Zeichen der Zeile
If CDlw = "" then MsgBox . . . klar,
dass es sich nur um einen Skriptabbruch bei falscher Eingabe handeln kann.
Das Skript
wird durch diese Zusammenfassung sogar besser lesbar (finde ich).
CDdurchsuchen4 - Eingabe auswerten
Damit das Skript einfach bleibt, soll es nicht möglich sein, mehrere Laufwerke
auf einmal einzugeben. Damit braucht von der Eingabe nur das erste Zeichen
ausgewertet zu werden:
CDlw = Left( CDlw, 1)
Um Fehleingaben auszuschließen, soll jetzt geprüft werden,
ob sich der eingegebene Laufwerksbuchstabe auf ein CD-Laufwerk
bezieht und ob dieses bereit ist. Vielleicht ist es aufgefallen:
die obige For .. Each- Schleife braucht einige
Zeit, bis sie komplett durchgelaufen ist. Aus diesem Grund soll
jetzt nur auf ein Laufwerk getestet werden. Dazu scheint sich der
Beispiel-VBScript-Code in der 'Windows Script'-Hilfe
zu der .IsReady-Eigenschaft zu eignen.
In diesem Beispiel gibt es ein 'l.IsReady', wobei der Objektverweis
'l' weiter oben mit 'Set l = fso.GetDrive(Laufwerksangabe)'
festgelegt wurde. Demnach schreibe ich in mein Skript statt
'l =' besser 'i ='
i = fso.GetDrive( CDlw )
So wird auch gleichzeitig der alte Objektverweis (weiter oben) beendet. Und:
if 4 = i.DriveType AND i.IsReady Then
sorgt für den Test.
Im Skript
ist nach der MsgBox noch ein End If einzufügen.
Wer das Skript
jetzt so mitgeschrieben hat, wird eine Fehlermeldung erhalten,
weil in der Zeile
i = fso.GetDrive( CDlw )
das 'Set' fehlt. So muss das Skript
aussehen:
Set i = fso.GetDrive( CDlw )
CDdurchsuchen5 - Inhaltsliste-Name
Besser ist es, wenn bei fehlgeschlagener Überprüfung (ob die Benutzereingabe auf
ein CD-Laufwerk verweist oder nicht) die Skriptabarbeitung beendet wird. Also
if not 4 = i.DriveType OR not i.IsReady Then
statt
if 4 = i.DriveType AND i.IsReady Then
Man beachte, dass beide Abfragen negiert (durch not) werden
müssen und die Verknüpfung der beiden Abfragen von AND in OR
zu ändern ist.
So! Nach dem klar ist, von welchem Laufwerk eine Inhaltsliste erstellt werden
soll, kann nun eine Liste erstellt werden. Dazu sind noch die Fragen zu klären
"Wo sollen die Listen gespeichert werden?" und "Wie sollen die Listen heißen?"
Am sinnvollsten scheint mir, die Listen in dem Verzeichnis abzulegen,
in dem sich das Skript befindet. Schließlich soll es später auch die Funktion
'Inhaltsliste mit der Maus auf das Skript ziehen und fallen lassen' geben; da
ist es besser, wenn das Skript im selben Verzeichnis wie die Dateien liegt.
Der Dateiname sollte aus dem .VolumeName abgeleitet werden. 'Abgeleitet'
deshalb, weil bei gleichem Namen (oder wiederholtem Einlesen) ein abweichender
Name gefunden werden muss: dazu bietet sich die fortlaufende Nummerierung an.
Mit i.VolumeName ist der Listenname ermittelt.
Den (Datei-) Type bzw. die (Datei-) Endung soll flexibler durch ein
Variable LstType am Skriptanfang definiert werden.
Liste = i.VolumeName
LstType = ".txt"
Da diese Variablen neu im Skript sind, muss wieder am Skriptanfang
'etwas' mit Dim geschehen. Die Variable LstType wird
auch gleich am Skriptanfang belegt.
Für die Nummerierung der Inhaltslisten sollten die Zahlen
von 1 bis 9 genügen.
Die folgenden Skriptzeilen werden etwa so aussehen:
if fso.FileExists( Liste & "1" & LstType ) then
' mehrere Zeilen
Else
' eine Zeile
End If
Dreht man das Ganze um (negieren), wird der Code wesentlich besser
lesbar, weil auf einen Blick beide Verzweigungen zu sehen sind:
if not fso.FileExists( Liste & "1" & LstType ) then
' eine Zeile
Else
' mehrere Zeilen
End If
Wenn es eine Liste 1 gibt:
if fso.FileExists( Liste & "1" & LstType ) then
soll überprüft werden, ob es noch weitere Listen gibt.
Andernfalls ( nach Else ) ergibt sich der Name der zu
erzeugenden Inhaltsliste:
Liste = Liste & "1" & LstType
Gibt es eine Liste 1, wird überprüft, ob es weitere gibt, die dann angezeigt
werden sollen - dafür wird die Variable Text verwendet:
For i = 1 to 9
if fso.FileExists( Liste & i & LstType ) then
Text = Text & Liste & i & LstType & vbCRLF
End If
Next
if fso.FileExists( " . . . " ) then
ermittelt über die Eigenschaft FileExists des Objektverweis fso.,
ob es die spezifizierte Datei gibt.
Zur Verbesserung des Skript könnte man noch zu jeder Datei den
Zeitpunkt der letzten Änderung anzeigen - dieser Zusatzaufgabe
möchte ich mich hier aber nicht stellen.
Nach dem Durchlaufen der For .. Next-Schleife sind die Namen
aller vorhandenen Inhaltslisten in Text gesammelt. Abschließend
werden noch ein paar Erklärungen in Text eingefügt.
Diesmal sollen/müssen weitere Parameter
bei der Anzeige der MsgBox übergeben werden: Die Buttons
[Ja], [Nein] und [Abbrechen]. In der 'Windows Script'-Hilfe ist zu
erfahren, dass folgende zwei Varianten möglich sind und dieselben
Anzeigen ergeben:
MsgBox Text, 3 + 32
und
MsgBox Text, vbYesNoCancel + vbQuestion
CDdurchsuchen6 - MsgBox-Buttons-Auswertung
Um diesen Bereich des Skripts testen zu können, sind einige
Dateien anzulegen. Heißt (.VolumeName) die eingelegte CD z.B.
'Neu', sollte man mindestens zwei Dateien (neu1.txt und neu2.txt) anlegen.
Es folgt die Auswertung des betätigten Buttons:
if Text = vbCancel then ...
if Text = vbNo then ...
if Text = vbYes then ...
Bei vbCancel erfolgt (wie oben) eine kurze Meldung und die
Skriptabarbeitung endet. Bei vbNo sind einige Dateien zu
löschen und wie bei vbYes der Name der neuen Inhaltsliste-Datei zu bestimmen.
Das Löschen ist schnell programmiert:
if Text = vbCancel then
For i = 1 to 9
if fso.FileExists( Liste & i & LstType ) then
' fso.DeleteFile( Liste & i & LstType )
End If
Next
oder mit Löschen erzwingen (true):
if Text = vbCancel then
For i = 1 to 9
' if fso.FileExists( Liste & i & LstType ) then fso.DeleteFile( Liste & i & LstType ), true
Next
Die Löschen-Zeile habe ich nach einem erfolgreichen Test auskommentiert,
damit die (beiden) Testdateien nicht immer wieder gelöscht werden.
Da es keine Inhaltslisten mit ähnlichen Namen wie die zu prüfende
CD mehr gibt, erhält die zu erstellende List die Nummer eins:
Liste = Liste & "1" & LstType
Wurde der [Yes]-Button betätigt, ist der erste mögliche Name (bzw. Nummer)
zu ermitteln. Das geht am einfachsten, wenn beim Testen auf vorhandene Dateien
rückwärts gezählt wird und sich das Skript die Zahl merkt, für die es (noch) keine
entsprechende Listendatei gibt. Die Schleife wird von neun bis eins herunter
gezählt. Nur wenn es einen Dateinamen nicht gibt, wird Text = i
(neu) gesetzt:
if Text = vbYes then
For i = 9 to 1 Step -1
if not fso.FileExists( Liste & i & LstType ) then Text = i
Next
Sollte nach dem Durchlaufen dieser Schleife Text immer noch
vbYes enthalten, ist Text kleiner als 'eins' -
das heißt, es gibt neun Dateien (und eine Fehlermeldung). Andernfalls
enthält Text die Zahl, aus der ein Dateiname zusammengesetzt
wird:
Liste = Liste & Text & LstType
CDdurchsuchen7 - Inhaltsliste erstellen
Der Inhaltslistenname steht nun fest und man kann sich Gedanken machen,
was in der Liste alles stehen soll. Als Kopfzeile genügt empfehle ich
Name und Erstellungzeitpunkt der Liste.
Um in eine Datei etwas schreiben zu können, muss diese angelegt werden.
(Mir fällt dazu gerade kein Befehl ein.) Da die Datei aber für Schreibzugriffe
geöffnet werden muss, vermute ich, dass mir dazu (schreiben) in der Hilfe
gleich noch Informationen zum Anlegen einer Datei mit gegeben werden.
'Schreiben' heißt im englischen 'write' und Dateioperationen haben
etwas mit dem FileSystemObject zu tun. Für mich ist es da am einfachsten,
wenn ich meine
fso-beispielcode.vbs
öffne und nach 'write' suche. Diesmal finde ich nicht gerade das,
was ich (schnell) verstehe und bemühe nun doch die 'Windows Script'-Hilfe.
Diesmal suche ich (erfolgreich) nach 'writeline'. Folgende Zeilen scheinen
sich gut zu eignen:
Set f = fso.OpenTextFile("c:\test.txt", ForWriting, True)
f.WriteLine "Hallo Welt!"
Weitere Informationen über 'OpenTextFile' und seine Parameter sind in der Hilfe
zu erfahren. Die von mir geänderten Zeilen sehen dann so aus:
Set FileOut = fso.OpenTextFile( Liste, 2, True)
FileOut.WriteLine "Hallo Welt!"
FileOut.Close
Set FileOut = nothing
Geöffnete Dateien sollten geschlossen werden (close) und nicht mehr
benötigte Objektverweise sind zu nichts (nothing) mehr zu gebrauchen.
Das Löschen der Objektverweise wurde bisher in diesem Skript unterlassen,
da noch nicht abzusehen war, wann sie das letzte mal benutzt werden.
Bei der Suche nach 'Datum' in der Hilfe wird man nach einiger Zeit
mehrere Möglichkeiten finden:
Now (aktuelles Datum und Zeit) und Time (aktuelle Systemzeit).
Ein kurzer Test
MsgBox now & vbCRLF & time
zeigt, dass Now vorzuziehen ist:
FileOut.WriteLine Liste & " - Verzeichnis vom " & Now
CDdurchsuchen8 - Inhaltsliste füllen
In Eingabeaufforderung und WSHShell.Run
wird erklärt, warum folgende Zeile sinnvoll ist:
WSHShell.Run "%comspec% /c dir " & CDlw & "\ /s /b >> " & Liste, , True
Da wir schon mal bei WSHShell.Run sind, fügen wir eine weitere Zeile ein:
WSHShell.Run Liste
Probiert man das Skript jetzt aus, wird zum Abschluß der Skriptabarbeitung
die Inhaltsliste (durch WSHShell.Run ) ausgeführt bzw. das Betriebssystem
startet entsprechend der Dateiendung eine passende Anwendung (meistens Notepad.exe).
Der Anwender braucht jetzt nur noch [Strg-F] drücken, um die Suchmaske
zu öffnen . . . oder das Skript macht dies auch noch:
WScript.Sleep 1000
WshShell.SendKeys ( "^F" )
CDdurchsuchen9 - Inhaltsliste als Argument
Wie in den Vorüberlegungen angedeutet, soll es möglich sein,
eine Datei mit der Maus auf das Skript zu ziehen und fallen
zu lassen. Dadurch erhält das Skript einen Dateinamen als
Parameter. Die Suchen in der Hilfe nach 'Argum*' (für 'Argument',
'Argumente', 'Argumenten') bringt bessere Ergebnisse als die nach
'Parameter'. Wenn man die Fundstellen so nach und nach durch gelesen
hat, wird man das 'WshArguments-Objekt' als das Mittel zur Lösung
finden:
Set objArgs = WScript.Arguments
For I = 0 to objArgs.Count - 1
WScript.Echo objArgs(I)
Next
Da nur ein Argument gebraucht wird, erfolgt das Verlassen der
For .. Next-Schleife mit Exit For bereits
im ersten Durchgang vor dem Next:
Set objArgs = WScript.Arguments
For i = 0 to objArgs.Count - 1
Liste = objArgs(i)
Exit For
Next
Um sicher zu gehen, dass das übergebene (erste) Argument auch wirklich
auf eine Datei verweist, erfolgt kurz eine Überprüfung:
if fso.FileExists( Liste ) then
Bei 'richtig' müsste die Skriptabarbeitung jetzt am Skriptende
weiter machen. Da es kein 'Goto' gibt, werden die erforderlichen
Zeilen nach oben kopiert (gibt es dann zweimal im Skript):
if fso.FileExists( Liste ) then
WSHShell.Run Liste
WScript.Sleep 1000
WshShell.SendKeys ( "^F" )
WScript.Quit
End If
Und nicht vergessen: 'objArgs' ist eine neue Variable und muss
in einer Dim-Zeile erwähnt werden.
CDdurchsuchenA - Prozedur
Richtig clevere Leute (wie wir) lagern sich
wiederholende Zeilen in Prozeduren aus - vergl.
Sub-Prozeduren und Function-Prozeduren - eine Einführung.
Dazu werden die Zeilen
WSHShell.Run Liste
WScript.Sleep 1000
WshShell.SendKeys ( "^F" )
an das Ende des Skripts verschoben und eingefasst von:
Sub ListeAnz ( Datei )
WSHShell.Run Datei
WScript.Sleep 1000
WshShell.SendKeys ( "^F" )
End Sub
Dort, wo die Zeilen vorher standen, steht dann nur noch:
ListeAnz ( Liste )
CDdurchsuchenB - Inhaltslistenname wählen
Nach einigen Tests fallen die ungünstigen Namen der Inhaltslisten auf.
Aus diesem Grund sollte noch eine Abfrage nach dem zu verwendenden Namen
eingefügt werden. Ein kurzer Blick in die 'Windows Script'-Hilfen zeigt,
dass man das Eingabefeld mit dem dritten Parameter vor belegen kann:
Liste = InputBox( Text , WScript.ScriptName, Liste )
CDdurchsuchenC - keine CD-Laufwerksauswahl
Arbeitet man einige Zeit mit dem Skript auf einem Computer mit nur
einem CD-Laufwerk, nervt irgendwann die Abfrage nach dem Laufwerk.
Da es keinen Befehl (der mir bekannt ist) gibt, der die Anzahl der
CD-Laufwerke zurück gibt, muss man sich etwas 'basteln'. Mir fallen dazu
auf die schnelle drei Varianten ein:
1. CDdurchsuchenC1 - keine CD-Laufwerksauswahl 1
In der For .. Next-Schleife zählt eine weitere
Variable die Anzahl der CD-Laufwerke. Nach einem anschließenden Vergleich
wird bei 1 nocheinmal eine For .. Next-Schleife
durchlaufen, die nur ein Laufwerk finden dürfte.
2. CDdurchsuchenC2 - keine CD-Laufwerksauswahl 2
In der For .. Next-Schleife zählt eine Variable CDnr
die Anzahl der CD-Laufwerke und eine Variable Text speichert (den zuletzt
gefundenen) Laufwerksbuchstaben. Damit enthält Text nach der Schleife
den CD-Laufwerksbuchstaben, wenn es nur ein CD-Laufwerk gibt.
3. CDdurchsuchenC3 - keine CD-Laufwerksauswahl 3
Diese Variante würde ich verwenden.
In der For .. Next-Schleife wird eine Variable
(z.B. Text) eingefügt, die ein Teil der Informationen
enthält, die CDlw übergeben werden. Wenn man auf
vbTab (in CDlw = CDlw & vbTab & i.DriveLetter...)
verzichtet, stimmen nach der For .. Next-Schleife das erste
Zeichen in CDlw mit dem Zeichen in der Variable (Text)
überein. Für diese Variante würde ich mich entscheiden, weil
dazu keine zusätzliche Variable im Skript eingefügt werden muss. Ich finde,
mit der Zunahme der Variablen verringert sich die Übersichtlichkeit.
CDdurchsuchenD - Kommentare
Was man eigentlich laufend und bereits während der Skriptprogrammierung
machen sollte, haben wir (oder nur ich?) bisher vernachlässigt: Zu den einzelnen
Schritten im Skript fehlen Kommentare, die die Funktionsweise des Skripts
(CDdurchsuchenC2 - keine CD-Laufwerksauswahl 2)
erklären.
Bei der Verwendung von Prozeduren (Sub oder Function) sollte
man diese speziell kennzeichnen. Beim Blättern und Suchen nach
einer Prozedur im Skript ist eine Linie (mit z.B. Sternchen; *) hilfreich,
um den Prozeduranfang zu finden; auch am Prozedurende schreibe ich
(fast immer) den Prozedurnamen noch einmal.
CDdurchsuchen - Nachtrag
Das Skript dürfte einigen Ansprüchen gerecht werden. Wer allerdings mehrere
Inhaltslisten auf das Skript ziehen will, kann nur die erste durchsuchen.
Um alle übergebenen Listen auswerten zu können, muss man das Skript
erheblich umbauen. Im Moment wird ja eine Datei mit Wordpad geöffnet,
die dann mit WordPad-eigenen Mitteln durchsucht werden kann. Eine
Skriptlösung müsste alle Dateien der Reihe nach öffnen, zeilenweise
lesen (und prüfen) und die Fundstellen mit Dateiname (und Zeilennummer?)
in eine Ergebniszeile speichern. Dazu könnte man sicher einige Zeilen aus
dateizeilenweiselesenbearbeitenschreiben.vbs verwenden. Da die
Umbauarbeiten recht umfangreich wären . . . möchte ich hier
davon Abstand nehmen.
Zum Schluss noch ein Danke an Peter Zienert für seine Anregungen, Korrekturen
und Hilfen.