Hey, Scripting Guy!Zeitmessung mit der Stoppuhr

Die Scripting Guys von Microsoft

Was mir an meiner Arbeit in Mexiko immer gefallen hat, war die Einstellung zur Zeit. Alle Arbeitsaufgaben wurden erfüllt, aber stets ohne jede Hektik. Wenn mein Freund Miguel auf unserem gemeinsamen Weg ins Büro vorschlug, ein neues Café auszuprobieren, dann nahm ich den Vorschlag an. Was machte es schon aus, wenn wir einige Minuten später im Büro ankamen? Wir saßen bei einer guten Tasse Kaffee in bester Gesellschaft und genossen einen wunderschönen Sonnenaufgang.

So sehr ich diese Lebensart auch schätze – die Zeiten haben sich geändert. Heute ist mein Leben ziemlich reglementiert. Ich stehe um 6:00 Uhr auf, treibe eine Stunde lang Sport, dusche mich, frühstücke und bin spätestens um 7:30 Uhr im Büro. Jeden Tag ertappe ich mich dabei, wie ich Dutzende Male auf die Uhr schaue, um sicherzugehen, dass ich meinen Zeitplan einhalte. In Mexiko trug ich nicht einmal eine Uhr. Zeit war nie ein Thema.

Für Netzwerkadministratoren und Berater hingegen ist Zeit immer ein Thema: Wir müssen Sicherungen planen, die Dienstverfügbarkeit berechnen sowie die Systemzeit, die Ausfallzeit und die Antwortzeit bestimmen. Zur Überwachung der Zeit mag es ausreichen, auf ein Symbol zu klicken, auf die Uhr zu schauen und die Sekunden oder Minuten bis zum Öffnen der Anwendung zu zählen. Was aber, wenn Sie während der Zeitmessung unterbrochen werden? Ich weiß nicht, wie es Ihnen geht – ich zumindest neige zu Vergesslichkeit, wenn ich bei einer Tätigkeit abgelenkt werde.

Ich könnte zwar die drehbare Lünette auf meiner Taucheruhr verwenden, um die Startzeit zu markieren. Dann bleibt jedoch immer noch das Subtrahieren all der Zahlen, und wenn ich unterbrochen werde, sind die Ergebnisse vielleicht nicht zuverlässig. Statt einer normalen Uhr oder einer Taucheruhr benötige ich eine Stoppuhr. Diese Stoppuhr muss mir mitteilen, wie lange der Vorgang gedauert hat, und sich außerdem erinnern, wie viel Zeit er beim letzten Mal beanspruchte. Auf diese Weise könnte ich mir eine Vorstellung davon machen, was die aktuellen Ergebnisse in Bezug auf die Leistung tatsächlich bedeuten.

Glücklicherweise verfügt Microsoft .NET Framework über eine StopWatch-Klasse, die ich in einem Skript namens „Set-StopWatchRecordValues.ps1“ verwende. Dieses Skript misst den Zeitaufwand für eine Aktivität und schreibt die Ergebnisse in die Registrierung. Wenn das Skript später wieder ausgeführt wird, ruft es den früheren Wert aus der Registrierung ab und teilt dem Benutzer sowohl die aktuelle als auch die frühere Zeit mit.

Die StopWatch-Klasse ist Teil des System.Diagnostics-Namespace. Sie verfügt über eine statische Methode namens „StartNew“, die eine neue StopWatch-Instanz erstellt und startet. Zum Aufrufen einer statische Methode aus einer .NET Framework-Klasse werden der Pfad zum Namespace und der Name der Klasse in eckige Klammern gesetzt, gefolgt von zwei Doppelpunkten und dem Namen der Methode. In unserem Beispiel ist „System.Diagnostics“ der .NET Framework-Namespace, und „StopWatch“ ist die Klasse. Wir benötigen außerdem eine Variable für das System.Diagnostics.StopWatch-Objekt, das von der Methode zurückgegeben wird:

$sw = [system.diagnostics.stopwatch]::startNew()

Anschließend können Sie die $sw-Variable zum Anzeigen von Informationen über das ausgeführte StopWatch verwenden. So können Sie z. B. die Ergebnisse an das Cmdlet „Format-List“ weiterleiten, um den Wert aller im Objekt enthaltenen Eigenschaften anzuzeigen:

PS C:\> $sw | Format-List -Property *

IsRunning           : True
Elapsed             : 00:00:22.5467175
ElapsedMilliseconds : 22546
ElapsedTicks        : 67472757628

StopWatch besitzt einige nützliche Methoden, die in Abbildung 1 angezeigt werden. Die wichtigste ist die Stop-Methode, da bei Verwendung der statischen StartNew-Methode das StopWatch-Objekt erstellt und gleichzeitig gestartet wird. Höchstwahrscheinlich beenden Sie daher das StopWatch-Objekt, um festzustellen, wie viel Zeit die Aktivität in Anspruch genommen hat.

Abbildung 1 StopWatch-Methoden
Name Definition
Equals System.Boolean Equals(Object obj)
GetHashCode System.Int32 GetHashCode()
GetType System.Type GetType()
get_Elapsed System.TimeSpan get_Elapsed()
get_ElapsedMilliseconds System.Int64 get_ElapsedMilliseconds()
get_ElapsedTicks System.Int64 get_ElapsedTicks()
get_IsRunning System.Boolean get_IsRunning()
Reset System.Void Reset()
Start System.Void Start()
Stop System.Void Stop()
ToString System.String ToString()

Im Skript „Set-StopWatchRecordValues.ps1“ erstellen wir vier Funktionen zum Erstellen und Verwalten des StopWatch-Objekts und zum Aufzeichnen der vergangenen Zeit in der Registrierung. Beim ersten Ausführen erstellt das Skript einen Registrierungsschlüssel und informiert den Benutzer darüber, dass keine gespeicherten Informationen vorhanden sind (siehe Abbildung 2).

fig02.gif

Abbildung 2 Im neuen Registrierungsschlüssel sind keine Informationen gespeichert

Das Skript erstellt dann die Registrierungseigenschaft und speichert die aktuelle Ausführungszeit in der Registrierung (siehe Abbildung 3). Wenn das Skript anschließend ausgeführt wird, werden die Registrierungsdaten abgerufen, angezeigt und aktualisiert (siehe Abbildung 4).

Abbildung 3 Registrierungsschlüssel, der die aktuelle Ausführungszeit speichert

fig04.gif

Abbildung 4 Durch erneutes Ausführen des Skripts werden Registrierungsdaten abgerufen, angezeigt und aktualisiert

Das Skript verwendet einen einzigen Parameter namens „$debug“, wobei es sich um einen Parameter handelt, der nur Auswirkungen hat, wenn er vorhanden ist. Wenn Sie das Skript mit dem Schalter „–debug“ ausführen, werden ausführliche Informationen (siehe Abbildung 5) ausgedruckt. Dazu gehört z. B., ob der Registrierungsschlüssel gefunden, welche Aktion das Skript für die Ausführung vorbereitet und wann die Ausführung der Aktion abgeschlossen wurde.

Abbildung 5 Ausführen des Skripts mit dem Schalter „–debug“

Um einen Befehlszeilenparameter zu erstellen, wird die Param-Anweisung wie folgt verwendet:

Param([switch]$debug)

Im Anschluss an die Param-Anweisung, die die erste nicht kommentierte Zeile im Skript sein muss, wird die erste Funktion erstellt. Diese Funktion namens „Set-StopWatch“ wird zum Erstellen und Starten oder zum Beenden von StopWatch verwendet. Der für den $action-Eingabeparameter der Funktion angegebene Wert bestimmt die Aufgabe der Funktion. Die Funktionsdeklaration sieht aus wie folgt:

Function Set-StopWatch($action)

Mithilfe einer switch-Anweisung wird die Aktion ausgewählt, die durchgeführt wird. An dieser Stelle kommt die erste debug-Anweisung ins Spiel. Zum Schreiben der Debuginformationen in die Konsoleneingabeaufforderung wird das Cmdlet „Write-Debug“ verwendet. Das Tolle am Cmdlet „Write-Debug“ besteht darin, dass es den Text automatisch gelb und schwarz formatiert (dies ist konfigurierbar). Außerdem schreibt es nur dann Informationen in die Konsole, wenn Sie die Anweisung dazu geben. Standardmäßig wird von Write-Debug nichts an die Konsole ausgegeben. Die Eingabevariable für die Set-StopWatch-Funktion ist $action. Die Switch-Anweisung bestimmt anhand des Werts der $action-Variablen, welche Aktion ausgeführt wird:

Write-Debug "Set-StopWatch action is $action
 Switch ($action)

Nun muss die Aktion definiert werden, die stattfinden soll. Die erste Aktion findet statt, wenn der Wert der $action-Variablen „Start“ entspricht. Wenn dies der Fall ist, verwenden wir die statische StartNew-Methode aus der System.Diagnostic.StopWatch-Klasse und speichern das resultierende StopWatch-Objekt in der $sw-Variablen. Außerdem erstellen wir eine debug-Anweisung zum Zeichen dafür, dass der Timer gestartet wird. Denken Sie jedoch daran, dass dies nur angezeigt wird, wenn das Skript mit dem Schalter „–debug“ gestartet wird:

 {
  "Start" { 

Write-Debug "Starting Timer"
              $script:sw = [system.diagnostics
                 .stopwatch]::StartNew() 
             }

Wenn $action mit stop übereinstimmt, schreiben wir eine debug-Anweisung, mit der erklärt wird, dass wir den Timer beenden. Anschließend prüfen wir, ob der Registrierungsschlüssel vorhanden ist. Wenn dies der Fall ist, erstellen wir eine Variable namens „$swv“ und setzen Sie auf „$null“. Dann wird eine weitere Debugmeldung ausgegeben:

  "Stop" { 
Write-Debug "Stopping Timer"
               If(Test-Path -path $path)
                  {
                    $swv = $null
Write-Debug "$path was found. Calling Get-StopWatchvalue"

Als Nächstes rufen wir die Get-StopWatchvalue-Funktion auf und übergeben ihr die soeben erstellte $swv-Variable. In diesem Code übergeben wir die Variable durch Verweis, was bedeutet, dass die Funktion der Variablen einen neuen Wert zuweist und wir sie außerhalb der Funktion verwenden, die ihr den Wert zuweist. Um die Variable durch Verweis zu übergeben, müssen wir $swv in einen Verweistyp konvertieren. Wir verwenden [ref], um diese Konvertierung durchzuführen. Beachten Sie, dass wir die $swv-Variable zuvor erstellen mussten, da sich die Variable nicht in einen Verweistyp umwandeln lässt, wenn sie nicht existiert:

                 Get-StopWatchvalue([ref]$swv)
Write-Debug "Get-StopWatchvalue swv was: $($swv)"
                  }

Wenn der Registrierungsschlüssel nicht vorhanden ist, schreiben wir einige debug-Anweisungen, erstellen die $swv-Variable und setzen Sie auf null. Anschließend rufen wir die New-StopWatchKey-Funktion auf, die den Registrierungsschlüssel erstellt:

               Else

                 {
Write-Debug "$path was not found"
                  $swv = $null

Write-Debug "$swv is null. Calling New-StopWatchKey"
                  New-StopWatchKey

Nach Abschluss der New-StopWatchKey-Funktion geben wir eine weitere debug-Anweisung aus und rufen die Get-StopWatchvalue-Funktion auf. Außerdem übergeben wir die $swv-Variable durch Verweis ($swv wird später verwendet, um die Daten anzuzeigen, die aus der Registrierung abgerufen wurden):

Write-Debug "Obtaining default value from get-StopWatchvalue"
                 et-StopWatchvalue([ref]$swv)
                 }

Nun müssen wir StopWatch beenden. Zunächst verwenden wir eine weitere debug-Anweisung, um eine Stoppmeldung auszugeben. Anschließend rufen wir die Stop-Methode aus dem StopWatch-Objekt auf, das in der $sw-Variablen gespeichert ist. Nach dem Beenden von StopWatch müssen wir das System.TimeSpan-Objekt, das über die Elapsed-Eigenschaft abgerufen wird, in eine Zeichenfolge konvertieren, damit wir seinen Wert in der Registrierung speichern können. Wir übergeben die Zeichenfolgendarstellung des timespan-Objekts an die Set-StopWatchValue-Funktion wie folgt:

Write-Debug "Stopping the stop watch"
               $script:sw.Stop() 
Write-Debug "Converting stop watch to string, and calling
 Set-StopWatchValue"
                   Set-StopWatchValue($script:
                      sw.Elapsed.toString())

Nun kann die Ausgabe an die Konsole erfolgen. Als Erstes stellen wir fest, wie viel Zeit der Befehl für die Ausführung benötigt hat. Wir verwenden die Skriptbereichsvariable „$sw“ und rufen die Elapsed-Eigenschaft ab. Ein Teilausdruck wird verwendet, um zu erzwingen, dass bei der Auswertung der Elapsed-Eigenschaft das timespan-Objekt zurückgegeben wird.

Dies mag ein wenig verwirrend erscheinen. Sie müssen jedoch wissen, dass es in Windows PowerShell zwei Arten von Zeichenfolgenzeichen gibt. Da wären erstens Literalzeichenfolgen, die mit einfachen Anführungszeichen dargestellt werden. Bei einer Literalzeichenfolge haben wir es mit einer originalgetreuen Darstellung auf dem Bildschirm zu tun. Dies bedeutet, dass eine Variable innerhalb einfacher Anführungszeichen nicht erweitert wird:

PS C:\> $a = "this is a string"
PS C:\> "This is what is in $a"
This is what is in $a

Wenn Sie erweiterbare Zeichenfolgen verwenden, dargestellt mit doppelten Anführungszeichen, wird der Wert der Variablen erweitert und ausgegeben:

PS C:\> $a = "this is a string"
PS C:\> "This is what is in $a"
This is what is in this is a string

Auch wenn dies anfangs frustrierend ist: Sie können es zu Ihrem Vorteil nutzen, um eine Verkettung von Zeichenfolgen und Variablen zu vermeiden. Wenn Sie sich der Existenz der beiden Zeichenfolgen bewusst sind, können Sie das Graviszeichen verwenden, um bei Bedarf die Variablenerweiterung zu unterdrücken:

PS C:\> $a = "this is a string"
PS C:\> "This is what is in "$a: $a"
This is what is in $a: this is a string

Ohne erweiterbare Zeichenfolgen müssten Sie die Ausgabe wie folgt verketten:

PS C:\> $a = "this is a string"
PS C:\> "This is what is in $a: " + $a
This is what is in $a: this is a string

Was hat dies nun mit unserem Code zu tun? Wenn ein Objekt in einer erweiterbaren Zeichenfolge erweitert wird, wird der Name des Objekts angegeben. Wenn Sie den Wert sehen möchten, müssen Sie einen Teilausdruck erstellen, indem Sie das Objekt in Klammern und ein Dollarzeichen davor setzen. Hierdurch wird die Auswertung des Objekts erzwungen. An die Befehlszeile wird die Standardeigenschaft zurückgegeben:

PS C:\> "$sw.Elapsed"
System.Diagnostics.Stopwatch.Elapsed
PS C:\> "$($sw.Elapsed)"
00:00:07.5247519

In der Ausgabe drucken wir eine Meldung, die angibt, wie viel Zeit der Befehl in Anspruch genommen hat, sowie den Wert, der in der $swv-Variablen gespeichert ist:

"The command took $($script:sw.Elapsed)"
"Previous command took: " + $swv

Bei Verwendung der Switch-Anweisung empfiehlt es sich immer, eine Standardaktion zu erstellen. Wird das Skript nicht mit dem Schalter „–debug“ ausgeführt, gibt es den Wert der $action-Variablen aus und weist den Benutzer an, entweder Start oder Stop zu verwenden. Bei Ausführung mit dem Schalter „–debug“ werden mehrere verschiedene Zeilen gedruckt. In jedem Fall wird das Skript durch Aufrufen des exit-Befehls wie folgt beendet:

   Default {
                 if(!$debug) {"$action is not understood. Specify Start / Stop"} 
Write-Debug "Entering default action. $action was specified."
Write-Debug "Action value must be either Start or Stop"
Write-Debug "Exiting script now"
                  Exit
               }
} #end Switch
} #end Set-StopWatch

Betrachten wir nun die New-StopWatchKey-Funktion, die aufgerufen wird, wenn das Skript feststellt, dass der Skriptregistrierungsschlüssel noch nicht erstellt wurde. Als Erstes gibt die New-StopWatchKey-Funktion eine Debugmeldung aus. Dann wird mithilfe des Cmdlets „New-Item“ der Registrierungsschlüssel erstellt. Die resultierende Meldung wird an das Cmdlet „Out-Null“ weitergeleitet, um ein Überladen der Anzeige zu vermeiden.

Eine weitere Debugmeldung wird ausgegeben. Anschließend wird die Registrierungseigenschaft für die Speicherung der früheren Laufzeit erstellt. Hierzu verwenden wir das Cmdlet „New-ItemProperty“. Die resultierende Meldung aus diesem Cmdlet wird ebenfalls an das Cmdlet „Out-Null“ gesendet. Nach der Ausgabe einer letzten Debugmeldung verlassen wir die Funktion:

Function New-StopWatchKey()
{
 Write-Debug "Inside New-StopWatchKey. Creating new item $path"
New-Item -path $path -force | 
out-null
Write-Debug "Creating new item property $property"
New-ItemProperty -Path $path "
-Name $property -PropertyType string -value "no data" | 
 out-null
Write-Debug "Leaving New-StopWatchkey"
} #end New-StopWatchKey

Nun müssen wir die Get-StopWatchvalue-Funktion erstellen, um die in der Registrierung gespeicherten Daten zu lesen und die Daten der $swv-Verweisvariablen zuzuweisen. Hierzu geben wir zuerst einige Debugmeldungen aus und erstellen dann mithilfe des Cmdlets „Get-ItemProperty“ ein benutzerdefiniertes Windows PowerShell-Objekt, das in der $swValue-Variablen gespeichert wird. Wie Sie hier sehen, sind mehrere Eigenschaften im Objekt enthalten:

PS C:\> $swValue = Get-ItemProperty -Path HKCU:\Scripting\Stopwatch
PS C:\> $swValue

PSPath          : Microsoft.PowerShell.Core\Registry::HKEY_CURRENT_USER\Scripting\Stopwatch
PSParentPath    : Microsoft.PowerShell.Core\Registry::HKEY_CURRENT_USER\Scripting
PSChildName     : Stopwatch
PSDrive         : HKCU
PSProvider      : Microsoft.PowerShell.Core\Registry
PreviousCommand : 00:00:00.3153793

Sie müssen nicht die Zwischenvariable verwenden, um die frühere value-Eigenschaft abzurufen. Sie können Klammern verwenden und die Eigenschaft direkt abfragen. Dies kann ein wenig verwirrend sein, aber die Syntax ist korrekt, wie Sie hier sehen können:

PS C:\> (Get-ItemProperty -Path HKCU:\Scripting\Stopwatch).PreviousCommand
00:00:00.3153793

Wenn das benutzerdefinierte Objekt vorliegt, fragen wir die PreviousCommand-Eigenschaft ab und weisen sie der value-Eigenschaft der $swv-Variablen (Verweistyp) zu. Noch einige debug-Anweisungen, und wir haben die Arbeit mit der Get-StopWatchvalue-Funktion abgeschlossen:

Function Get-StopWatchvalue([ref]$swv)
{
Write-Debug "Inside Get-StopWatchvalue."
Write-Debug "Obtaining $path\$property"
$swValue = Get-ItemProperty -Path $path "
  -Name $property
$swv.value = $swValue.PreviousCommand
Write-Debug "Value of "$swv is $($swv.value)"
Write-Debug "Leaving Get-StopWatchvalue"
} #end Get-StopWatchvalue

Der nächste Schritt besteht darin, die Zeitdauer für die Ausführung des Befehls in die Registrierung zu schreiben. Also erstellen wir die Set-StopWatchvalue-Funktion. Diese Funktion akzeptiert den Wert, der in der Variablen „$newSwv“ in die Registrierung geschrieben werden soll. Wir schreiben einige debug-Anweisungen und rufen dann das Cmdlet „Set-ItemProperty“ auf, an das wir den in der $path-Variablen gespeicherten Pfad, den Namen der in der $property-Variablen gespeicherten Registrierungseigenschaft und den in der $newSwv-Variablen gespeicherten Wert übergeben. Anschließend geben wir eine weitere Debugmeldung aus und verlassen die Set-StopWatchValue-Funktion:

Function Set-StopWatchvalue($newSwv)
{
Write-Debug "Inside Set-StopWatchvalue"
Write-Debug "setting $path\$property to $newSwv"
Set-ItemProperty -Path $path "
-Name $property -Value $newSwv
Write-Debug "Leaving Set-StopWatchvalue"
} #end Set-StopWatchvalue

Nun haben wir alle für das Skript erforderlichen Funktionen erstellt. Am Einstiegspunkt des Skripts wird zuerst getestet, ob die $debug-Variable vorhanden ist. Wenn dies der Fall ist, wurde das Skript mit dem Schalter „–debug“ ausgeführt. Wir ändern dann den Wert der automatischen Variablen „$DebugPreference“ in „continue“. Standardmäßig ist die Variable „$DebugPreference“ auf „silently continue“ eingestellt. Dies bedeutet, dass vom Cmdlet „Write-Debug“ keine Debugmeldungen angezeigt werden.

In unserem Skript sollen die StopWatch-Zeiten in einem Registrierungsschlüssel unter der HKEY_Current_User-Struktur namens „Scripting\Stopwatch“ gespeichert werden. Wir verwenden eine Eigenschaft namens „PreviousCommand“. Jede ist den entsprechenden Variablen zugewiesen. Nach dem Initialisieren der Variablen rufen wir als Erstes die Set-StopWatch-Funktion mit Start als Aktion auf. Nach dem Ausführen dieser Funktion rufen wir das Cmdlet „Get-Process“ auf:

if($debug) { $DebugPreference = "continue" }
$path = "HKCU:\Scripting\Stopwatch"
$property = "PreviousCommand"
Set-StopWatch "Start"
Get-Process

Wenn Sie dieses Skript für die Zeitmessung verschiedener Aktivitäten verwenden, fügen Sie an dieser Stelle alles Erforderliche hinzu. Sie könnten jetzt sogar ein Skript aufrufen oder entsprechend Ihren Anforderungen beliebig viele Befehle einschließen.

Wenn die $debug-Variable nicht existiert, wird das Skript im normalen Modus ausgeführt. In diesem Fall ist es nicht erforderlich, die Ergebnisse des Aufrufs des Cmdlets „Get-Process“ auf dem Bildschirm anzuzeigen, da wir nur an der Zeitmessung der Aktivität interessiert sind. Daher verwenden wir den not-Operator (das Ausrufezeichen oder wie immer Sie den Operator nennen), um anzugeben, dass bei Abwesenheit einer debug-Variablen der Bildschirm mithilfe der Clear-Host-Funktion von Windows PowerShell geleert wird. Abschließend rufen wir die Set-StopWatch-Funktion mit der Stop-Aktion auf, um den Vorgang zu beenden:

if(!$debug) {Clear-Host}
Set-StopWatch "Stop"

Abbildung 6 zeigt das vollständige Skript „Set-StopWatchRecordValues.ps1“.

Abbildung 6 Set-StopWatchRecordValues.ps1

Param([switch]$debug)
Function Set-StopWatch($action)
{
Write-Debug “Set-StopWatch action is $action”
 Switch ($action)
 {
  “Start” {
Write-Debug “Starting Timer”
               $script:sw = [system.diagnostics.stopwatch]::StartNew()
            }
  “Stop” {
Write-Debug “Stopping Timer”
               If(Test-Path -path $path)
                  {
                    $swv = $null
Write-Debug “$path was found. Calling Get-StopWatchvalue”
                    Get-StopWatchvalue([ref]$swv)
Write-Debug “Get-StopWatchvalue swv was: $($swv)”
                   }
               Else
                 {
Write-Debug “$path was not found”
                 $swv = $null
Write-Debug “$swv is null. Calling New-StopWatchKey”
                 New-StopWatchKey
Write-Debug “Obtaining default value from get-StopWatchvalue”
                 Get-StopWatchvalue([ref]$swv)
                }
Write-Debug “Stopping the stop watch”
               $script:sw.Stop()
Write-Debug “Converting stop watch to string, and calling Set-StopWatchValue”
               Set-StopWatchValue($script:sw.Elapsed.toString())
               “The command took $($script:sw.Elapsed)”
               “Previous command took: “ + $swv
              }
      Default {
                  if(!$debug) {“$action is not understood. Specify Start / Stop”}
Write-Debug “Entering default action. $action was specified.”
Write-Debug “Action value must be either Start or Stop”
Write-Debug “Exiting script now”
                 Exit
              }
 } #end Switch
} #end Set-StopWatch

Function New-StopWatchKey()
{
Write-Debug “Inside New-StopWatchKey. Creating new item $path”
 New-Item -path $path -force |
 out-null
Write-Debug “Creating new item property $property”
 New-ItemProperty -Path $path `
 -Name $property -PropertyType string -value “no data” |
 out-null
Write-Debug “Leaving New-StopWatchkey”
} #end New-StopWatchKey

Function Get-StopWatchvalue([ref]$swv)
{
Write-Debug “Inside Get-StopWatchvalue.”
Write-Debug “Obtaining $path\$property”
 $swValue = Get-ItemProperty -Path $path `
  -Name $property
 $swv.value = $swValue.PreviousCommand
Write-Debug “Value of `$swv is $($swv.value)”
Write-Debug “Leaving Get-StopWatchvalue”
} #end Get-StopWatchvalue

Function Set-StopWatchvalue($newSwv)
{
Write-Debug “Inside Set-StopWatchvalue”
Write-Debug “setting $path\$property to $newSwv”
 Set-ItemProperty -Path $path `
 -Name $property -Value $newSwv
Write-Debug “Leaving Set-StopWatchvalue”
} #end Set-StopWatchvalue

# *** entry point ***

if($debug) { $DebugPreference = “continue” }
$path = “HKCU:\Scripting\Stopwatch”
$property = “PreviousCommand”
Set-StopWatch “Start”
Get-Process
if(!$debug) {Clear-Host}
Set-StopWatch “Stop”

Ich hoffe, Ihnen hat dieser Ausflug in die StopWatch-Klasse gefallen. Weitere Informationen finden Sie im TechNet-Skriptcenter in unseren täglichen „Hey, Scripting Guy!“-Artikeln.

Ed Wilson ist ein bekannter Skriptingexperte. Er hat acht Bücher geschrieben und bei Microsoft Press veröffentlicht, darunter fünf Titel zu Microsoft Windows-Skripting, und arbeitet derzeit an einem Buch über bewährte Methoden für Windows PowerShell. Ed Wilson besitzt mehr als 20 Branchenzertifizierungen, darunter als Microsoft Certified Systems Engineer (MCSE) und Certified Information Systems Security Professional (CISSP). Zu seinen Hobbys gehören Holzbearbeitung, Unterwasserfotografie und Sporttauchen. Und Teetrinken.

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 Liebendorfer ganz oben auf der Liste, und daher ist er hier gut aufgehoben. Als größte Leistung in seinem Leben betrachtet er seine wunderbare Tochter.