Articles

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 ComponentRole 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.

Schreibe einen Kommentar

Deine E-Mail-Adresse wird nicht veröffentlicht. Erforderliche Felder sind mit * markiert.