Notitie
Voor toegang tot deze pagina is autorisatie vereist. U kunt proberen u aan te melden of de directory te wijzigen.
Voor toegang tot deze pagina is autorisatie vereist. U kunt proberen de mappen te wijzigen.
Net als in veel andere talen heeft PowerShell opdrachten voor het beheren van de uitvoeringsstroom in uw scripts. Een van deze instructies is de switch instructie en in PowerShell biedt het functies die niet in andere talen worden gevonden. Vandaag gaan we dieper in op het werken met de PowerShell-switch
.
Notitie
De oorspronkelijke versie van dit artikel verscheen op de blog geschreven door @KevinMarquette. Het PowerShell-team bedankt Kevin voor het delen van deze inhoud met ons. Bekijk zijn blog op PowerShellExplained.com.
De if
-instructie
Een van de eerste verklaringen die u leert, is de if
-verklaring. Hiermee kunt u een scriptblok uitvoeren als een voorwaarde is $true
.
if ( Test-Path $Path )
{
Remove-Item $Path
}
U kunt veel complexere logica hebben met behulp van elseif
- en else
-instructies. Hier volgt een voorbeeld waarin ik een numerieke waarde heb voor de dag van de week en ik de naam als een tekenreeks wil ophalen.
$day = 3
if ( $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
Het blijkt dat dit een gemeenschappelijk patroon is en dat er veel manieren zijn om hiermee om te gaan. Een daarvan heeft een switch
.
Switch-instructie
Met de instructie switch
kunt u een variabele en een lijst met mogelijke waarden opgeven. Als de waarde overeenkomt met de variabele, wordt het scriptblok uitgevoerd.
$day = 3
switch ( $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 dit voorbeeld komt de waarde van $day
overeen met een van de numerieke waarden en wordt de juiste naam toegewezen aan $result
. In dit voorbeeld wordt alleen een variabeletoewijzing uitgevoerd, maar elke PowerShell kan in deze scriptblokken worden uitgevoerd.
Toewijzen aan een variabele
We kunnen dat laatste voorbeeld op een andere manier schrijven.
$result = switch ( $day )
{
0 { 'Sunday' }
1 { 'Monday' }
2 { 'Tuesday' }
3 { 'Wednesday' }
4 { 'Thursday' }
5 { 'Friday' }
6 { 'Saturday' }
}
We plaatsen de waarde in de PowerShell-pijplijn en wijzen deze toe aan de $result
. U kunt hetzelfde doen met de if
- en foreach
-verklaringen.
Verstek
We kunnen het default
trefwoord gebruiken om te bepalen wat er moet gebeuren als er geen overeenkomst is.
$result = switch ( $day )
{
0 { 'Sunday' }
# ...
6 { 'Saturday' }
default { 'Unknown' }
}
Hier retourneren we de waarde Unknown
in het standaardscenario.
Tekenreeksen
In die laatste voorbeelden kwam ik getallen overeen, maar je kunt ook tekenreeksen vergelijken.
$item = 'Role'
switch ( $item )
{
Component
{
'is a component'
}
Role
{
'is a role'
}
Location
{
'is a location'
}
}
is a role
Ik besloot de Component
-,Role
- en Location
-overeenkomsten niet tussen aanhalingstekens te plaatsen om te benadrukken dat ze optioneel zijn. De switch
behandelt deze in de meeste gevallen als een tekenreeks.
Reeksen
Een van de handige functies van de PowerShell-switch
is de manier waarop matrices worden verwerkt. Als u een switch
een array geeft, wordt elk element in die verzameling verwerkt.
$roles = @('WEB','Database')
switch ( $roles ) {
'Database' { 'Configure SQL' }
'WEB' { 'Configure IIS' }
'FileServer' { 'Configure Share' }
}
Configure IIS
Configure SQL
Als u items in uw matrix hebt herhaald, worden deze meerdere keren vergeleken door de juiste sectie.
PSItem
U kunt de $PSItem
of $_
gebruiken om te verwijzen naar het huidige item dat is verwerkt. Wanneer we een eenvoudige vergelijking maken, is $PSItem
de waarde die we matchen. Ik zal enkele geavanceerde matches uitvoeren in het volgende gedeelte waar deze variabele wordt gebruikt.
Parameterwaarden
Een unieke functie van de PowerShell-switch
is dat het een aantal switchparameters heeft die wijzigen hoe het presteert.
-Hoofdlettergevoelig
De overeenkomsten zijn standaard niet hoofdlettergevoelig. Als hoofdlettergevoeligheid gewenst is, kunt u -CaseSensitive
gebruiken. Dit kan worden gebruikt in combinatie met de andere switchparameters.
-Jokerteken
We kunnen ondersteuning voor jokertekens inschakelen met de -Wildcard
-switch. Hierbij wordt dezelfde wildcardlogica als de -like
-operator gebruikt om elke match uit te voeren.
$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 verwerken we een bericht en voeren het vervolgens uit op verschillende streams op basis van de inhoud.
-Regex
De switch-instructie ondersteunt regex-matchen, net zoals het wildcards doet.
switch -Regex ( $message )
{
'^Error'
{
Write-Error -Message $Message
}
'^Warning'
{
Write-Warning -Message $Message
}
default
{
Write-Information $message
}
}
Ik heb meer voorbeelden van het gebruik van regex in een ander artikel dat ik schreef: De vele manieren om regex te gebruiken.
-Bestand
Een weinig bekende functie van de switch-instructie is dat het een bestand kan verwerken met de parameter -File
. U gebruikt -File
met een pad naar een bestand in plaats van een variabele expressie te geven.
switch -Wildcard -File $path
{
'Error*'
{
Write-Error -Message $PSItem
}
'Warning*'
{
Write-Warning -Message $PSItem
}
default
{
Write-Output $PSItem
}
}
Het werkt net als bij het verwerken van een array. In dit voorbeeld combineer ik het met wildcards en maak ik gebruik van de $PSItem
. Hiermee wordt een logboekbestand verwerkt en geconverteerd naar waarschuwings- en foutberichten, afhankelijk van de regex-overeenkomsten.
Geavanceerde details
Nu u zich bewust bent van al deze gedocumenteerde functies, kunnen we deze gebruiken in de context van geavanceerdere verwerking.
Uitdrukkingen
De switch
kan zich in een expressie bevinden in plaats van een variabele.
switch ( ( Get-Service | where Status -EQ 'running' ).Name ) {...}
Wat de expressie oplevert, is de waarde die wordt gebruikt voor de vergelijking.
Meerdere overeenkomsten
Mogelijk hebt u dit al opgemerkt, maar een switch
kan overeenkomen met meerdere voorwaarden. Dit geldt met name bij het gebruik van -Wildcard
of -Regex
matches. U kunt dezelfde voorwaarde meerdere keren toevoegen en alles wordt geactiveerd.
switch ( 'Word' )
{
'word' { 'lower case word match' }
'Word' { 'mixed case word match' }
'WORD' { 'upper case word match' }
}
lower case word match
mixed case word match
upper case word match
Alle drie deze verklaringen worden verworpen. Dit laat zien dat elke voorwaarde wordt gecontroleerd (in volgorde). Dit geldt voor het verwerken van matrices waarbij elk item elke voorwaarde controleert.
Doorgaan
Normaal gesproken zou ik de break
-verklaring introduceren, maar het is beter dat we leren hoe we eerst continue
gebruiken. Net als bij een foreach
lus gaat continue
door naar het volgende item in de verzameling of sluit u de switch
af als er geen items meer zijn. We kunnen dat laatste voorbeeld opnieuw schrijven met continue instructies, zodat slechts één instructie wordt uitgevoerd.
switch ( 'Word' )
{
'word'
{
'lower case word match'
continue
}
'Word'
{
'mixed case word match'
continue
}
'WORD'
{
'upper case word match'
continue
}
}
lower case word match
In plaats van alle drie de items overeen te laten komen, wordt het eerste item overeen laten komen en gaat de schakelaar verder naar de volgende waarde. Omdat er geen waarden meer te verwerken zijn, wordt de switch afgesloten. In dit volgende voorbeeld ziet u hoe een jokerteken kan overeenkomen met meerdere items.
switch -Wildcard -File $path
{
'*Error*'
{
Write-Error -Message $PSItem
continue
}
'*Warning*'
{
Write-Warning -Message $PSItem
continue
}
default
{
Write-Output $PSItem
}
}
Omdat een regel in het invoerbestand zowel het woord Error
als Warning
kan bevatten, willen we alleen de eerste regel uitvoeren en vervolgens doorgaan met het verwerken van het bestand.
Pauze
Met een break
-instructie wordt de schakeloptie afgesloten. Dit is hetzelfde gedrag dat continue
presenteert voor enkele waarden. Het verschil wordt weergegeven bij het verwerken van een reeks.
break
stopt alle verwerking in de switch en continue
naar het volgende item gaat.
$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 update
WARNING: Ran into errors downloading file
Write-Error -Message $PSItem : Error: out of disk space
+ CategoryInfo : NotSpecified: (:) [Write-Error], WriteErrorException
+ FullyQualifiedErrorId : Microsoft.PowerShell.Commands.WriteErrorException
In dit geval, als we een regel tegenkomen die begint met Error
, dan krijgen we een foutmelding en stopt de schakelaar.
Dit is wat die break
-verklaring voor ons doet. Als we Error
in de tekenreeks vinden en niet alleen aan het begin, schrijven we deze als waarschuwing. We doen hetzelfde voor Warning
. Het is mogelijk dat een regel zowel het woord Error
als Warning
heeft, maar we hoeven er maar één te verwerken. Dit is wat de continue
verklaring voor ons doet.
Labels verbreken
De instructie switch
ondersteunt labels break/continue
, net zoals 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
}
}
}
Ik hou persoonlijk niet van het gebruik van breaklabels, maar ik wilde ze aanwijzen omdat ze verwarrend zijn als je ze nog nooit eerder hebt gezien. Wanneer u meerdere switch
- of foreach
-instructies hebt die zijn genest, wilt u mogelijk meer dan het binnenste item uitsplitsen. U kunt een label plaatsen op een switch
die het doel van uw break
kan zijn.
Enumeratie
PowerShell 5.0 gaf ons opsommingen en we kunnen ze in een switch gebruiken.
enum Context {
Component
Role
Location
}
$item = [Context]::Role
switch ( $item )
{
Component
{
'is a component'
}
Role
{
'is a role'
}
Location
{
'is a location'
}
}
is a role
Als u alles wilt behouden als sterk getypte opsommingen, kunt u ze tussen haakjes plaatsen.
switch ($item )
{
([Context]::Component)
{
'is a component'
}
([Context]::Role)
{
'is a role'
}
([Context]::Location)
{
'is a location'
}
}
Haakjes zijn hier nodig, zodat de switch de waarde [Context]::Location
niet als een letterlijke tekenreeks behandelt.
ScriptBlock
We kunnen indien nodig een scriptblok gebruiken om de evaluatie voor een overeenkomst uit te voeren.
$age = 37
switch ( $age )
{
{$PSItem -le 18}
{
'child'
}
{$PSItem -gt 18}
{
'adult'
}
}
'adult'
Dit voegt complexiteit toe en kan uw switch
moeilijk te lezen maken. In de meeste gevallen waarin u zoiets zou gebruiken, is het beter om if
en elseif
verklaringen te gebruiken. Ik zou dit overwegen als ik al een grote switch had en ik twee items nodig had om hetzelfde evaluatieblok te bereiken.
Een ding dat volgens mij helpt bij de leesbaarheid, is door het scriptblok tussen haakjes te plaatsen.
switch ( $age )
{
({$PSItem -le 18})
{
'child'
}
({$PSItem -gt 18})
{
'adult'
}
}
Het wordt nog steeds op dezelfde manier uitgevoerd en biedt een betere visuele onderbreking wanneer u er snel naar kijkt.
Regex $Matches
We moeten regex opnieuw bezoeken om iets aan te raken dat niet meteen duidelijk is. Het gebruik van regex vult de variabele $Matches
. Ik ga meer in op het gebruik van $Matches
als ik het heb over De vele manieren om regexte gebruiken. Hier volgt een snel voorbeeld om deze in actie te laten zien met benoemde overeenkomsten.
$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-3456
WARNING: message may contain a credit card number: 1234-5678-1234-5678
$null
U kunt een $null
-waarde gebruiken die niet de standaard hoeft te zijn.
$values = '', 5, $null
switch ( $values )
{
$null { "Value '$_' is `$null" }
{ '' -eq $_ } { "Value '$_' is an empty string" }
default { "Value [$_] isn't an empty string or `$null" }
}
Value '' is an empty string
Value [5] isn't an empty string or $null
Value '' is $null
Bij het testen van een lege tekenreeks in een switch
-instructie is het belangrijk om, in plaats van de onbewerkte waarde ''
, de vergelijkingsinstructie te gebruiken, zoals in dit voorbeeld wordt getoond. In een switch
verklaring komt de ruwe waarde ''
ook overeen met $null
. Voorbeeld:
$values = '', 5, $null
switch ( $values )
{
$null { "Value '$_' is `$null" }
'' { "Value '$_' is an empty string" }
default { "Value [$_] isn't an empty string or `$null" }
}
Value '' is an empty string
Value [5] isn't an empty string or $null
Value '' is $null
Value '' is an empty string
Wees ook voorzichtig met lege retourwaarden van cmdlets. Cmdlets of pijplijnen die geen uitvoer hebben, worden behandeld als een lege matrix die niet overeenkomt met iets, inclusief het default
geval.
$file = Get-ChildItem NonExistantFile*
switch ( $file )
{
$null { '$file is $null' }
default { "`$file is type $($file.GetType().Name)" }
}
# No matches
Constante expressie
Lee Dailey wees erop dat we een constante $true
expressie kunnen gebruiken om [bool]
items te evalueren.
Stel dat we verschillende Booleaanse controles hebben die moeten plaatsvinden.
$isVisible = $false
$isEnabled = $true
$isSecure = $true
switch ( $true )
{
$isEnabled
{
'Do-Action'
}
$isVisible
{
'Show-Animation'
}
$isSecure
{
'Enable-AdminMenu'
}
}
Do-Action
Enabled-AdminMenu
Dit is een schone manier om de status van verschillende Booleaanse velden te evalueren en actie te ondernemen. Het leuke hiervan is dat u een voorwaarde kunt hebben om de status van een waarde om te draaien die nog niet geëvalueerd is.
$isVisible = $false
$isEnabled = $true
$isAdmin = $false
switch ( $true )
{
$isEnabled
{
'Do-Action'
$isVisible = $true
}
$isVisible
{
'Show-Animation'
}
$isAdmin
{
'Enable-AdminMenu'
}
}
Do-Action
Show-Animation
Als u $isEnabled
instelt op $true
in dit voorbeeld, zorgt u ervoor dat $isVisible
ook is ingesteld op $true
.
Wanneer $isVisible
vervolgens wordt geëvalueerd, wordt het scriptblok aangeroepen. Dit is een beetje contra-intuïtief, maar is een slim gebruik van de mechanica.
automatische variabele $switch
Wanneer de switch
de waarden verwerkt, wordt er een enumerator gemaakt en wordt deze $switch
aanroepen. Dit is een automatische variabele die is gemaakt door PowerShell en u kunt deze rechtstreeks bewerken.
$a = 1, 2, 3, 4
switch($a) {
1 { [void]$switch.MoveNext(); $switch.Current }
3 { [void]$switch.MoveNext(); $switch.Current }
}
Dit geeft u de resultaten van:
2
4
Door de enumerator naar voren te verplaatsen, wordt het volgende item niet verwerkt door de switch
, maar hebt u rechtstreeks toegang tot die waarde. Ik zou het gek noemen.
Andere patronen
Hashtabellen
Een van mijn populairste berichten is het bericht dat ik heb gemaakt over hashtables. Een van de use cases voor een hashtable
is een opzoektabel. Dat is een alternatieve benadering van een veelvoorkomend patroon dat vaak door een switch
-verklaring wordt behandeld.
$day = 3
$lookup = @{
0 = 'Sunday'
1 = 'Monday'
2 = 'Tuesday'
3 = 'Wednesday'
4 = 'Thursday'
5 = 'Friday'
6 = 'Saturday'
}
$lookup[$day]
Wednesday
Als ik alleen een switch
voor het opzoeken gebruik, gebruik ik vaak een hashtable
in plaats daarvan.
Enumeratie
PowerShell 5.0 heeft de enum
geïntroduceerd en het is ook een optie in dit geval.
$day = 3
enum DayOfTheWeek {
Sunday
Monday
Tuesday
Wednesday
Thursday
Friday
Saturday
}
[DayOfTheWeek]$day
Wednesday
We kunnen de hele dag op verschillende manieren gaan kijken om dit probleem op te lossen. Ik wilde er alleen voor zorgen dat je wist dat je opties had.
Laatste woorden
De switch-instructie is oppervlakkig eenvoudig, maar biedt enkele geavanceerde functies waarvan de meeste mensen zich niet realiseren dat ze beschikbaar zijn. Wanneer deze functies worden samengevoegd, maakt dit een krachtige functie. Ik hoop dat je iets hebt geleerd dat je nog niet eerder had gerealiseerd.