Unterthema: Handwerkszeug
Unterthema: Listing 1
Unterthema: Listing 2
Unterthema: Listing 3
Unterthema: Listing 4
Unterthema: Listing 5
Unterthema: Listing 6
Anders als etwa MacOS besitzt Windows keinen Ordner `Ausschaltobjekte´, in dem der Anwender Programme und Skripte seiner Wahl platzieren kann. Es gibt zwar Shareware, die in den Ausschaltprozess einzugreifen vermag (`Shutdown-König´, siehe c't 12/99, S. 134), doch deren Möglichkeiten sind recht eingeschränkt im Vergleich zu jenen, die man sich mit dem Scripting Host von Windows erschließt [2, 3].
Wir haben insgesamt fünf Skriptprogramme fürs Herunterfahren implementiert, die zusammengenommen komfortabler sind als der von Microsoft vorgesehene Befehl. Wer vor dem Ausschalten die Festplatte automatisch defragmentieren, reparieren oder auch wichtige Daten sichern lassen möchte, sollte also in Zukunft sein Windows nicht mehr mit dem bekannten `Beenden´-Aufruf schließen. Genau wie dieser schalten die Skripte den Computer nach dem Herunterfahren sogar aus - sofern er über ein ATX-Netzteil verfügt.
Experimentieren Sie mit den einzelnen Varianten des Skriptes und fügen Sie bei Bedarf eigene Funktionen hinzu. Die entsprechend gekennzeichneten Listings arbeiten nur unter Windows 98. Alle haben eines gemeinsam: In den Skriptkonstanten sind die Herunterfahr-Befehle gespeichert, die mit der Run-Methode des WSHShell-Objekts aufgerufen werden. Die Systemvariable %WINDIR%, die das Windows-Verzeichnis enthält, wird dabei zuvor über ExpandEnvironmentStrings durch den tatsächlichen Ordnernamen ersetzt.
Bemerkenswert ist die undokumentierte Datei SOFTBOOT.EXE, mit der man das System neu starten kann. Sie existiert allerdings nur, wenn der Internet Explorer 4 installiert ist. Unter Windows 9x findet sie sich dann im Verzeichnis `Windows\System´, bei Windows NT unter `WinNT\System32´.
Execute prüft zunächst in der Registry, ob für den jeweiligen Auftrag bereits ein Schlüssel eingetragen ist. Falls ja, liest es aus dem Schlüssel das Datum, an dem das Tool zum letzten Mal ausgeführt wurde. Anschließend ermittelt es via DateDiff die Zeitdifferenz zum aktuellen Datum und kann so entscheiden, ob es Zeit ist, diesen Wartungsbefehl auszuführen. Da Windows von Haus aus mit zweistelligen Jahreszahlen arbeitet, wird die Routine beim Jahrtausendwechsel stolpern. Das können Sie verhindern, indem Sie die `Ländereinstellungen´ der Systemsteuerung auf vierstellige Jahreszahlen umstellen.
Ist das Intervall überschritten, ruft die Run-Methode den Wartungsbefehl auf. Der zusätzliche Parameter true lässt das Skript so lange anhalten, bis die Wartung abgeschlossen ist, sodass sich die Tools nicht gegenseitig ins Gehege kommen. Schließlich vermerkt das Skript das aktuelle Ausführungsdatum im Registry-Schlüssel des Tools.
Damit das Skript bequem zu handhaben ist, gibt es einige Meldungen aus. Steht beispielsweise ein Wartungsprogramm zur Ausführung an, so meldet das Skript dies und gibt die Möglichkeit, die Wartung abzubrechen und sofort herunterzufahren. Die Wartung wird dann beim nächsten Herunterfahren automatisch neu angeboten.
Darüber hinaus fragt das Skript nach jedem Wartungsprogramm nach, ob Sie den gesamten Prozess abbrechen wollen. Kommen Sie beispielsweise nach einigen Stunden an den Rechner und stellen fest, dass dieser noch mit Reparatur- oder Aufräumarbeiten beschäftigt ist, dann können Sie auf diese Weise das laufende Wartungsprogramm abbrechen und anschließend den Herunterfahr-Prozess abbrechen. Allerdings erscheint die Abfrage nur für vier Sekunden. So ist gewährleistet, dass das Skript im unbeaufsichtigten Modus nicht ewig wartet.
Das Skript speichert die Ausführungsdaten der einzelnen Wartungstools im Registry-Schlüssel HKEY_CURRENT_USER\Software\CTmagazin\. Das Skript CLEAR.VBS löscht diese Informationen auf Wunsch wieder - nützlich etwa, um das Skript ausgiebig zu testen. Es entfernt alle Eintragungen, sodass beim nächsten Herunterfahren wieder alle Wartungstools unabhängig vom eingestellten Wartungsintervall ausgeführt werden.
Durch die Eingabe von SCANDSKW.EXE /SAGESET:5 im Startmenü `Ausführen´ legt man alle Optionen des ScanDisk-Tools fest, die man später per /SAGERUN:5 aufrufen möchte. Wählen Sie als Prüfmethode `Standard´, und aktivieren Sie die Option `Fehler automatisch korrigieren´. Damit das Tool nach vollbrachter Arbeit keine störenden Meldungen anzeigt, die das Herunterfahren stoppen könnten, klickt man anschließend noch auf `Erweitert´ und wählt im Feld `Zusammenfassung anzeigen´ die Option `Nie´.
Rufen Sie als nächstes SCANDSKW.EXE /SAGESET:6 auf, schalten Sie auf `Intensiv´, aktivieren Sie je nach Wunsch weitere Optionen und schalten Sie wiederum `Fehler automatisch korrigieren´ ein. Der Festplatten-Optimierer Defrag lässt sich analog dazu über DEFRAG.EXE /SAGESET:5 konfigurieren. Welche Ziffern Sie hinter /SAGESET: respektive /SAGERUN: verwenden, spielt keine Rolle - nur die 1 sollten Sie vermeiden, denn die verwendet der Windows-98-Wartungsassistent.
Execute """C:\TEST\DOCLEAN.VBS""", 0, "befehlx"Wie oben beschrieben, erfordert Execute drei Parameter, nämlich den Befehlsaufruf, das Wartungsintervall (0 steht für `jedes Mal´) sowie einen unverwechselbaren Namen. Anstelle von `befehlx´ können Sie auch einen beliebigen anderen wählen. Da VBScript zwei Anführungszeichen in eins verwandelt, muss man hier drei angeben.
BackItUp "C:\BRIEFE", "D:\BACKUP", ";doc;", 1Nach getaner Arbeit gibt das Skript eine Erfolgsmeldung aus - aber nur für zehn Sekunden, wiederum, um andere Tätigkeiten nicht zu behindern.
Da das BACKITUP-Skript das gesamte Dateisystem durchsuchen kann, eignet es sich auch, um etwa überflüssige Dateien per Dateityp, Name oder letztem Dateizugriff zu sammeln und zu löschen. Das Umschreiben ist in wenigen Minuten erledigt, doch Vorsicht beim rekursiven Löschen - ein falscher Parameter kann zu verheerenden Ergebnissen führen!
In der Variablen typen legt man durch Semikola getrennt fest, mit welchen Dateitypen man tatsächlich regelmäßig arbeitet. Im abgedruckten Skript sind das beispielsweise die Textdokumente .doc und .txt sowie das Bildformat .bmp. Alle Verweise, die nicht auf einen dieser Dateitypen verweisen, werden aus dem Dokumente-Menü entfernt: Nach dem nächsten Systemstart liefert es endlich einen wirklich wertvollen Überblick über alle wichtigen Dateien, mit denen kürzlich gearbeitet wurde.
Wie schon in den letzten beiden Artikeln zum Scripting Host können wir hier aus Platzgründen nur funktionierende Beispiele ohne größeren Komfort bieten. Experimentieren Sie selbst, sichern Sie Ihre individuellen Dokumenttypen, speichern Sie Ihre Arbeitszeiten in einer Tabelle oder lassen Sie sich eine ganz neue Idee einfallen: Die Skripte bilden das ideale Grundgerüst dafür. (se)
[2] Dr. Tobias Weltner: Windows im Griff, Mit dem Scripting Host wird das System erst rund, c't 10/99, S. 96
[3] Dr. Tobias Weltner: Scandruckfaxkopierer, Einlesen, Ausgeben, Bearbeiten mit Windows-Bordmitteln, c't 14/99, S. 192
[4] http://wwwthep.physik.uni-mainz.de/~frink/newgina_pre09.zip
REM Doclean.VBS (c) c't/Tobias Weltner
typen = ";doc;txt;bmp;"
set fs = CreateObject("Scripting.FileSystemObject")
Set WshShell = Wscript.CreateObject("Wscript.Shell")
set ordner = fs.GetFolder(WshShell.SpecialFolders("Recent"))
for each datei in ordner.files
if lcase(fs.GetExtensionName(datei.path)) = "lnk" then
set scut = WshShell.CreateShortcut(datei.path)
ziel = scut.TargetPath
extension = ";" & lcase(fs.GetExtensionName(ziel)) & ";"
if Instr(lcase(typen), extension)=0 then
datei.delete vbtrue
end if
end if
next
Kasten 3
REM Autoclose.VBS (c) c't/Tobias Weltner
do
loop until CloseAllWindows=0
function CloseAllWindows
set Shell = CreateObject("Shell.Application")
set shellwindows = Shell.Windows
for each window in shellwindows
set parent = window.Application
parent.Quit
next
set shellwindows = Shell.Windows
CloseAllWindows = shellwindows.Count
end function
Kasten 4
REM Herunterfahren.VBS (c) c't/Tobias Weltner
' Dieses Skript fährt den Rechner auf verschiedene Arten herunter
const sd_ausschalten9598 = "rundll32.exe user,ExitWindows"
const sd_kaltstart9598IE4 = "%windir%\system\softboot.exe /s:,60"
const sd_kaltstartNTIE4 = "%windir%\system32\softboot.exe /s:,60"
const sd_warmstart9598 = "rundll.exe user,ExitWindowsExec"
const sd_anmelden98 = "rundll32.exe shell32.dll,SHExitWindowsEx 0"
const sd_ausschalten98 = "rundll32.exe shell32.dll,SHExitWindowsEx 1"
const sd_kaltstart98 = "rundll32.exe shell32.dll,SHExitWindowsEx 2"
frage = "Wollen Sie Windows wirklich beenden?"
header = "Beenden"
antwort = MsgBox(frage, vbQuestion + vbYesNo, header)
if antwort = vbYes then
ShutDown sd_ausschalten9598
end if
sub ShutDown(variante)
set WSHShell = CreateObject("WScript.Shell")
variante = WSHShell.ExpandEnvironmentStrings(variante)
WSHShell.Run variante
end sub
Kasten 5
REM Herunterfahren2.VBS (c) c't/Tobias Weltner
' Dieses Skript fährt den Rechner auf verschiedene Arten herunter
const sd_ausschalten9598 = "rundll32.exe user,ExitWindows"
const sd_kaltstart9598IE4 = "%windir%\system\softboot.exe /s:,60"
const sd_kaltstartNTIE4 = "%windir%\system32\softboot.exe /s:,60"
const sd_warmstart9598 = "rundll.exe user,ExitWindowsExec"
const sd_anmelden98 = "rundll32.exe shell32.dll,SHExitWindowsEx 0"
const sd_ausschalten98 = "rundll32.exe shell32.dll,SHExitWindowsEx 1"
const sd_kaltstart98 = "rundll32.exe shell32.dll,SHExitWindowsEx 2"
public asked
public wartung
public interrupt
public abbrechen
frage = "Wollen Sie Windows wirklich beenden?"
header = "Beenden"
antwort = MsgBox(frage, vbQuestion + vbYesNo, header)
if antwort = vbYes then
ShutDown sd_ausschalten9598
end if
sub ShutDown(variante)
set WSHShell = CreateObject("WScript.Shell")
variante = WSHShell.ExpandEnvironmentStrings(variante)
Wartungsprogramme
if not abbrechen=vbYes then WSHShell.Run variante
end sub
sub Wartungsprogramme
Execute "SCANDSKW.EXE /SAGERUN:5", 5, "befehl1"
Execute "SCANDSKW.EXE /SAGERUN:6", 30, "befehl2"
Execute "DEFRAG.EXE /SAGERUN:5", 14, "befehl3"
end sub
sub Execute(befehl, wann, key)
set WSHShell = CreateObject("WScript.Shell")
regkey = "HKCU\Software\CTmagazin\" + key + "\datum\"
if KeyExists(regkey) then
lastExec = WSHShell.RegRead(regkey)
timediff = DateDiff("d", lastExec, Date())
if timediff>=wann then
doit = true
else
doit = false
end if
else
doit = true
end if
if doit then
if not asked then
wartung = MsgBox("Es stehen einige Wartungen an. Durchführen?",
vbQuestion + vbYesNo)
asked = true
end if
if wartung = vbYes then
WSHShell.Run befehl, 1, true
WSHShell.RegWrite regkey, date()
abbrechen = WSHShell.Popup("Herunterfahren abbrechen?", 4,
"Unterbrechung", vbQuestion + vbYesNo)
if abbrechen = vbYes then wartung = vbNo
end if
end if
set WSHShell = Nothing
end sub
function KeyExists(key)
on error resume next
set WSHShell = CreateObject("WScript.Shell")
test = WSHShell.RegRead(key)
if err.number<>0 then
err.clear
KeyExists = false
else
KeyExists = true
end if
set WSHShell = Nothing
end function
Kasten 6
REM Clear.VBS (c) c't/Tobias Weltner
set WSHShell = CreateObject("WScript.Shell")
on error resume next
WSHShell.RegDelete "HKCU\Software\CTmagazin\"
if err.Number=0 then
MsgBox "Registry-Einstellungen gelöscht", vbinformation
else
MsgBox "Keine Registry-Einstellungen vorhanden", vbInformation
end if
Kasten 7
REM BackItUp.VBS (c) c't/Tobias Weltner
set fs = CreateObject("Scripting.FileSystemObject")
set WSHShell = CreateObject("WScript.Shell")
erneuert = 0
neukopiert = 0
uptodate = 0
unzutreffend = 0
neuordner = 0
problem = 0
' ---------------------------------------------------------------------
' Syntax: BackItUp quelle, ziel, extensionen, modus
' quelle: Ordner mit den Originalen
' ziel: Ordner mit den Sicherheitskopien
' extensionen: Liste der Dateiextensionen, die gesichert werden sollen
' Extensionen durch Semikola trennen: ";vbs;doc;txt;"
' modus: 1 auch Unterordner sichern
' 2 alle Dateien sichern
' 4 immer neu kopieren
BackItUp "C:\WINDOWS\DESKTOP\CT", "C:\BACKUP1", "", 1+2
' ---------------------------------------------------------------------
' Statusreport für 10 Sekunden anzeigen:
r = neukopiert & " Dateien neu kopiert" + vbCr
r = r & erneuert & " Dateien aktualisiert" + vbCr
r = r & uptodate & " Dateien befanden sich auf aktuellem Stand" + vbCr
r = r & unzutreffend & " Dateien entsprachen nicht den Auswahlkriterien." + vbCr
r = r & problem & " Dateien konnten aufgrund von Fehlern nicht kopiert werden."
+ vbCr
r = r & neuordner & " neue Ordner angelegt."
WSHShell.Popup r, 10, "Report", vbInformation
sub BackItUp(original, ziel, extensionen, mode)
' "\" am Ende des Pfadnamens entfernen, falls vorhanden:
if right(original,1)="\" then original=left(original, len(original)-1)
if right(ziel,1)="\" then ziel=left(ziel, len(ziel)-1)
' Fehler abfangen:
if not fs.FolderExists(original) then
fehler = "Quell-Ordner """ & original & """ existiert nicht!"
end if
if not fs.FolderExists(ziel) then
fehler = "Ziel-Ordner """ & ziel & """ existiert nicht!"
end if
if not fehler="" then
MsgBox fehler, vbCritical
WScript.Quit
end if
' Quellordner sichern:
set ordner = fs.GetFolder(original)
BackupOrdner ordner, original, ziel, extensionen, mode
end sub
sub BackupOrdner(folderobj, original, sicherung, extensionen, mode)
' Dateien in diesem Ordner sichern
BackupFiles folderobj, original, sicherung, extensionen, mode
' Unterordner in diesem Ordner sichern
' (rekursiver Aufruf)
if (mode and 1) then
for each unterordner in folderobj.subfolders
BackupOrdner unterordner, original, sicherung, extensionen, mode
next
end if
end sub
sub BackupFiles(ordner, original, sicherung, extensionen, mode)
' alle Dateien in diesem Ordner auflisten
for each datei in ordner.files
' Dateiextension der aktuellen Datei ermitteln:
extension = ";" & lcase(fs.GetExtensionName(datei.Path)) & ";"
' bei mode=2 oder passender Extension sichern:
if (mode and 2) or (Instr(lcase(extensionen), extension) >0) then
' Original wann zuletzt geändert?
alteroriginal = datei.DateLastModified
' liegt die Originaldatei in einem Unterordner?
' Pfad der Datei bestimmen:
dateipfad = datei.path
' Dateinamen vom Pfad entfernen:
dateipfad = left(dateipfad, InstrRev(dateipfad, "\"))
' nur das Unterverzeichnis des Originale-Ordners übriglassen:
dateipfad = mid(dateipfad, len(original)+1)
' Sicherungsordner + evtl. Unterordner:
sicherungsordner = sicherung + dateipfad
' Zieldateiname:
zieldatei = sicherungsordner & datei.Name
' Existiert bereits die Sicherungskopie?
zieldateiexist = fs.FileExists(zieldatei)
if zieldateiexist then
' von wann ist die Sicherungskopie?
alterziel = fs.GetFile(zieldatei).DateLastModified
else
alterziel = CDate("1.1.80")
flag = true
end if
' Sicherungskopie ist veraltet oder mode=4:
if (alteroriginal>alterziel) or (mode and 4) then
ok = CopyIt(datei,sicherungsordner)
if flag and ok then
neukopiert = neukopiert + 1
elseif ok then
erneuert = erneuert + 1
else
problem = problem + 1
end if
else
uptodate = uptodate + 1
end if
else
unzutreffend = unzutreffend + 1
end if
next
end sub
function CopyIt(filehandle, zielordner)
' kopiert die Datei
on error resume next
if not fs.FolderExists(zielordner) then
fs.CreateFolder zielordner
neuordner = neuordner + 1
end if
ziel = zielordner & filehandle.name
filehandle.copy ziel, true
if err.number=0 then
CopyIt = true
else
CopyIt = false
err.clear
end if
end function