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 hodnota odpovídá proměnné, provede se její blok příkazu.
$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 $resultsprá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 [switch] parametrů, 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 [switch] parametry.
-Zástupný znak
U parametru můžeme povolit podporu zástupných -Wildcard[switch] 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 Warningslovo , 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í $true položek můžeme použít konstantní [bool] 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.
Jakmile se $isVisible vyhodnotí, dojde k vyvolání bloku příkazů. 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.