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 Component
Role
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 continue
en premier. Tout comme avec une boucle foreach
continue
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.