Poznámka
Přístup k této stránce vyžaduje autorizaci. Můžete se zkusit přihlásit nebo změnit adresáře.
Přístup k této stránce vyžaduje autorizaci. Můžete zkusit změnit adresáře.
Stejně jako mnoho dalších jazyků má PowerShell příkazy pro řízení toku provádění ve vašich skriptech. Jedním z těchto příkazů je příkaz switch a v PowerShellu nabízí funkce, které nejsou nalezeny v jiných jazycích. Dnes se podrobně podíváme na práci s PowerShellem switch
.
Poznámka:
původní verze tohoto článku se objevila na blogu napsaného @KevinMarquette. Tým PowerShellu děkujeme Kevinovi za sdílení tohoto obsahu s námi. Prosím, podívejte se na jeho blog na PowerShellExplained.com.
Příkaz if
Jedním z prvních příkazů, které se naučíte, je if
příkaz. Umožňuje spustit blok skriptu, pokud je podmínka $true
splněna.
if ( Test-Path $Path )
{
Remove-Item $Path
}
Můžete mít mnohem složitější logiku pomocí příkazů elseif
a else
. Tady je příklad, kde mám číselnou hodnotu pro den v týdnu a chci získat název jako řetězec.
$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
Ukázalo se, že se jedná o běžný vzor a existuje mnoho způsobů, jak to vyřešit. Jeden z nich je s switch
.
příkaz switch
Příkaz switch
umožňuje zadat proměnnou a seznam možných hodnot. Pokud se hodnota shoduje s proměnnou, spustí se její skriptblock.
$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'
V tomto příkladu je hodnota $day
shodná s jednou z číselných hodnot a pak je přiřazen $result
správný název . V tomto příkladu provádíme pouze přiřazení proměnné, ale v těchto blocích skriptu se dá spustit libovolný PowerShell.
Přiřaďte k proměnné
Tento poslední příklad můžeme napsat jiným způsobem.
$result = switch ( $day )
{
0 { 'Sunday' }
1 { 'Monday' }
2 { 'Tuesday' }
3 { 'Wednesday' }
4 { 'Thursday' }
5 { 'Friday' }
6 { 'Saturday' }
}
Hodnotu umístíme do kanálu PowerShellu a přiřadíme ji k sadě $result
. To samé můžete udělat s příkazy if
a foreach
.
Výchozí
Klíčové slovo můžeme použít default
k identifikaci toho, co by se mělo stát, pokud neexistuje shoda.
$result = switch ( $day )
{
0 { 'Sunday' }
# ...
6 { 'Saturday' }
default { 'Unknown' }
}
Tady vrátíme hodnotu Unknown
ve výchozím případě.
Řetězce
V posledních příkladech jsem shodovala čísla, ale můžete také shodovat řetězce.
$item = 'Role'
switch ( $item )
{
Component
{
'is a component'
}
Role
{
'is a role'
}
Location
{
'is a location'
}
}
is a role
Rozhodl jsem se nezabalit shody Component
, Role
a Location
do uvozovek, abych zdůraznil, že jsou volitelné. Ve většině případů s nimi switch
zachází jako s řetězcem.
Pole
Jednou ze skvělých funkcí PowerShellu switch
je způsob, jakým zpracovává pole. Pokud dáte switch
pole, zpracuje každý prvek v této kolekci.
$roles = @('WEB','Database')
switch ( $roles ) {
'Database' { 'Configure SQL' }
'WEB' { 'Configure IIS' }
'FileServer' { 'Configure Share' }
}
Configure IIS
Configure SQL
Pokud máte v poli opakující se položky, pak odpovídají příslušnému oddílu vícekrát.
PsItem
Můžete použít $PSItem
nebo $_
odkazovat na aktuální položku, která byla zpracována. Když provedeme jednoduchou shodu, $PSItem
je hodnota, kterou porovnáváme. Budu provádět několik pokročilých shod v další části, kde se tato proměnná používá.
Parametry
Jedinečnou funkcí PowerShellu switch
je, že má řadu parametrů přepínače, které mění jeho výkon.
- Rozlišuje velká a malá písmena
Ve výchozím nastavení se shody nerozlišují malá a velká písmena. Pokud potřebujete rozlišovat malá a velká písmena, můžete použít -CaseSensitive
. To lze použít v kombinaci s ostatními parametry přepínače.
-Zástupný znak
Pomocí přepínače -Wildcard
můžeme povolit podporu zástupných znaků. Používá se stejná logika zástupných znaků, jakou používá operátor -like
pro každou shodu.
$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
Tady zpracováváme zprávu a pak ji vypíšeme do různých datových proudů na základě obsahu.
-Regex
Příkaz switch podporuje shody regulárních výrazů stejně jako zástupné znaky.
switch -Regex ( $message )
{
'^Error'
{
Write-Error -Message $Message
}
'^Warning'
{
Write-Warning -Message $Message
}
default
{
Write-Information $message
}
}
Mám více příkladů použití regex v jiném článku jsem napsal: mnoho způsobů použití regex.
-Soubor
Trochu známou funkcí příkazu switch je, že může zpracovat soubor s parametrem -File
. Místo toho, abyste mu dali proměnnou výraz, použijete -File
cestu k souboru.
switch -Wildcard -File $path
{
'Error*'
{
Write-Error -Message $PSItem
}
'Warning*'
{
Write-Warning -Message $PSItem
}
default
{
Write-Output $PSItem
}
}
Funguje stejně jako zpracování pole. V tomto příkladu jej zkombinuji se zástupným znakem a použijem $PSItem
. Tento postup zpracuje soubor protokolu a převede ho na upozornění a chybové zprávy v závislosti na shodě regulárních výrazů.
Pokročilé údaje
Teď, když víte o všech těchto dokumentovaných funkcích, je můžeme použít v kontextu pokročilejšího zpracování.
Výrazy
Může switch
být ve výrazu místo proměnné.
switch ( ( Get-Service | where Status -EQ 'running' ).Name ) {...}
Cokoli, k čemu se výraz vyhodnotí, je hodnota použitá pro shodu.
Více shod
Možná jste si toho už postřehli, ale switch
se může shodovat s několika podmínkami. To platí zejména při použití shod -Wildcard
nebo -Regex
. Stejnou podmínku můžete přidat vícekrát a všechny se aktivují.
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
Všechny tři tyto příkazy jsou ukončeny. To ukazuje, že každá podmínka je zkontrolována (v pořadí). To platí pro zpracování polí, kde každá položka kontroluje každou podmínku.
Pokračovat
Za normálních okolností je to místo, kde bych představil break
prohlášení, ale je lepší, abychom se naučili, jak použít continue
jako první. Stejně jako u foreach
smyčky continue
pokračuje na další položku v kolekci nebo ukončí switch
, pokud už žádné další položky nejsou. Poslední příklad můžeme přepsat pomocí příkazů continue tak, aby se provedl pouze jeden příkaz.
switch ( 'Word' )
{
'word'
{
'lower case word match'
continue
}
'Word'
{
'mixed case word match'
continue
}
'WORD'
{
'upper case word match'
continue
}
}
lower case word match
Místo párování všech tří položek se první položka porovná a přepínač pokračuje k další hodnotě. Protože nejsou žádné hodnoty ke zpracování, přepínač skončí. Tento další příklad ukazuje, jak může zástupný znak odpovídat více položkám.
switch -Wildcard -File $path
{
'*Error*'
{
Write-Error -Message $PSItem
continue
}
'*Warning*'
{
Write-Warning -Message $PSItem
continue
}
default
{
Write-Output $PSItem
}
}
Vzhledem k tomu, že řádek ve vstupním souboru může obsahovat slovo Error
i Warning
slovo , chceme, aby se spustil pouze první řádek, a pak pokračovat ve zpracování souboru.
Přestávka
Příkaz break
ukončí přepínač. Jedná se o stejné chování, které continue
představuje pro jednotlivé hodnoty. Rozdíl se zobrazí při zpracování pole.
break
zastaví veškeré zpracování v přepínači a continue
přesune se na další položku.
$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
Pokud v tomto případě narazíme na nějaké řádky, které začínají Error
, zobrazí se chyba a přepínač se zastaví.
Toto je to, co pro nás dělá ono tvrzení break
. Pokud v řetězci najdeme Error
nejen na začátku, napíšeme ho jako upozornění. Děláme to samé pro Warning
. Je možné, že řádek může obsahovat slovo Error
i Warning
, ale potřebujeme pouze jedno ke zpracování. Toto pro nás dělá continue
prohlášení.
Štítky přerušení
Příkaz switch
podporuje break/continue
popisky stejně jako 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
}
}
}
Osobně se mi nelíbí použití štítků přerušení, ale chtěl jsem na ně upozornit, protože mohou být matoucí, pokud jste se s nimi nikdy nesetkali. Pokud máte více switch
příkazů nebo foreach
příkazů, které jsou vnořené, můžete chtít vystoupit z více než jen z vnitřní položky. Můžete umístit popisek na switch
, který může být cílem vašeho break
.
Enum
PowerShell 5.0 nám poskytl výčty a můžeme je použít v přepínači.
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
Pokud chcete zachovat vše jako výčty silného typu, můžete je umístit do závorek.
switch ($item )
{
([Context]::Component)
{
'is a component'
}
([Context]::Role)
{
'is a role'
}
([Context]::Location)
{
'is a location'
}
}
Tady jsou potřeba závorky, aby přepínač nezacházal s hodnotou [Context]::Location
jako s literálovým řetězcem.
ScriptBlock
K vyhodnocení shody můžeme v případě potřeby použít skriptový blok.
$age = 37
switch ( $age )
{
{$PSItem -le 18}
{
'child'
}
{$PSItem -gt 18}
{
'adult'
}
}
'adult'
To zvyšuje složitost a může ztížit čtení switch
. Ve většině případů, kdy byste použili něco podobného, by bylo lepší použít if
a elseif
příkazy. Uvažoval bych o použití tohoto, pokud bych již měl velký přepínač a potřeboval jsem, aby se dvě položky dostaly do stejného hodnotícího bloku.
Jedna věc, která podle mě pomáhá s čitelností, je umístit blok skriptu do závorek.
switch ( $age )
{
({$PSItem -le 18})
{
'child'
}
({$PSItem -gt 18})
{
'adult'
}
}
Stále se provádí stejným způsobem a dává lepší vizuální přestávku, když se na ni rychle podíváte.
$Matches regulárních výrazů
Musíme se vrátit k regulárním výrazům, abychom se mohli dotknout něčeho, co není okamžitě zřejmé. Použití regexu plní proměnnou $Matches
. Podrobněji se zabývám používáním $Matches
, když mluvím o mnoha způsobech použití regulárních výrazů. Tady je rychlá ukázka, která ji zobrazí v akci s pojmenovanými shodami.
$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
Můžete se shodovat s $null
hodnotou, která nemusí být výchozí.
$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
Při testování prázdného řetězce v switch
příkazu je důležité použít příkaz porovnání, jak je znázorněno v tomto příkladu místo nezpracované hodnoty ''
. V příkazu se nezpracovaná switch
hodnota ''
také shoduje $null
. Například:
$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
Také buďte opatrní s prázdnými výstupy z cmdletů. Cmdlety nebo kanály, které nemají žádný výstup, se považují za prázdné pole, které neodpovídá ničemu, včetně případu default
.
$file = Get-ChildItem NonExistantFile*
switch ( $file )
{
$null { '$file is $null' }
default { "`$file is type $($file.GetType().Name)" }
}
# No matches
Konstantní výraz
Lee Dailey zdůraznil, že k vyhodnocení [bool]
položek můžeme použít konstantní $true
výraz.
Představte si, že máme několik logických kontrol, ke kterým musí dojít.
$isVisible = $false
$isEnabled = $true
$isSecure = $true
switch ( $true )
{
$isEnabled
{
'Do-Action'
}
$isVisible
{
'Show-Animation'
}
$isSecure
{
'Enable-AdminMenu'
}
}
Do-Action
Enabled-AdminMenu
Toto je elegantní způsob, jak vyhodnotit a jednat ohledně stavu několika logických polí. Skvělé na tom je, že můžete mít jednu operaci, která překlopí stav hodnoty, jež ještě nebyla vyhodnocena.
$isVisible = $false
$isEnabled = $true
$isAdmin = $false
switch ( $true )
{
$isEnabled
{
'Do-Action'
$isVisible = $true
}
$isVisible
{
'Show-Animation'
}
$isAdmin
{
'Enable-AdminMenu'
}
}
Do-Action
Show-Animation
Nastavení $isEnabled
v $true
tomto příkladu zajistí, že $isVisible
je také nastavena na $true
.
Poté, když je $isVisible
vyhodnoceno, pak se vyvolá jeho skriptový blok. To je trochu protiintuitivní, ale je to chytrý způsob použití mechaniky.
$switch automatické proměnné
switch
Při zpracování svých hodnot vytvoří enumerátor a zavolá ho $switch
. Jedná se o automatickou proměnnou vytvořenou prostředím PowerShell a můžete s ní pracovat přímo.
$a = 1, 2, 3, 4
switch($a) {
1 { [void]$switch.MoveNext(); $switch.Current }
3 { [void]$switch.MoveNext(); $switch.Current }
}
Tím získáte výsledky:
2
4
Přesunutím enumerátoru dopředu se další položka nezpracuje pomocí switch
, ale k této hodnotě se můžete dostat přímo. Říkal bych to šílenství.
Jiné vzory
Hashtables
Jedním z mých nejoblíbenějších příspěvků je ten, který jsem udělal na hashtables. Jedním z případů použití hashtable
je vyhledávací tabulka. Jedná se o alternativní přístup k běžnému vzoru, který switch
příkaz často řeší.
$day = 3
$lookup = @{
0 = 'Sunday'
1 = 'Monday'
2 = 'Tuesday'
3 = 'Wednesday'
4 = 'Thursday'
5 = 'Friday'
6 = 'Saturday'
}
$lookup[$day]
Wednesday
Pokud používám switch
pouze pro vyhledávání, často používám místo toho hashtable
.
Enum
PowerShell 5.0 představil enum
a v tomto případě je to také možnost.
$day = 3
enum DayOfTheWeek {
Sunday
Monday
Tuesday
Wednesday
Thursday
Friday
Saturday
}
[DayOfTheWeek]$day
Wednesday
Celý den bychom se mohli podívat na různé způsoby, jak tento problém vyřešit. Jen jsem se chtěl ujistit, že jsi věděl, že máš možnosti.
Konečná slova
Příkaz switch je na povrchu jednoduchý, ale nabízí některé pokročilé funkce, o kterých většina lidí ani netuší, že jsou k dispozici. Propojení těchto funkcí dohromady činí z toho silnou funkci. Doufám, že jste se dozvěděli něco, co jste si předtím neuvědomili.