Vorgabe: Ablaufdatum für Code in Anmeldeskripts

24. Januar 2010

Oft erweist sich in der Praxis für den Administrator ein Standard-Skript als sinnvoll, das nur für einen vorgegebenen Zeitraum bestimmte Aufgaben ausführt. Damit legt er quasi ein Ablaufdatum für einen bestimmten Code-Bereich in dem Skript fest.Das Umsetzen dieser Aktionen erweist sich eigentlich nicht als besonders schwierig. Doch wer sich mit den Eigenheiten der jeweiligen Skriptsprache nicht gut auskennt, wird seine Probleme haben, wenn er hier eine konsistente Lösung erarbeiten möchte. Mit einigen Zeilen eines VBScript-Programms hat es aber der Administrator in der Hand, einen bestimmten Code nach einem frei zu definierenden Datum und Zeitpunkt nicht mehr ausführen zu lassen. Alex K. Angelopoulos zeigt, wie es funktioniert.

Die hier gezeigte Lösung eignet sich für die verschiedensten Arten von Aufgaben, die nach einem vorgegebenen Zeitpunkt nicht mehr ausgeführt werden sollen. Für dieses Beispiel aber soll das Thema Drucker-Mapping herhalten. Da die Daten für das Drucker-Mapping nur im Benutzerkontext verfügbar sind, ist das Abfragen dieser Daten am besten mit Hilfe eines Anmeldeskripts zu machen. Dabei kann der Administrator den nötigen Code dem Anmeldeskript hinzufügen und so an die gewünschten Daten kommen. Danach muss man nur mehr die Daten an einen verfügbaren Anmeldeserver mit Hilfe der Methode LogEvent aus WScript.Shell zusenden.

Das Ausführen eines derartigen Auditings aus einem Anmeldeskript bereitet aber einige Probleme. Zunächst wird man nur einen Bruchteil der Benutzer erreichen, wenn man den Code nur für einen Teil eines Tages oder auch für einen Tag laufen lässt. Je nachdem wie das Netzwerk verzweigt ist und wie häufig sich die einzelnen Benutzer anmelden, muss man mehrere Tage oder womöglich sogar mehrere Wochen versuchen, die Information über den Großteil der Benutzer zu erhalten. Und zum zweiten ergibt sich ein Problem, weil der Code ja bei jedem Anmeldevorgang läuft: Damit bekommt man dieselben Daten immer wieder zugesendet – wenn sich Benutzer recht häufig im Verbund anmelden. Und da macht es schon Sinn, all diese Daten nicht immer wieder in das Ereignisprotokoll zu schreiben.

In einem Idealen Universum bräuchte der Administrator dann nur den Code aus dem Anmeldeskript entfernen, wenn eine Woche oder so verstrichen ist. Doch die Praxis sieht anders aus – da wird leicht eine derartige Aufräumaktion vergessen. Das ist besonders dann der Fall, wenn man als nicht festangestellter Support-Spezialist für ein Unternehmen aktiv ist. Daher erweist sich der Ansatz, den Code automatisch nach der vorgegebenen zeit zu entfernen, als eine passende Idee. Zudem fungiert dieser Ansatz auch als eine gewisse Versicherung, dass nach der vorgegebenen Zeit die Auswirkungen dieser Überwachungsaktion wieder verschwinden.

Code-Bereich im Skript ausschließen

Damit ein Code-Bereich innerhalb eines Skripts nach einer gewissen Zeit abläuft, braucht man eigentlich nur eine Code-Zeile nehmen: Sie muss das aktuelle Datum (und die Uhrzeit) ermitteln und darf den folgenden Code nur dann ausführen, wenn das aktuelle Datum noch vor dem Ablaufdatum liegt. Doch hier schlagen die Eigenheiten von VBScript zu – genauer gesagt die Art und Weise, wie VBScript mit Datumsangaben hantiert.

VBScript erweist sich in der Praxis als sehr flexibel, und zwar nicht nur was es als Datumsangabe erkennt, sondern auch wie es diese Informationen in einen Datumswert überführt. Das hat aber auch zur Folge, dass der Einsatz eines Datumsformats, wie es zum Beispiel in den USA Verwendung findet, in anderen Ländern – etwa in Großbritannien oder gar in Ländern, die das ISO-Format verwenden – nicht richtig funktioniert. Daher ist hier Vorsicht geboten.

Es gibt aber verschiedene Optionen, um sicherzustellen, dass VBScript ein fest programmiertes Datum korrekt interpretiert. Doch eine Methodik hat sich als besonders zuverlässig und zugleich einfach bewährt:

Das Datum muss im Format

yyyy-MM-dd

angegeben werden. Dabei steht yyyy mit vier Ziffern für die Jahreszahl, MM steht für zwei Ziffern, die das Monat angeben und dd ist der zweistellige Tag des Monats.

Liegen die vier ersten Stelle und die Trennzeichen (also die Minuszeichen) vor, dann wird VBScript diese Information immer als ein Datum nach dem Format ISO 8601 interpretieren.

Dabei gilt es aber einen Sonderfall zu beachten, bei dem das System die Daten in dem Format

yyyy-dd-MM

darstellen könnte – doch das ist eigentlich weltweit nirgendwo vorzufinden.
Verfolgt man dagegen den Ansatz mit yyyy-MM-dd, muss man den ersten Februar 2010 angeben als:

2010-02-01

Um diese Information in ein Datum umzuwandeln und nicht in einen String, der nur wie ein Datum aussieht, kann man das #-Zeichen von VBScript verwenden und auf Anführungszeichen verzichten, wenn man im Skript ein Datum angeben möchte.

Mit einem eindeutig zu interpretierenden Datum vereinfacht sich dann die Aufgabe: Es bleibt dann nur mehr die aktuelle Systemzeit abzufragen und sie mit dem Auslaufdatum für die gewünschte Aktion zu vergleichen.

Das lässt sich mit Hilfe einer If-then-Schleife realisieren. Mit der folgenden logischen Abfrage wird der Code nur dann ausgeführt, wenn das aktuelle Datum noch nicht das Ablaufdatum erreicht hat:

If Date < #2010-02-01# Then
   ‚ Code goes here
End If

Eine Besonderheit sollte man noch erwähnen: Das Ablaufdatum, das angegeben wird, sollte der Tag nach  dem letzten Tag sein, an dem der Code noch laufen soll. In VBScript ist ein Datum genau betrachtet ein Datum und eine Uhrzeit. Ruft man aber die Methode Date() von VBScript auf, besteht das aktuelle Datum in VBScript auch noch aus der Uhrzeit und nicht nur aus der Tagesangabe.

Damit ist ein Wert von 2 a.m. (also in der amerikanischen Zeitangabe) am 1. Februar 2010 ein größerer Wert als nur der 1. Februar 2010. Man könnte den Code zwar so modifizieren, dass er auch mit der Zeitangabe des Tages klar kommt, doch damit handelt man sich nur weitere Unwägbarkeiten ein. Zudem bringt das Angeben eines Zeitpunkts keine Vorteile, denn die Interpretation der Uhrzeit erfolgt immer lokal – das wirkt sich dann auch bei den verschiedenen Zeitzonen aus:

Egal welches Ablaufdatum (und -Zeitpunkt) man vorsieht: Ein System mit der London-Zeit wird den Code zehn Stunden vor einem System in Honolulu nicht mehr ausführen. Wer hier eine noch komplexere Lösung sucht, dem sei geraten, sich die Klasse wbemDateTime aus der Windows Management Instrumentation (WMI) anzusehen.

Der Code im Bereich des Listings zeigt einen nutzbaren Ansatz, wie ein bestimmter Code-Bereich je nach Zeitpunkt ausgeführt werden kann. Dabei werden die Drucker für die einzelnen Benutzer überwacht und diese Informationen dann an den Anmeldeserver gesendet.

Dazu überträgt das Skript noch den Benutzernamen und die Bezeichnung des Computers, an dem der Anmeldevorgang stattgefunden hat. Die Daten werden dann im Anwendungsprotokoll auftauchen und als Datenquelle wird der WSH (Windows Scripting Host) angegeben sein.

Wer dieses Skript (siehe die nächste Seite im Artikel) direkt einsetzt, bei dem wird der Code bis zum 1. Februar 2010 ausgeführt werden. Danach „verwirft“ das Skript diesen Code. Wer dieses Ablaufdatum ändern will, muss nur das derzeit eingesetzte Datum

#2010-02-01#

entsprechend modifizieren.

Arbeitet der Administrator sauber, wird er auch das Anmeldeskript zu gegebener zeit von dem zusätzlichen Code säubern. Doch wer die Lösung mit der gezeigten Datumsabfrage einsetzt, der muss diese Aufräumaktion nicht sofort ausführen. Zudem wird es zu keinem Informations-Overflow im jeweiligen Ereignisprotokoll kommen, selbst wenn der Administrator erst nach einem Monat das Anmeldeskript wieder aufräumt.

Alex K. Angelopoulos/rhh

Beispiel-Listing mit einem Ablaufdatum für Anmeldeskripts, die Drucker überwachen (Vorsicht beim Einsatz von Skripts in produktiv-Umgebungen: Unbedingt erst diese Tools in einer Testumgebung ausprobieren).

If Date() < #2010-02-01# Then
 
   ‚using pn prefix for variables to limit name collisions
   ‚ Begin printer audit code
   Dim pnNet, pnPrinters, pnSd, pnSh, pnCount
   Dim pnUser, pnComputer, pnLogonServer, pnMsg
   Set pnNet = CreateObject("WScript.Network")
   set pnPrinters = pnNet.EnumPrinterConnections()
   set pnSD = CreateObject("Scripting.Dictionary")
   set pnSh = CreateObject("WScript.Shell")
   pnUser = pnNet.UserName
   pnComputer = pnNet.ComputerName
   pnLogonServer = pnSh.ExpandEnvironmentStrings("%LOGONSERVER%")
   pnSd( "user " & pnUser & " logging on from " & pnComputer _
       & " has these printers:") = ""
   for pnCount = 0 to pnPrinters.length -1 Step 2
       pnSD(pnPrinters(pnCount) _
           & " = " & pnPrinters(pnCount + 1)) = ""
   next
   pnMsg = Join(pnSd.Keys, vbCrLf)
   pnSh.LogEvent 4, pnMsg, pnLogonServer
   ‚ end printer audit code
 
End If

Lesen Sie auch