Articles

Tout ce que vous avez toujours voulu savoir sur l’instruction switch

  • 01/03/2021
  • 12 minutes à lire
    • s
    • c
    • x

Comme beaucoup d’autres langages, PowerShell a des commandes pour contrôler le flux d’exécution dans vos scripts. L’une de ces instructions est l’instruction switch et dans PowerShell, elle offre des fonctionnalités introuvables dans d’autres langues. Aujourd’hui, nous plongeons profondément dans le travail avec le PowerShell switch.

Note

La version originale de cet article est apparue sur le blog écrit par @KevinMarquette. L’équipe de ThePowerShell remercie Kevin d’avoir partagé ce contenu avec nous. Veuillez consulter son blog atPowerShellExplained.com .

L’instruction if

L’une des premières instructions que vous apprenez est l’instruction if. Il vous permet d’exécuter un bloc de script si une instruction est $true.

if ( Test-Path $Path ){ Remove-Item $Path}

Vous pouvez avoir une logique beaucoup plus compliquée en utilisant les instructions elseif et else. Voici un exemple où j’ai une valeur numérique pour le jour de la semaine et je veux obtenir le nom sous forme de chaîne.

$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

Il s’avère que c’est un modèle commun et qu’il existe de nombreuses façons de traiter cela. L’un d’eux est avec un switch.

Instruction Switch

L’instruction switch vous permet de fournir une variable et une liste de valeurs possibles. Si la valeur correspond à la variable, son bloc de script est exécuté.

$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'

Pour cet exemple, la valeur de $day correspond à l’une des valeurs numériques, puis le nom correct est attribué à $result. Nous ne faisons qu’une affectation de variable dans cet exemple, mais tout PowerShell peut être exécuté dans ces blocs de script.

Assigner à une variable

Nous pouvons écrire ce dernier exemple d’une autre manière.

$result = switch ( $day ){ 0 { 'Sunday' } 1 { 'Monday' } 2 { 'Tuesday' } 3 { 'Wednesday' } 4 { 'Thursday' } 5 { 'Friday' } 6 { 'Saturday' }}

Nous plaçons la valeur sur le pipeline PowerShell et l’affectons au $result. Vous pouvez faire la même chose avec les instructions if et foreach.

Par défaut

Nous pouvons utiliser le mot clé default pour identifier ce qui devrait se passer s’il n’y a pas de correspondance.

$result = switch ( $day ){ 0 { 'Sunday' } # ... 6 { 'Saturday' } default { 'Unknown' }}

Ici, nous renvoyons la valeur Unknown dans le cas par défaut.

Chaînes

Je faisais correspondre des nombres dans ces derniers exemples, mais vous pouvez également faire correspondre des chaînes.

$item = 'Role'switch ( $item ){ Component { 'is a component' } Role { 'is a role' } Location { 'is a location' }}
is a role

J’ai décidé de ne pas envelopper le ComponentRole et Location correspond entre guillemets ici pour souligner qu’ils sont facultatifs. Le switch les traite comme une chaîne dans la plupart des cas.

Tableaux

L’une des fonctionnalités intéressantes du PowerShell switch est la façon dont il gère les tableaux. Si vous donnez à un switch un tableau, il traite chaque élément de cette collection.

$roles = @('WEB','Database')switch ( $roles ) { 'Database' { 'Configure SQL' } 'WEB' { 'Configure IIS' } 'FileServer' { 'Configure Share' }}
Configure IISConfigure SQL

Si vous avez des éléments répétés dans votre tableau, ils sont appariés plusieurs fois par la section appropriée.

PSItem

Vous pouvez utiliser $PSItem ou $_ pour référencer l’élément en cours qui a été traité. Lorsque nous faisons une correspondance simple, $PSItem est la valeur que nous faisons correspondre. Je vais effectuer des correspondances avancées dans la section suivante où cette variable est utilisée.

Paramètres

Une caractéristique unique du PowerShell switch est qu’il a un certain nombre de paramètres de commutation quichanger comment il fonctionne.

– Sensible à la casse

Les correspondances ne sont pas sensibles à la casse par défaut. Si vous devez être sensible à la casse, vous pouvez utiliser -CaseSensitive. Cela peut être utilisé en combinaison avec les autres paramètres du commutateur.

– Caractère générique

Nous pouvons activer le support des caractères génériques avec le commutateur -wildcard. Cela utilise la même logique générique que l’opérateur -like pour faire chaque correspondance.

$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

Ici, nous traitons un message, puis l’émettons sur différents flux en fonction du contenu.

– Regex

L’instruction switch prend en charge les correspondances regex tout comme les caractères génériques.

switch -Regex ( $message ){ '^Error' { Write-Error -Message $Message } '^Warning' { Write-Warning -Message $Message } default { Write-Information $message }}

J’ai plus d’exemples d’utilisation de l’expression régulière dans un autre article que j’ai écrit: Les nombreuses façons d’utiliser l’expression régulière.

-File

Une caractéristique peu connue de l’instruction switch est qu’elle peut traiter un fichier avec le paramètre -File. Vous utilisez -file avec un chemin d’accès à un fichier au lieu de lui donner une expression de variable.

switch -Wildcard -File $path{ 'Error*' { Write-Error -Message $PSItem } 'Warning*' { Write-Warning -Message $PSItem } default { Write-Output $PSItem }}

Cela fonctionne comme le traitement d’un tableau. Dans cet exemple, je le combine avec une correspondance de caractères génériques etfaire usage du $PSItem. Cela traiterait un fichier journal et le convertirait en messages d’avertissement et d’erreurs en fonction des correspondances d’expressions régulières.

Détails avancés

Maintenant que vous connaissez toutes ces fonctionnalités documentées, nous pouvons les utiliser dans le contexte d’un traitement plus avancé.

Expressions

Le switch peut être sur une expression au lieu d’une variable.

switch ( ( Get-Service | Where status -eq 'running' ).name ) {...}

Quelle que soit l’expression évaluée, c’est la valeur utilisée pour la correspondance.

Plusieurs correspondances

Vous avez peut-être déjà compris cela, mais un switch peut correspondre à plusieurs conditions. Ceci est particulièrement vrai lorsque vous utilisez des correspondances -wildcard ou -regex. Vous pouvez ajouter la même condition plusieurs fois et toutes sont déclenchées.

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

Ces trois instructions sont déclenchées. Cela montre que chaque condition est vérifiée (dans l’ordre). Cela est vrai pour le traitement des tableaux où chaque élément vérifie chaque condition.

Continue

Normalement, c’est là que je présenterais l’instruction break, mais il vaut mieux que nous apprenions comment utiliser continueen premier. Tout comme avec une boucle foreachcontinue continue sur l’élément suivant dans la collection ou quitte le switch s’il n’y a plus d’éléments. Nous pouvons réécrire ce dernier exemple avec les instructions continue afin qu’une seule instruction s’exécute.

switch ( 'Word' ){ 'word' { 'lower case word match' continue } 'Word' { 'mixed case word match' continue } 'WORD' { 'upper case word match' continue }}

lower case word match

Au lieu de faire correspondre les trois éléments, le premier est mis en correspondance et le commutateur continue à la valeur suivante. Parce qu’il n’y a plus de valeurs à traiter, le commutateur se ferme. Cet exemple suivant montre comment un caractère générique peut correspondre à plusieurs éléments.

switch -Wildcard -File $path{ '*Error*' { Write-Error -Message $PSItem continue } '*Warning*' { Write-Warning -Message $PSItem continue } default { Write-Output $PSItem }}

Parce qu’une ligne dans le fichier d’entrée peut contenir à la fois le mot Error et Warning, nous voulons seulement que le premier s’exécute puis continue à traiter le fichier.

Break

Une instruction break quitte le commutateur. C’est le même comportement que continue présente pour les valeurs uniques. La différence est affichée lors du traitement d’un tableau. arrête tout le traitement dans le commutateur et continue passe à l’élément suivant.

$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

Dans ce cas, si nous frappons des lignes commençant par Error alors nous obtenons une erreur et le commutateur s’arrête.C’est ce que cette instruction fait pour nous. Si nous trouvons Error à l’intérieur de la chaîne et non juste au début, nous l’écrivons comme un avertissement. Nous faisons la même chose pour Warning. Il est possible qu’une ligne puisse avoir à la fois le mot Error et Warning, mais nous n’avons besoin que d’un seul processus. C’est ce que l’instruction continue fait pour nous.

Étiquettes de rupture

L’instruction switch prend en charge les étiquettes break/continue tout comme 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 } }}

Personnellement, je n’aime pas l’utilisation d’étiquettes de rupture, mais je voulais les signaler car elles se confèrent si vous ne les avez jamais vues auparavant. Lorsque vous avez plusieurs déclarations switch ou foreach qui sont imbriquées, vous voudrez peut-être sortir de plus que l’élément le plus interne. Vous pouvez placer un labelon a switch qui peut être la cible de votre .

Enum

PowerShell 5.0 nous a donné des énumérations et nous pouvons les utiliser dans un commutateur.

enum Context { Component Role Location}$item = ::Roleswitch ( $item ){ Component { 'is a component' } Role { 'is a role' } Location { 'is a location' }}
is a role

Si vous voulez tout garder comme des énumérations fortement typées, vous pouvez les placer entre parenthèses.

switch ($item ){ (::Component) { 'is a component' } (::Role) { 'is a role' } (::Location) { 'is a location' }}

Les parenthèses sont nécessaires ici pour que le commutateur ne traite pas la valeur ::Location comme une chaîne littérale.

ScriptBlock

Nous pouvons utiliser un scriptblock pour effectuer l’évaluation d’une correspondance si nécessaire.

$age = 37switch ( $age ){ {$PSItem -le 18} { 'child' } {$PSItem -gt 18} { 'adult' }}
'adult'

Cela ajoute de la complexité et peut rendre votre switch difficile à lire. Dans la plupart des cas où vous utiliseriez quelque chose comme ça, il serait préférable d’utiliser les instructions if et elseif. J’envisagerais d’utiliser cela si j’avais déjà un gros interrupteur en place et que j’avais besoin de deux éléments pour atteindre le même bloc d’évaluation.

Une chose qui, à mon avis, aide à la lisibilité est de placer le scriptblock entre parenthèses.

switch ( $age ){ ({$PSItem -le 18}) { 'child' } ({$PSItem -gt 18}) { 'adult' }}

Il s’exécute toujours de la même manière et donne une meilleure pause visuelle lorsqu’il le regarde rapidement.

Regexmatchesmatches

Nous devons revisiter regex pour toucher à quelque chose qui n’est pas immédiatement évident. L’utilisation de regexpopule la variable $matches. Je vais dans l’utilisation de $matches plus quand je parle des nombreuses façons d’utiliser regex. Voici un exemple rapide pour le montrer en action avec des correspondances nommées.

$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

nullnull

Vous pouvez faire correspondre une valeur $null qui ne doit pas nécessairement être la valeur par défaut.

$value = $nullswitch ( $value ){ $null { 'Value is null' } default { 'value is not null' }}```OutputValue is null

Il en va de même pour une chaîne vide.

switch ( '' ){ '' { 'Value is empty' } default { 'value is a empty string' }}```OutputValue is empty

Expression constante

Lee Dailey a souligné que nous pouvons utiliser une expression $true pour évaluer les éléments .Imaginez si nous avons plusieurs vérifications booléennes qui doivent se produire.

$isVisible = $false$isEnabled = $true$isSecure = $trueswitch ( $true ){ $isEnabled { 'Do-Action' } $isVisible { 'Show-Animation' } $isSecure { 'Enable-AdminMenu' }}
Do-ActionEnabled-AdminMenu

C’est un moyen propre d’évaluer et d’agir sur l’état de plusieurs champs booléens. Le truc cool à ce sujet est que vous pouvez avoir une correspondance retournant le statut d’une valeur qui n’a pas encore été évaluée.

$isVisible = $false$isEnabled = $true$isAdmin = $falseswitch ( $true ){ $isEnabled { 'Do-Action' $isVisible = $true } $isVisible { 'Show-Animation' } $isAdmin { 'Enable-AdminMenu' }}
Do-ActionShow-Animation

La définition de $isEnabled$true dans cet exemple garantit que $isVisible est également définie sur $true. Ensuite, lorsque $isVisible est évalué, son bloc de script est invoqué. C’est un bitcounter-intuitif mais c’est une utilisation intelligente de la mécanique.

switch variable automatique de commutation

Lorsque le switch traite ses valeurs, il crée un énumérateur et l’appelle $switch. C’est une variable automatique créée par PowerShell et vous pouvez la manipuler directement.

$a = 1, 2, 3, 4switch($a) { 1 { $switch.MoveNext(); $switch.Current } 3 { $switch.MoveNext(); $switch.Current }}

Cela vous donne les résultats de:

24

En déplaçant l’énumérateur vers l’avant, l’élément suivant n’est pas traité par le switch mais vous pouvez accéder directement à cette valeur. J’appellerais ça de la folie.

Autres modèles

Tables de hachage

L’un de mes messages les plus populaires est celui que j’ai fait sur les tables de hachage. L’un des cas d’utilisation d’un hashtable est d’être une table de recherche. C’est une approche alternative à un modèle commun qu’une instruction switch adresse souvent.

$day = 3$lookup = @{ 0 = 'Sunday' 1 = 'Monday' 2 = 'Tuesday' 3 = 'Wednesday' 4 = 'Thursday' 5 = 'Friday' 6 = 'Saturday'}$lookup
Wednesday

Si j’utilise uniquement un switch comme recherche, j’utilise souvent un hashtable à la place.

Enum

PowerShell 5.0 a introduit le Enum et c’est également une option dans ce cas.

$day = 3enum DayOfTheWeek { Sunday Monday Tuesday Wednesday Thursday Friday Saturday}$day
Wednesday

Nous pourrions passer toute la journée à chercher différentes façons de résoudre ce problème. Je voulais juste m’assurer que tu savais que tu avais des options.

Mots finaux

L’instruction switch est simple à première vue, mais elle offre des fonctionnalités avancées que la plupart des gens ne réalisent pas sont disponibles. L’enchaînement de ces fonctionnalités en fait une fonctionnalité puissante. J’espère que tu as appris quelque chose que tu n’avais pas réalisé auparavant.

Laisser un commentaire

Votre adresse e-mail ne sera pas publiée. Les champs obligatoires sont indiqués avec *