Alles, was Sie schon immer über die switch-Anweisung wissen wollten
- 03/01/2021
- 12 Minuten zum Lesen
-
- s
- c
- x
Wie viele andere Sprachen verfügt PowerShell über Befehle zur Steuerung des Ausführungsflusses in yourscripts. Eine dieser Anweisungen ist die switch-Anweisung, die in PowerShell Funktionen bietet, die in anderen Sprachen nicht zu finden sind. Heute tauchen wir tief in die Arbeit mit der PowerShellswitch
ein.
Hinweis
Die Originalversion dieses Artikels erschien auf dem Blog von @KevinMarquette. Das PowerShell-Team dankt Kevin für das Teilen dieser Inhalte mit uns. Bitte schauen Sie sich seinen Blog an atPowerShellExplained.com .
Die if-Anweisung
Eine der ersten Anweisungen, die Sie lernen, ist die if
-Anweisung. Damit können Sie einen Skriptblock ausführenwenn eine Anweisung $true
.
if ( Test-Path $Path ){ Remove-Item $Path}
Sie können viel kompliziertere Logik haben, indem Sie elseif
und else
Anweisungen verwenden. Hier ist ein Beispiel, wo ich einen numerischen Wert für den Wochentag habe und den Namen als Zeichenfolge erhalten möchte.
$day = 3if ( $day -eq 0 ) { $result = 'Sunday' }elseif ( $day -eq 1 ) { $result = 'Monday' }elseif ( $day -eq 2 ) { $result = 'Tuesday' }elseif ( $day -eq 3 ) { $result = 'Wednesday' }elseif ( $day -eq 4 ) { $result = 'Thursday' }elseif ( $day -eq 5 ) { $result = 'Friday' }elseif ( $day -eq 6 ) { $result = 'Saturday' }$result
Wednesday
Es stellt sich heraus, dass dies ein häufiges Muster ist und es viele Möglichkeiten gibt, damit umzugehen. Einer von ihnen ist mit einem switch
.
Switch-Anweisung
Mit der switch
-Anweisung können Sie eine Variable und eine Liste möglicher Werte angeben. Wenn der Wert mit der Variablen übereinstimmt, wird sein Skriptblock ausgeführt.
$day = 3switch ( $day ){ 0 { $result = 'Sunday' } 1 { $result = 'Monday' } 2 { $result = 'Tuesday' } 3 { $result = 'Wednesday' } 4 { $result = 'Thursday' } 5 { $result = 'Friday' } 6 { $result = 'Saturday' }}$result
'Wednesday'
In diesem Beispiel entspricht der Wert von $day
einem der numerischen Werte, dann wird der richtige Name zugewiesen $result
. Wir führen in diesem Beispiel nur eine Variablenzuweisung durch, aber jede PowerShellcan kann in diesen Skriptblöcken ausgeführt werden.
Einer Variablen zuweisen
Wir können das letzte Beispiel auf andere Weise schreiben.
$result = switch ( $day ){ 0 { 'Sunday' } 1 { 'Monday' } 2 { 'Tuesday' } 3 { 'Wednesday' } 4 { 'Thursday' } 5 { 'Friday' } 6 { 'Saturday' }}
Wir platzieren den Wert in der PowerShell-Pipeline und weisen ihn der $result
zu. Sie können dasselbe mit den Anweisungen if
und foreach
tun.
Default
Wir können das Schlüsselwort default
verwenden, um zu identifizieren, was passieren soll, wenn keine Übereinstimmung vorliegt.
$result = switch ( $day ){ 0 { 'Sunday' } # ... 6 { 'Saturday' } default { 'Unknown' }}
Hier geben wir den Wert Unknown
im Standardfall zurück.
Strings
Ich habe in diesen letzten Beispielen Zahlen abgeglichen, aber Sie können auch Strings abgleichen.
$item = 'Role'switch ( $item ){ Component { 'is a component' } Role { 'is a role' } Location { 'is a location' }}
is a role
Ich habe beschlossen, die Component
Role
und Location
Übereinstimmungen hier nicht in Anführungszeichen zu setzen, um dasssie sind optional. Die switch
behandelt diese in den meisten Fällen als Zeichenfolge.
Arrays
Eine der coolen Funktionen der PowerShell switch
ist die Art und Weise, wie Arrays behandelt werden. Wenn Sie einemswitch
ein Array geben, verarbeitet es jedes Element in dieser Sammlung.
$roles = @('WEB','Database')switch ( $roles ) { 'Database' { 'Configure SQL' } 'WEB' { 'Configure IIS' } 'FileServer' { 'Configure Share' }}
Configure IISConfigure SQL
Wenn Sie Elemente in Ihrem Array wiederholt haben, werden sie vom appropriatesection mehrmals abgeglichen.
PSItem
Sie können die $PSItem
oder $_
verwenden, um auf das aktuelle Element zu verweisen, das verarbeitet wurde. Wenn wir eine einfache Übereinstimmung machen, $PSItem
ist der Wert, den wir abgleichen. Ich werde im nächsten Abschnitt, in dem diese Variable verwendet wird, einige erweiterte Übereinstimmungen durchführen.
Parameter
Ein einzigartiges Merkmal der PowerShell switch
ist, dass sie über eine Reihe von Switch-Parametern verfügt, die ihre Leistung ändern.
-CaseSensitive
Bei den Übereinstimmungen wird standardmäßig nicht zwischen Groß- und Kleinschreibung unterschieden. Wenn Sie die Groß-/Kleinschreibung beachten müssen, können Sie-CaseSensitive
. Dies kann in Kombination mit den anderen Schaltparametern verwendet werden.
-Platzhalter
Wir können die Platzhalterunterstützung mit dem Schalter -wildcard
aktivieren. Dies verwendet die gleiche Platzhalterlogik wie der Operator-like
, um jede Übereinstimmung durchzuführen.
$Message = 'Warning, out of disk space'switch -Wildcard ( $message ){ 'Error*' { Write-Error -Message $Message } 'Warning*' { Write-Warning -Message $Message } default { Write-Information $message }}
WARNING: Warning, out of disk space
Hier verarbeiten wir eine Nachricht und geben sie dann basierend auf dem Inhalt in verschiedenen Streams aus.
-Regex
Die switch-Anweisung unterstützt Regex-Übereinstimmungen genauso wie Platzhalter.
switch -Regex ( $message ){ '^Error' { Write-Error -Message $Message } '^Warning' { Write-Warning -Message $Message } default { Write-Information $message }}
Ich habe weitere Beispiele für die Verwendung von Regex in einem anderen Artikel, den ich geschrieben habe: Die vielen Möglichkeiten, Regex zu verwenden.
-File
Ein wenig bekanntes Merkmal der switch-Anweisung ist, dass sie eine Datei mit dem -File
-Parameter verarbeiten kann. Sie verwenden -file
mit einem Pfad zu einer Datei, anstatt ihr einen Variablenausdruck zu geben.
switch -Wildcard -File $path{ 'Error*' { Write-Error -Message $PSItem } 'Warning*' { Write-Warning -Message $PSItem } default { Write-Output $PSItem }}
Es funktioniert wie die Verarbeitung eines Arrays. In diesem Beispiel kombiniere ich es mit Wildcard-Matching undVerwenden Sie die $PSItem
. Dies würde eine Protokolldatei verarbeiten und sie abhängig von den Regex-Übereinstimmungen in warning und errormessages konvertieren.
Erweiterte Details
Nun, da Sie alle diese dokumentierten Funktionen kennen, können wir sie im Rahmen einer erweiterten Verarbeitung verwenden.
Ausdrücke
Die switch
kann auf einem Ausdruck anstelle einer Variablen sein.
switch ( ( Get-Service | Where status -eq 'running' ).name ) {...}
Was auch immer der Ausdruck auswertet, ist der Wert, der für die Übereinstimmung verwendet wird.
Mehrere Übereinstimmungen
Möglicherweise haben Sie dies bereits erkannt, aber ein switch
kann mehreren Bedingungen entsprechen. Dies gilt insbesondere, wenn -wildcard
oder -regex
Übereinstimmungen verwendet werden. Sie können die gleiche Bedingung mehrmals hinzufügen und alle werden ausgelöst.
switch ( 'Word' ){ 'word' { 'lower case word match' } 'Word' { 'mixed case word match' } 'WORD' { 'upper case word match' }}
lower case word matchmixed case word matchupper case word match
Alle drei dieser Anweisungen werden ausgelöst. Dies zeigt, dass jede Bedingung (in der Reihenfolge) überprüft wird. Dies gilt für die Verarbeitung von Arrays, bei denen jedes Element jede Bedingung überprüft.
Weiter
Normalerweise würde ich hier die break
-Anweisung einführen, aber es ist besser, dass wir zuerst lernen, wie man continue
verwendet. Genau wie bei einer foreach
Schleife fährt continue
mit dem nächsten Element in der Sammlung fort oder verlässt die switch
, wenn keine weiteren Elemente vorhanden sind. Wir können das letzte examplewith continue Anweisungen so umschreiben, dass nur eine Anweisung ausgeführt wird.
switch ( 'Word' ){ 'word' { 'lower case word match' continue } 'Word' { 'mixed case word match' continue } 'WORD' { 'upper case word match' continue }}
lower case word match
Anstatt alle drei Elemente abzugleichen, wird das erste Element abgeglichen und der Schalter fährt mit dem nächsten fortwert. Da keine Werte mehr zu verarbeiten sind, wird der Switch beendet. Dieses nächste Beispiel zeigt, wie ein Platzhalter mehreren Elementen entsprechen kann.
switch -Wildcard -File $path{ '*Error*' { Write-Error -Message $PSItem continue } '*Warning*' { Write-Warning -Message $PSItem continue } default { Write-Output $PSItem }}
Da eine Zeile in der Eingabedatei sowohl das Wort Error
als auch Warning
enthalten kann, soll nur die erste Zeile ausgeführt und dann die Datei weiterverarbeitet werden.
Break
Eine break
Anweisung beendet den Schalter. Dies ist das gleiche Verhalten, das continue
für singlevalues . Der Unterschied wird bei der Verarbeitung eines Arrays angezeigt. break
stoppt die gesamte Verarbeitung im switchand continue
wechselt zum nächsten Element.
$Messages = @( 'Downloading update' 'Ran into errors downloading file' 'Error: out of disk space' 'Sending email' '...')switch -Wildcard ($Messages){ 'Error*' { Write-Error -Message $PSItem break } '*Error*' { Write-Warning -Message $PSItem continue } '*Warning*' { Write-Warning -Message $PSItem continue } default { Write-Output $PSItem }}
Downloading updateWARNING: Ran into errors downloading filewrite-error -message $PSItem : Error: out of disk space+ CategoryInfo : NotSpecified: (:) , WriteErrorException+ FullyQualifiedErrorId : Microsoft.PowerShell.Commands.WriteErrorException
Wenn wir in diesem Fall Zeilen treffen, die mit Error
beginnen, erhalten wir einen Fehler und der Schalter stoppt.Dies ist, was diese break
Anweisung für uns tut. Wenn wir Error
in der Zeichenfolge finden und nichtnur am Anfang schreiben wir es als Warnung. Wir machen dasselbe für Warning
. Es ist möglich, dass eine Zeile sowohl das Wort Error
als auch Warning
, aber wir brauchen nur einen toprocess . Dies ist, was die Anweisung continue
für uns tut.
Break labels
Die switch
Anweisung unterstützt break/continue
Beschriftungen wie foreach
.
:filelist foreach($path in $logs){ :logFile switch -Wildcard -File $path { 'Error*' { Write-Error -Message $PSItem break filelist } 'Warning*' { Write-Error -Message $PSItem break logFile } default { Write-Output $PSItem } }}
Ich persönlich mag die Verwendung von Umbruchbeschriftungen nicht, aber ich wollte sie darauf hinweisen, weil sie verwirrend sind, wenn Sie sie noch nie gesehen haben. Wenn Sie mehrere switch
oder foreach
-Anweisungen haben, die verschachtelt sind, möchten Sie möglicherweise aus mehr als dem innersten Element ausbrechen. Sie können ein Label auf einem switch
platzieren, das das Ziel Ihres break
.
Enum
PowerShell 5.0 gab uns Enums und wir können sie in einem Switch verwenden.
enum Context { Component Role Location}$item = ::Roleswitch ( $item ){ Component { 'is a component' } Role { 'is a role' } Location { 'is a location' }}
is a role
Wenn Sie alles als stark typisierte Aufzählungen beibehalten möchten, können Sie sie in Klammern setzen.
switch ($item ){ (::Component) { 'is a component' } (::Role) { 'is a role' } (::Location) { 'is a location' }}
Die Klammern werden hier benötigt, damit der Schalter den Wert ::Location
nicht als Literalzeichenfolge behandelt.
ScriptBlock
Wir können bei Bedarf einen Scriptblock verwenden, um die Auswertung für ein Match durchzuführen.
$age = 37switch ( $age ){ {$PSItem -le 18} { 'child' } {$PSItem -gt 18} { 'adult' }}
'adult'
Dies erhöht die Komplexität und kann Ihre switch
schwer lesbar machen. In den meisten Fällen, in denen Sie verwenden würdenetwas wie dieses wäre es besser, if
und elseif
Anweisungen zu verwenden. Ich würde usingthis in Betracht ziehen, wenn ich bereits einen großen Schalter hätte und zwei Elemente bräuchte, um denselben evaluationblock zu treffen.
Eine Sache, die meiner Meinung nach bei der Lesbarkeit hilft, ist, den Skriptblock in Klammern zu setzen.
switch ( $age ){ ({$PSItem -le 18}) { 'child' } ({$PSItem -gt 18}) { 'adult' }}
Es läuft immer noch auf die gleiche Weise und gibt eine bessere visuelle Pause, wenn man es schnell betrachtet.
Regex $matches
Wir müssen regex erneut aufrufen, um etwas zu berühren, das nicht sofort offensichtlich ist. Die Verwendung von regexpopuliert die $matches
Variable. Ich gehe auf die Verwendung von $matches
mehr ein, wenn ich über die vielen Möglichkeiten spreche, Regex zu verwenden. Hier ist ein kurzes Beispiel, um es in Aktion mit benannten Übereinstimmungen zu zeigen.
$message = 'my ssn is 123-23-3456 and credit card: 1234-5678-1234-5678'switch -regex ($message){ '(?<SSN>\d\d\d-\d\d-\d\d\d\d)' { Write-Warning "message contains a SSN: $($matches.SSN)" } '(?<CC>\d\d\d\d-\d\d\d\d-\d\d\d\d-\d\d\d\d)' { Write-Warning "message contains a credit card number: $($matches.CC)" } '(?<Phone>\d\d\d-\d\d\d-\d\d\d\d)' { Write-Warning "message contains a phone number: $($matches.Phone)" }}
WARNING: message may contain a SSN: 123-23-3456WARNING: message may contain a credit card number: 1234-5678-1234-5678
$null
Sie können einen $null
Wert abgleichen, der nicht der Standardwert sein muss.
$value = $nullswitch ( $value ){ $null { 'Value is null' } default { 'value is not null' }}```OutputValue is null
Gleiches gilt für einen leeren String.
switch ( '' ){ '' { 'Value is empty' } default { 'value is a empty string' }}```OutputValue is empty
Konstanter Ausdruck
Lee Dailey wies darauf hin, dass wir einen konstanten $true
Ausdruck verwenden können, um Elemente auszuwerten.Stellen Sie sich vor, wir haben mehrere boolesche Prüfungen, die durchgeführt werden müssen.
$isVisible = $false$isEnabled = $true$isSecure = $trueswitch ( $true ){ $isEnabled { 'Do-Action' } $isVisible { 'Show-Animation' } $isSecure { 'Enable-AdminMenu' }}
Do-ActionEnabled-AdminMenu
Dies ist eine saubere Möglichkeit, den Status mehrerer boolescher Felder auszuwerten und Maßnahmen zu ergreifen. Das Coole daran ist, dass Sie eine Übereinstimmung mit dem Status eines Werts haben können, der noch nicht ausgewertet wurde.
$isVisible = $false$isEnabled = $true$isAdmin = $falseswitch ( $true ){ $isEnabled { 'Do-Action' $isVisible = $true } $isVisible { 'Show-Animation' } $isAdmin { 'Enable-AdminMenu' }}
Do-ActionShow-Animation
Die Einstellung $isEnabled
auf $true
stellt in diesem Beispiel sicher, dass $isVisible
auch auf$true
. Wenn dann $isVisible
ausgewertet wird, wird sein scriptblock aufgerufen. Dies ist ein Bitcounter-intuitiv, aber eine clevere Nutzung der Mechanik.
$switch automatische Variable
Wenn switch
seine Werte verarbeitet, erstellt es einen Enumerator und ruft ihn $switch
. Dies ist eine automatische Variable, die von PowerShell erstellt wurde und die Sie direkt bearbeiten können.
$a = 1, 2, 3, 4switch($a) { 1 { $switch.MoveNext(); $switch.Current } 3 { $switch.MoveNext(); $switch.Current }}
Dies gibt Ihnen die Ergebnisse von:
24
Wenn Sie den Enumerator vorwärts bewegen, wird das nächste Element nicht von switch
verarbeitet, aber Sie könnenauf diesen Wert direkt zugreifen. Ich würde es Wahnsinn nennen.
Andere Muster
Hashtables
Einer meiner beliebtesten Beiträge ist der, den ich auf Hashtables gemacht habe. Einer der Anwendungsfälle für einehashtable
ist eine Nachschlagetabelle. Dies ist ein alternativer Ansatz für ein allgemeines Muster, das häufig von einerswitch
-Anweisung angesprochen wird.
$day = 3$lookup = @{ 0 = 'Sunday' 1 = 'Monday' 2 = 'Tuesday' 3 = 'Wednesday' 4 = 'Thursday' 5 = 'Friday' 6 = 'Saturday'}$lookup
Wednesday
Wenn ich nur eine switch
als Lookup verwende, verwende ich stattdessen oft eine hashtable
.
Enum
PowerShell 5.0 führte die Enum
und es ist auch eine Option in diesem Fall.
$day = 3enum DayOfTheWeek { Sunday Monday Tuesday Wednesday Thursday Friday Saturday}$day
Wednesday
Wir könnten den ganzen Tag nach verschiedenen Wegen suchen, um dieses Problem zu lösen. Ich wollte nur sicherstellen, dass Sie wissen, dass Sie Optionen haben.
Letzte Worte
Die switch-Anweisung ist oberflächlich einfach, bietet aber einige erweiterte Funktionen, von denen die meisten nicht wissen, dass sie verfügbar sind. Das Aneinanderreihen dieser Funktionen macht dies zu einer leistungsstarken Funktion. Ich hoffe, Sie haben etwas gelernt, was Sie vorher nicht bemerkt hatten.