Hey, Scripting Guy!Berechnen der Serverbetriebszeit

Die Scripting Guys von Microsoft

Codedownload verfügbar unter: HeyScriptingGuy2008_12.exe(152 KB)

Betriebszeit bedeutet Verfügbarkeit und Ausfallzeit das Gegenteil. Das ist ziemlich offensichtlich. Allerdings ist nicht alles so einfach, wenn es um die Serverbetriebszeit geht. Um die Betriebszeit zu kennen, müssen Sie die Ausfallzeit kennen. Nahezu jedem Netzwerkadministrator ist die Serverbetriebszeit ein Anliegen. (Das heißt, außer wenn die Serverausfallzeit Grund zur Sorge gibt.) Die meisten Administratoren haben vorgegebene Betriebszeiten und müssen Ihren Vorgesetzten Berichte über die Betriebszeiten vorlegen.

Wo ist das Problem? Es sieht so aus, als ob Sie die Win32_OperatingSystem-WMI-Klasse verwenden könnten, die zwei Eigenschaften hat, die einen solchen Vorgang recht einfach gestalten: LastBootUpTime und LocalDateTime. Alles, was Sie anscheinend tun müssen, ist das Subtrahieren der LastBootUptime von der LocalDateTime, und dann ist alles in Ordnung, und Sie haben sogar Zeit eingespart.

Also starten Sie Windows PowerShell, um die Win32_OperatingSystem-WMI-Klasse abzufragen, und wählen Sie die Eigenschaften aus, wie hier gezeigt:

PS C:\> $wmi = Get-WmiObject -Class Win32_OperatingSystem
PS C:\> $wmi.LocalDateTime - $wmi.LastBootUpTime

Aber wenn Sie diese Befehle ausführen, werden Sie nicht mit der freundlichen Betriebszeit Ihres Servers begrüßt, sondern von der eher traurigen Fehlermeldung in Abbildung 1.

fig01.gif

Abbildung 1 Fehler, der beim Versuch, WMI-UTC-Zeitwerte zu subtrahieren, zurückgegeben wird (zum Vergrößern auf das Bild klicken)

Die Fehlermeldung ist vielleicht etwas irreführend: „Fehlerhafte numerische Konstante“. Wie heißt das? Sie wissen, was eine Zahl ist, und Sie wissen, was eine Konstante ist, aber was hat das mit Zeit zu tun?

Bei seltsamen Fehlermeldungen ist es am besten, direkt die Daten anzusehen, die das Skript zu analysieren versucht. Außerdem ist es bei Windows PowerShell in der Regel sinnvoll zu untersuchen, welcher Datentyp verwendet wird.

Um die Daten zu untersuchen, die das Skript verwendet, können Sie sie einfach auf dem Bildschirm ausgeben. Hier ist das Ergebnis:

PS C:\> $wmi.LocalDateTime
20080905184214.290000-240

Die Zahl scheint etwas seltsam. Welche Art von Datum ist das? Um das herauszufinden, verwenden Sie die GetType-Methode. Das Gute an GetType ist, dass es fast immer verfügbar ist. Sie müssen es nur aufrufen. Hier ist die Ursache des Problems. Der LocalDateTime-Wert wird als Zeichenfolge, nicht als System.DateTime-Wert gemeldet:

PS C:\> $wmi.LocalDateTime.gettype()

IsPublic IsSerial Name BaseType
-------- -------- ---- --------
True     True     String
System.Object

Wenn Sie eine Zeit von einer anderen Zeit subtrahieren müssen, stellen Sie sicher, dass Sie es mit Zeitwerten und nicht mit Zeichenfolgen zu tun haben. Dies ist einfach, wenn Sie die Methode „ConvertToDateTime“ verwenden, die Windows PowerShell allen WMI-Klassen hinzufügt:

PS C:\> $wmi = Get-WmiObject -Class Win32_OperatingSystem
PS C:\> $wmi.ConvertToDateTime($wmi.LocalDateTime) –
$wmi.ConvertToDateTime($wmi.LastBootUpTime)

Wenn Sie einen Zeitwert von einem anderen subtrahieren, bleibt eine Instanz des System.TimeSpan-Objekts übrig. Dies bedeutet, dass Sie auswählen, wie Ihre Betriebszeitinformationen angezeigt werden sollen, ohne viel Arithmetik durchführen zu müssen. Sie müssen nur auswählen, welche Eigenschaft angezeigt werden soll (und hoffentlich zählen Sie Ihre Betriebszeit in TotalDays und nicht in TotalMilliseconds). Die Standardanzeige des System.TimeSpan-Objekts wird hier dargestellt:

Days              : 0
Hours             : 0
Minutes           : 40
Seconds           : 55
Milliseconds      : 914
Ticks             : 24559148010
TotalDays         : 0.0284249398263889
TotalHours        : 0.682198555833333
TotalMinutes      : 40.93191335
TotalSeconds      : 2455.914801
TotalMilliseconds : 2455914.801

Das Problem bei dieser Methode ist, dass sie Ihnen nur mitteilt, wie lange der Server seit dem letzten Neustart in Betrieb war. Sie berechnet die Ausfallzeit nicht. Um die Betriebszeit zu berechnen, müssen Sie also zuerst die Ausfallzeit kennen.

Wie ermitteln Sie also, wie lange der Server ausgefallen war? Dafür müssen Sie wissen, wann der Server startet und wann er herunterfährt. Sie können diese Informationen aus dem Systemereignisprotokoll abrufen. Einer der ersten Prozesse, der auf Ihrem Server oder der Arbeitsstation startet, ist das Ereignisprotokoll, und wenn ein Server heruntergefahren wird, gehört das Ereignisprotokoll zu den letzten Prozessen, die beendet werden. Jedes dieser Start-/Stoppereignisse generiert eine eventID: 6005, wenn das Ereignisprotokoll startet, und 6006, wenn das Ereignisprotokoll beendet wird. Abbildung 2 zeigt ein Beispiel für ein startendes Ereignisprotokoll.

fig02.gif

Abbildung 2 Der Ereignisprotokolldienst startet nach dem Start des Computers (zum Vergrößern auf das Bild klicken)

Durch das Abrufen der 6005- und 6006-Ereignisse aus dem Systemprotokoll, ihre Sortierung und das Subtrahieren der Starts von den Stopps können Sie den Zeitraum bestimmen, den der Server zwischen den Neustarts außer Betrieb war. Wenn Sie diesen Betrag dann von der Anzahl der Minuten während des jeweiligen Zeitraums subtrahieren, können Sie die Prozentzahl der Serverbetriebszeit berechnen. Dies ist der Ansatz, der im Skript „CalculateSystemUpTimeFromEventLog.ps1“ verwendet wird (siehe Abbildung 3).

Abbildung 3 CalculateSystemUpTimeFromEventLog 3

#---------------------------------------------------------------
# CalculateSystemUpTimeFromEventLog.ps1
# ed wilson, msft, 9/6/2008
# Creates a system.TimeSpan object to subtract date values
# Uses a .NET Framework class, system.collections.sortedlist to sort the events from eventlog.
#---------------------------------------------------------------
#Requires -version 2.0
Param($NumberOfDays = 30, [switch]$debug)

if($debug) { $DebugPreference = " continue" }

[timespan]$uptime = New-TimeSpan -start 0 -end 0
$currentTime = get-Date
$startUpID = 6005
$shutDownID = 6006
$minutesInPeriod = (24*60)*$NumberOfDays
$startingDate = (Get-Date -Hour 00 -Minute 00 -Second 00).adddays(-$numberOfDays)

Write-debug "'$uptime $uptime" ; start-sleep -s 1
write-debug "'$currentTime $currentTime" ; start-sleep -s 1
write-debug "'$startingDate $startingDate" ; start-sleep -s 1

$events = Get-EventLog -LogName system | 
Where-Object { $_.eventID -eq  $startUpID -OR $_.eventID -eq $shutDownID `
  -and $_.TimeGenerated -ge $startingDate } 

write-debug "'$events $($events)" ; start-sleep -s 1

$sortedList = New-object system.collections.sortedlist

ForEach($event in $events)
{
 $sortedList.Add( $event.timeGenerated, $event.eventID )
} #end foreach event
$uptime = $currentTime - $sortedList.keys[$($sortedList.Keys.Count-1)]
Write-Debug "Current uptime $uptime"

For($item = $sortedList.Count-2 ; $item -ge 0 ; $item -- )
{ 
 Write-Debug "$item `t `t $($sortedList.GetByIndex($item)) `t `
   $($sortedList.Keys[$item])" 
 if($sortedList.GetByIndex($item) -eq $startUpID)
 {
  $uptime += ($sortedList.Keys[$item+1] - $sortedList.Keys[$item])
  Write-Debug "adding uptime. `t uptime is now: $uptime"
 } #end if  
} #end for item 

"Total up time on $env:computername since $startingDate is " + "{0:n2}" -f `
  $uptime.TotalMinutes + " minutes."
$UpTimeMinutes = $Uptime.TotalMinutes
$percentDownTime = "{0:n2}" -f (100 - ($UpTimeMinutes/$minutesInPeriod)*100)
$percentUpTime = 100 - $percentDowntime

"$percentDowntime% downtime and $percentUpTime% uptime."

Das Skript beginnt mit der Param-Anweisung, um einige Befehlszeilenparameter zu definieren, deren Werte Sie ändern können, wenn Sie das Skript von der Befehlszeile ausführen. Mit dem ersten Parameter, $NumberOfDays, können Sie eine andere Zahl von Tagen angeben, die im Bericht über die Betriebszeit verwendet werden soll. (Beachten Sie, dass ich einen Standardwert von 30 Tagen im Skript bereitgestellt habe, damit Sie das Skript ausführen können, ohne einen Wert für den Parameter bereitstellen zu müssen. Selbstverständlich können Sie dies bei Bedarf ändern.)

Der zweite Parameter, [switch]$debug, ist ein Wählparameter, mit dem Sie vom Skript Informationen zum Debuggen erhalten, wenn Sie es beim Ausführen des Skripts in der Befehlszeile einschließen. Diese Informationen können helfen, wenn es um mehr Vertrauen in die vom Skript ausgegebenen Ergebnisse geht. Es könnte Zeiten geben, wenn die 6006-Beendigungsnachricht des Ereignisprotokolldiensts nicht vorhanden ist, vielleicht infolge eines schwerwiegenden Serverfehlers, der dazu führte, dass sie nicht in das Ereignisprotokoll geschrieben werden konnte, weshalb das Skript einen Betriebszeitwert von einem anderen Betriebszeitwert subtrahieren musste und die Ergebnisse verzerrt wurden.

Nachdem die $Debug-Variable von der Befehlszeile bereitgestellt wird, ist es auf dem Laufwerk „Variable:“ vorhanden. In diesem Fall ist der Wert der $debugPreference-Variablen so festgelegt, dass er fortgesetzt wird, das heißt, das Skript wird weiterhin ausgeführt, und jeder für Write-Debug bereitgestellte Wert wird sichtbar. Beachten Sie, dass der $debugPreference-Wert standardmäßig „silentlycontinue“ lautet. Wenn Sie also den Wert von $debugPreference nicht so festlegen, dass er fortgesetzt wird, wird das Skript ausgeführt, aber kein für Write-Debug bereitgestellter Wert ist sichtbar.

Wenn das Skript ausgeführt wird, listet die daraus resultierende Ausgabe jedes Vorkommen der 6005- und 6006-Ereignisprotokolleinträge auf (siehe Abbildung 4) und zeigt die Betriebszeitberechnung an. Mithilfe dieser Informationen können Sie die Genauigkeit der Ergebnisse bestätigen.

fig04.gif

Abbildung 4 Der Debugmodus zeigt eine Ablaufverfolgung der einzelnen Zeitwerte an, die der Betriebszeitberechnung hinzugefügt werden (zum Vergrößern auf das Bild klicken)

Der nächste Schritt besteht darin, eine Instanz des System.TimeSpan-Objekts zu erstellen. Sie könnten das New-Object-Cmdlet verwenden, um ein standardmäßiges Timespan-Objekt zu erstellen, das Sie für die Durchführung von Datumsdifferenzberechnungen verwenden würden:

PS C:\> [timespan]$ts = New-Object system.timespan

Aber Windows PowerShell enthält ein New-TimeSpan-Cmdlet zum Erstellen eines TimeSpan-Objekts. Deshalb ist es logisch, es zu verwenden. Durch dieses Cmdlet wird das Skript leserlicher, und das erstellte Objekt entspricht dem TimeSpan-Objekt, das mit New-Object erstellt wird.

Jetzt können Sie einige Variable initialisieren, angefangen mit $currentTime, die verwendet wird, um den aktuellen Zeit- und Datumswert festzuhalten. Sie rufen diese Informationen vom Get-Date-Cmdlet ab:

$currentTime = get-Date

Initialisieren Sie als Nächstes die zwei Variablen, die die Start- und die Stoppnummern für eventID enthalten. Dies ist nicht wirklich notwendig, aber der Code kann dadurch einfacher gelesen werden, und Fehler können leichter behoben werden, wenn Sie vermeiden, die beiden als Literalzeichenfolgenwerte einzubetten.

Der nächste Schritt besteht darin, eine Variable namens „$minutesInPeriod“ zu erstellen, damit sie das Ergebnis der Berechnung aufnimmt, das verwendet wird, um die Anzahl der Minuten während des jeweiligen Zeitraums zu bestimmen:

$minutesInPeriod = (24*60)*$NumberOfDays

Abschließend müssen Sie die $startingDate-Variable erstellen, die ein System.DateTime-Objekt enthalten wird, das die Startzeit des Berichtzeitraums repräsentiert. Das Datum wird Mitternacht des Anfangsdatums für den Zeitraum sein:

$startingDate = (Get-Date -Hour 00 -Minute 00 -Second 00).adddays(-$numberOfDays)

Nachdem die Variablen erstellt wurden, rufen Sie die Ereignisse aus dem Ereignisprotokoll ab und speichern die Ergebnisse der Abfrage in der $events-Variablen. Verwenden Sie das Get-EventLog-Cmdlet, um das Ereignisprotokoll abzufragen, indem Sie „system“ als Protokollnamen angeben. In Windows PowerShell 2.0 könnten Sie einen –source-Parameter verwenden, um die Informationsmenge zu verringern, die im Where-Object-Cmdlet verarbeitet werden muss. In Windows PowerShell 1.0 haben Sie diese Auswahl aber nicht und müssen deshalb alle ungefilterten Ereignisse durchgehen, die von der Abfrage zurückgegeben werden. Leiten Sie also die Ereignisse zum Where-Object-Cmdlet, um die geeigneten Ereignisprotokolleinträge herauszufiltern. Beim Untersuchen des Where-Object-Filters werden Sie sehen, warum die Scripting Guys Sie Variable erstellen lassen, die die Parameter enthalten sollen.

Der Befehl liest sich viel besser, als wenn Sie die Zeichenfolgenliterale verwendet hätten. Die get-eventIDs entsprechen entweder $startUpID oder $shutDownID. Sie sollten außerdem sicherstellen, dass die timeGenerated-Eigenschaft des Ereignisprotokolleintrags größer als oder gleich $startingDate ist, etwa so:

$events = Get-EventLog -LogName system |
Where-Object { $_.eventID -eq  $startUpID -OR $_.eventID -eq $shutDownID -and $_.TimeGenerated -ge $startingDate }

Bedenken Sie, dass dieser Befehl nur lokal ausgeführt wird. In Windows PowerShell 2.0 könnten Sie den –computerName-Parameter verwenden, damit der Befehl von einem Remotestandort aus funktioniert.

Der nächste Schritt ist das Erstellen eines sortierten Listenobjekts. Warum? Wenn Sie die Sammlung der Ereignisse durchlaufen, ist nicht garantiert, in welcher Reihenfolge die Ereignisprotokolleinträge gemeldet werden. Selbst wenn Sie die Objekte zum Sort-Object-Cmdlet leiten und die Ergebnisse wieder in einer Variablen speichern, können Sie, wenn Sie eine Iteration durch die Objekte durchführen und die Ergebnisse in einer Hashtabelle speichern, nicht sicher sein, dass die Liste die Ergebnisse des Sortierverfahrens beibehalten wird.

Um diesen frustrierenden und schwer zu behebenden Problemen auszuweichen, erstellen Sie eine Instanz des System.Collections.SortedList-Objekts, indem Sie den Standardkonstruktor für das Objekt verwenden. Der Standardkonstruktor fordert die sortierte Liste auf, die Daten chronologisch zu sortieren. Speichern Sie das leere sortierte Listenobjekt in der $sortedList-Variablen:

$sortedList = New-object system.collections.sortedlist

Nachdem Sie das sortierte Listenobjekt erstellt haben, müssen Sie es auffüllen. Verwenden Sie dazu die ForEach-Anweisung, und gehen Sie durch die Sammlung der Ereignisprotokolleinträge, die in der $entries-Variablen gespeichert sind. Beim Durchlaufen der Sammlung verfolgt die $event-Variable Ihre Position in der Sammlung. Sie können die Add-Methode verwenden, um dem System.Collections.SortedList-Objekt zwei Eigenschaften hinzuzufügen. Die sortierte Liste ermöglicht Ihnen, einen Schlüssel und eine value-Eigenschaft hinzuzufügen (so ähnlich wie bei einem Wörterbuchobjekt, außer, dass Sie auch in die Sammlung indizieren können, so wie ein Array es tun). Fügen Sie die timegenerated-Eigenschaft als Schlüssel und die eventID als Werteigenschaft hinzu:

ForEach($event in $events)
{
 $sortedList.Add( $event.timeGenerated,
 $event.eventID )
} #end foreach event

Als Nächstes berechnen Sie die aktuelle Betriebszeit des Servers. Verwenden Sie dazu den neuesten Ereignisprotokolleintrag in der sortierten Liste. Beachten Sie, dass dies immer eine 6005-Instanz sein wird, denn wenn der neueste Eintrag 6006 wäre, wäre der Server nach wie vor inaktiv. Da der Index nullbasiert ist, wird der neueste Eintrag die Zahl -1 sein.

Um den Erstellungszeitwert abzurufen, müssen Sie sich die Haupteigenschaft der sortierten Liste ansehen. Um den Indexwert abzurufen, verwenden Sie die Zahleigenschaft, und subtrahieren Sie davon eins. Subtrahieren Sie dann die Zeit, als das 6005-Ereignis erstellt wurde, vom Datumszeitwert, der in der $currenttime-Variablen gespeichert wurde, die Sie zuvor geladen haben. Sie können die Ergebnisse dieser Berechnung nur drucken, wenn das Skript in Debugmodus ausgeführt wird. Dieser Code wird hier gezeigt:

$uptime = $currentTime -
$sortedList.keys[$($sortedList.Keys.Count-1)]
Write-Debug "Current uptime $uptime"

Es ist jetzt Zeit, das sortierte Listenobjekt zu durchlaufen und die Betriebszeit für den Server zu berechnen. Weil Sie das System.Collections.Sorted-Listenobjekt verwenden, werden Sie die Tatsache nutzen, dass Sie in die Liste indizieren können. Verwenden Sie dazu die for-Anweisung, und zwar beginnend mit -2, weil die Zahl -1 zuvor schon für die Bestimmung der aktuellen Betriebszeit verwendet wurde.

Zum Feststellen der Betriebszeit zählen Sie rückwärts. Also ist die Bedingung, die an der zweiten Position der for-Anweisung angegeben ist, dass das Element größer oder gleich 0 ist. An der dritten Position der for-Anweisung verwenden Sie „--“, wodurch der Wert von $item um eins verringert wird. Sie verwenden das Write-Debug-Cmdlet, um den Wert der Indexzahl zu drucken, wenn das Skript mit dem –debug-Schalter ausgeführt wird. Außerdem führen Sie einen Tabulatorsprung durch, indem Sie das `t-Zeichen verwenden, und drucken den Zeiterstellungszeitwert aus. Dieser Abschnitt des Codes wird hier gezeigt:

For($item = $sortedList.Count-2 ; $item -ge 
  0 ; $item--)
{ 
 Write-Debug "$item `t `t $($sortedList.
 GetByIndex($item)) `t `
   $($sortedList.Keys[$item])" 

Wenn der eventID-Wert gleich 6005 ist (der Wert der Start-eventID), berechnen Sie den Wert der Betriebszeit durch Subtrahieren der Startzeit vom vorherigen Ausfallzeitwert. Speichern Sie diesen Wert in der $uptime-Variablen. Wenn Sie sich im Debugmodus befinden, können Sie das Write-Debug-Cmdlet verwenden, um diese Werte auf dem Bildschirm auszugeben:

 if($sortedList.GetByIndex($item) -eq $startUpID)
 {
  $uptime += ($sortedList.Keys[$item+1] 
  - $sortedList.Keys[$item])
  Write-Debug "adding uptime. `t uptime is now: $uptime"
 } #end if  
} #end for item

Zuletzt müssen Sie den Bericht generieren. Rufen Sie den Computernamen vom Systemumgebungsvariablen-Computer ab. Sie verwenden die aktuelle Zeit, die im $startingdate-Wert gespeichert ist, und zeigen die Gesamtanzahl der Betriebszeitminuten für den Zeitraum an. Sie verwenden den Formatbezeichner {0:n2}, um die Zahl mit zwei Ziffern zu drucken. Berechnen Sie als Nächstes den Prozentsatz der Ausfallzeit durch Dividieren der Anzahl der Betriebszeitminuten durch die Anzahl der Minuten, die im Zeitraum des Berichts abgedeckt werden. Verwenden Sie den gleichen Formatbezeichner, um den Wert mit zwei Dezimalstellen zu drucken. Nur zum Spaß können Sie auch die Prozentzahl der Betriebszeit berechnen und dann beide Werte ausgeben, etwa so:

"Total up time on $env:computername since $startingDate is " + "{0:n2}" -f `
  $uptime.TotalMinutes + " minutes."
$UpTimeMinutes = $Uptime.TotalMinutes
$percentDownTime = "{0:n2}" -f (100 - ($UpTimeMinutes/$minutesInPeriod)*100)
$percentUpTime = 100 - $percentDowntime
"$percentDowntime% downtime and $percentUpTime% uptime."

Sie sehen jetzt, dass Sie nicht über die Betriebszeit sprechen können, ohne die Ausfallzeit zu berücksichtigen. Wenn Ihnen dieser Artikel gefallen hat, lesen Sie auch die anderen Artikel unter Hey, Scripting Guy auf TechNet, oder besuchen Sie das Scriptcenter.

Versionsprobleme

Als Michael Murgolo, der redaktionelle Beiträge schreibt, das Skript „CalculateSystemUptimeFromEventLog.ps1“ auf seinem Laptop testete, stieß er auf einen sehr ärgerlichen Fehler. Ich habe das Skript meinem Freund Jit gegeben, und bei ihm hat sich der gleiche Fehler eingestellt. Was der Fehler war? Hier ist er:

PS C:\> C:\fso\CalculateSystemUpTimeFromEventLog.ps1
Cannot index into a null array.
At C:\fso\CalculateSystemUpTimeFromEventLog.ps1:36 char:43 + $uptime = 
$currentTime - $sortedList.keys[$ <<<< ($sortedList.Keys.Count-1)]
Total up time on LISBON since 09/02/2008 00:00:00 is 0.00 minutes.
100.00% downtime and 0% uptime.

Der Fehler „In einem NULL-Array kann kein Index erstellt werden“ zeigt an, dass das Array nicht richtig erstellt wurde. Also habe ich mich in den Code vertieft, der das Array erstellt:

ForEach($event in $events)
{
 $sortedList.Add( $event.timeGenerated,
 $event.eventID )
} #end foreach event

Letztendlich war der Code in Ordnung. Was verursachte dann den Fehler?

Als Nächstes sah ich mir das SortedList-Objekt an. Dafür habe ich ein einfaches Skript, das eine Instanz der System.Collections.SortedList-Klasse erstellt und ihr einige Informationen hinzufügt. An diesem Punkt habe ich die keys-Eigenschaft verwendet, um die Auflistung der Schlüssel zu drucken. Hier ist der Code:

$aryList = 1,2,3,4,5
$sl = New-Object Collections.SortedList
ForEach($i in $aryList)
{
 $sl.add($i,$i)
}

$sl.keys

Auf meinem Computer funktioniert dieser Code gut. Auf dem Computer von Jit ist er fehlgeschlagen. Schade, aber zumindest zeigte mir das die richtige Richtung. Wie sich herausstellte, lag das Problem an einem Fehler in System.Collections.SortedList in Windows PowerShell 1.0. Da ich zufällig den aktuellen Build des noch nicht veröffentlichten Windows PowerShell 2.0 ausführe, in dem dieser Fehler bereits behoben ist, bereitet der Code folglich keine Probleme.

Was bedeutet das nun für dieses Skript? Wie sich herausstellte, enthält die SortedList-Klasse eine Methode namens „GetKey“, und diese Methode funktioniert sowohl unter Windows PowerShell 1.0 als auch unter Windows Power­Shell 2.0. Also wird der Code für die 1.0-Version des Skripts so geändert, dass er GetKey verwendet, statt eine Iteration durch die Schlüsselsammlung durchzuführen. In der 2.0-Version des Skripts wird ein Tag hinzugefügt, das die Version 2.0 von Windows PowerShell erfordert. Wenn Sie versuchen, dieses Skript auf einem Windows PowerShell 1.0-Computer auszuführen, wird das Skript einfach beendet, und Sie erhalten keinen Fehler.

Michael hat auch auf etwas hingewiesen, was keinen Fehler darstellt, aber mit einer Entwurfsüberlegung zusammenhängt. Er hat bemerkt, dass das Skript die Betriebszeit nicht richtig erkennt, wenn Sie den Computer in den Ruhezustand oder in den Standbymodus versetzen. Das ist richtig, da wir diese Ereignisse nicht erkennen oder nach ihnen suchen.

In Wirklichkeit kümmert mich die Betriebszeit auf meinem Laptop oder Desktopcomputer jedoch nicht. Für mich ist die Betriebszeit auf einem Server interessant, und ich habe noch keinen Server im Ruhezustand oder im Standbymodus angetroffen. Es ist zwar nicht auszuschließen und könnte eine interessante Möglichkeit sein, im Rechenzentrum Strom zu sparen, aber es ist mir noch nicht untergekommen. Lassen Sie mich wissen, falls Sie Ihren Servern etwas Ruhe gönnen. Sie erreichen mich unter Scripter@Microsoft.com.

Der Scripting Perplexer von Dr. Scripto

Die monatliche Herausforderung, die nicht nur Ihr Talent zum Rätsellösen testet, sondern auch Ihre Skriptingfähigkeiten.

Dezember 2008: PowerShell-Befehle

Die Liste unten enthält 21 Windows PowerShell-Befehle. Das Quadrat enthält die gleichen Befehle, aber sie sind versteckt. Ihre Aufgabe besteht darin, die Befehle zu finden, die horizontal, vertikal oder diagonal (vorwärts oder rückwärts) versteckt sein können.

EXPORT-CSV FORMAT-LIST FORMAT-TABLE
GET-ACL GET-ALIAS GET-CHILDITEM
GET-LOCATION INVOKE-ITEM MEASURE-OBJECT
NEW-ITEMPROPERTY OUT-HOST OUT-NULL
REMOVE-PSSNAPIN SET-ACL SET-TRACESOURCE
SPLIT-PATH START-SLEEP STOP-SERVICE
SUSPEND-SERVICE WRITE-DEBUG WRITE-WARNING

\\msdnmagtst\MTPS\TechNet\issues\en\2008\12\HeyScriptingGuy - 1208\Figures\puzzle.gif

Antwort:

Der Scripting Perplexer von Dr. Scripto

Antwort: Dezember 2008: PowerShell-Befehle

fig12.gif

Ed Wilson ist leitender Berater bei Microsoft und ein bekannter Skriptexperte. Er ist ein Microsoft-zertifizierter Schulungsleiter, der für Microsoft Premier-Kunden weltweit einen beliebten Workshop zu Windows PowerShell anbietet. Ed Wilson hat acht Bücher, einschließlich mehrerer Bücher zum Thema Windows-Skripterstellung, geschrieben und hat an fast einem Dutzend anderer Bücher mitgearbeitet. Er besitzt mehr als 20 Branchenzertifizierungen.

Craig Liebendorfer ist ein Wortschmied und ein langjähriger Microsoft-Webredakteur. Er kann immer noch nicht glauben, dass es einen Job gibt, bei dem er dafür bezahlt wird, täglich mit Wörtern zu arbeiten. Respektloser Humor steht bei Craig ganz oben auf der Liste, und daher ist er hier gut aufgehoben. Er sieht seine wunderbare Tochter als seine größte Leistung im Leben an.