Как работать с Powershell Switch на примерах


05 октября 2019


Примеры работы с Powershell Switch

Powershell Switch - это одна из особенностей, которое отличает язык команд от других. Самое первое условие, с которым мы начинаем работу в любых языках это IF. Его конструкция следующая:

If (Get-Item $way)
{
 Get-Content $way
}

Чаще нам нужно использовать сразу несколько условий прибегая к конструкциям elseif и else:

$day = (Get-Date).DayOfWeek
$day
if ($day -eq 'Sunday'){$result = 'Воскресенье'}
elseif ($day -eq 'Monday'){$result = 'Понедельник'}
elseif ($day -eq 'Tuesday'){$result = 'Вторник'}
elseif ($day -eq 'Wednesday'){$result = 'Среда'}
elseif ($day -eq 'Thursday'){$result = 'Четверг'}
elseif ($day -eq 'Friday'){$result = 'Пятница'}
elseif ($day -eq 'Saturday'){$result = 'Суббота'}
else {$result = 'Неизвестно'}
$result

Powershell IF

Такой подход очень частый в использовании и один из способов решения это использование switch.

Оператор Switch

В отличие от IF оператор Switch позволяет указывать переменную со значением единожды. Так будет выглядеть прошлый пример в варианте со Switch:

$day = (Get-Date).DayOfWeek
switch ($day)
{
'Sunday' {$rus_date = 'Воскресенье'}
'Monday'{$rus_date = 'Понедельник'}
'Tuesday' {$rus_date = 'Вторник'}
'Wednesday' {$rus_date = 'Среда'}
'Thursday' {$rus_date = 'Четверг'}
'Friday' {$rus_date = 'Пятница'}
'Saturday' {$rus_date = 'Суббота'}
}
$rus_date

powershell switch

Мы передали переменную $day единожды и нам не нужно каждый раз выполнять сравнение. После успешного сравнения переменная $rus_date примет указанное значение.

В случаях со сравнением не обязательно указывать кавычки, но рекомендуется так как в случае использования символов типа проблема мы получим ошибки.

 

Присвоение переменной

Предыдущий вариант можно еще больше сократить присвоив Switch в переменную:

$day = (Get-Date).DayOfWeek
$var = switch ($day)
{
'Sunday' {'Воскресенье'}
'Monday'{'Понедельник'}
'Tuesday' {'Вторник'}
'Wednesday' {'Среда'}
'Thursday' {'Четверг'}
'Friday' {'Пятница'}
'Saturday' {'Суббота'}
}
$var

powershell switch

По сути мы помещаем в переменную $var первый результат вернувший из конвейера True. Кроме строковых значений мы можем хранить и численные.

 

Default

Значение Default - это как else, который будет присвоен если ни одно значение не совпадет:

$month = (Get-Date).Month
$month_rus = switch ($month)
{
1 {'Январь'}
2 {'Февраль'}
3 {'Март'}
default {'Месяц не перечислен'}
}
$month_rus

powershell switch default

 

Использование массивов

Мы можем использовать Switch с массивами. Будет проверено каждое значение, которое в нем находится. Пример ниже сработает только на ОС с русской локализацией иначе примется значение default:

$modules = (Get-Module).Name
$modules.GetType()
$modules_installed = switch($modules) {
'Dism' {'Управление дисками'}
'Microsoft.PowerShell.Management' {'Модуль для обслуживания систем'}
'Microsoft.PowerShell.Security' {'Модуль безопасности'}
default {'Такой модуль не указан'}
}
$modules_installed

powershell switch с массивом

После выполнения команды $modules_installed так же будет массивом вне зависимости от того сколько значений у нас было. Если у нас много одинаковых значений, то все они будут проверены.

 

Использование встроенных параметров

Мы можем использовать дополнительные параметры при использовании switch.

-Wildcard

Параметр Wildcard позволяет использовать маски. Для примера мы хотим найти слово 'параллелепипед' в какой-то длинной строке (тексте) и мы можем использовать четыре способа:

  1. *параллелепипед* - говорит о том, что мы может быть текст слева и справа.
  2. параллелепипед* - значит, что текст начинается с этого слова, но после него идет какой-то текст.
  3. *параллелепипед - текст заканчивается на это слово, но слева от него может быть текст.
  4. *пара*елепипед* - в этом случае подразумеваеться что есть текст до "пара", затем какое-то количество символов до "елепипед" и после него текст.

Если знаки * не указаны, то будет искаться точные соответствия:

$string = 'Как использовать swich в Powershell и не допустить ошибку'
$search = switch -Wildcard ($string){
'*Powershell*' {'Тут идет речь про Powershell'}
'*Ошибку' {'Тут так же идет речь про ошибки, регистр не важен'}
'Как*' {'Это слово ищется только в начале строки'}
'*Испо*ь*' {'Пропуск букв'}
'использовать' {'Это не найдется, так как не указан знак *'}}
$string

powershell switch с маски

Такой вариант сработает и с массивами:

$array = 'Текст один', 'два'
$search = switch -Wildcard ($array){
'*оди*' {'Это текст один'}
'два' {'Точное соответствие'}}
$search

powershell switch с маски

-regex

Так же как макси мы можем использовать регулярные выражения, но знак * в регулярных выражениях и масках работает по-разному. На примере ниже ищется IP адрес в массиве:

$regular_mask_ip = "(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)"
$vals = 'smt','192.168.3.1','255.255.255.0','another var'
$find_ip = switch -regex ($vals){
$regular_mask_ip {'Похоже на IP: ' + $PSItem}
default {'Это не IP: '+ $PSItem}
}

powershell switch регулярные выражения

Вы можете заметить, что мы можем передавать значение в виде переменных. $PSItem - это текущее значение, которое выполняется при сравнении. Чаще эту переменную указывают как "$_" .

-File

Отдельно и вместе с параметром маски и регулярных значений мы можем указывать и путь к файлу:

$path = 'C:\Windows\System32\drivers\etc\hosts'
$sw = switch -Wildcard -File $path {
"*localhost*" {'localhost прописан'}
"*127.0.0.1*" {'127.0.0.1 тоже прописан '}
}
$sw

powershell switch file

-casesensitive

Casesensitive добавляет учет регистра при анализе:

$word = 'Text'
$sw = switch -CaseSensitive ($word){
"text" {'Не будет учтен, так как пишется с маленькой буквы'}
"texT" {'Буквы отличаются'}
"Text" {'Полное совпадение'}
}
$sw

powershell switch case

 

Дополнительные возможности

В этой главе рассмотрим дополнительные возможности применения в скриптах.

Выражения

Вместе значения, которое мы передаем в switch, можно использовать командлет. Для примера так я найду отключенных пользователей не объявляя отдельную переменную:

$users = switch ((Get-LocalUser | where -Property Enabled -eq $False).Name){
'Гость' {"Пользователь $PSItem выключен"}
'Guest' {"Пользователь $PSItem выключен"}
'Администратор' {"Пользователь $PSItem выключен"}
'Administrator' {"Пользователь $PSItem выключен"}
}

powershell switch выражения

Обратите внимание, что переменные включаются в строки при двойных кавычках.

Поиск дополнительных вхождений

Если условия поиска совпадут, то это не значит что совпадения не будут искаться дальше. Это имеет весомое значение, когда мы используем регулярные выражения:

$val = '192.168.1.1'
switch -Wildcard ($val){
'*.*' {'Тут сработало'}
'*1*' {'И тут сработало'}
'*2*' {'И тут'}}

powershell switch вхождения

О том как избежать возможных проблем будет рассмотрено дальше.

Continue

Когда нам нужно найти все совпадающие значение, но единожды, нужно использовать Continue. Результат работы хорошо виден с массивами:

$val = '1','2','3'
switch($val){
'1' {'Это значение больше не будет проверяться' 
     continue}
'1' {'Этого текста не будет' 
     continue}
'2' {'Первый раз 2'}
'2' {'Второй раз 2'}
}

powershell switch continue

На примере 2 видно, что она проверяется каждый раз, так как в ней не указан Continue. Такой же подход будет работать и при регулярных выражениях.

В этом сценарии 6 будет проверена дважды, так как предыдущее выражение используется раньше и не использует Continue:

$val = '6','5'
switch($val){
'6' {'Первый' 
     }
'6' {'Второй' 
     continue}
}

Break

В отличие от Continue при использовании Break выполнения сравнение прервется на 1 не проверяя дальнейшие значения:

$val = '1','2','3'
switch($val){
'1' {'Это значение больше не будет проверяться' 
     break}
'1' {'Этого текста не будет' 
     }
'2' {'Первый раз 2'}
'2' {'Второй раз 2'}
}

powershell switch break 

Так же как и в Continue чем ниже оно находится, тем больше сравнений будет выполнено:

$for_break = 'Inet1','Inet2','Inet3','Inet4'
switch($for_break){
'Inet1' {'Продолжение 1'}
'Inet2' {'Продолжение 2'
continue}
'Inet3' {'Остановка выполнения'
break}
'Inet4' {'Не будет использоваться'}
}

Дополнительные условия

Вместо значений с которыми мы сравниваем можно использовать дополнительные условия:

$kopilka = 3000
switch($kopilka){
	{$PSItem -eq 3000}
		{'Кушай доширак'
		continue}
	{$PSItem -le 6000}
		{'Можно купить сосиски'
		continue}
	{$PSItem -le 9000}
		{'Возьму в кредит iPhone'
		continue}
default {'Моя копилка давно сломана'}
}

powershell switch дополнительные условия

Можно добавить более интересные условия, но такой подход затруднит чтение кода. Скрипт ниже проверяет могут ли указанные пользователи менять пароль:

$case = 'Гость','Guest','Администратор','Administrator'
switch($case){
	{(Get-LocalUser -Name $PSItem).UserMayChangePassword -eq $False}
		{"Пользователь $PSItem не может менять пароль"
		continue}
	{(Get-LocalUser -Name $PSItem).UserMayChangePassword -eq $True}
		{"Пользователь $PSItem может менять пароль"
		continue}
	default {"Пользователя $PSItem нет в базе"}
}

powershell switch дополнительные условия

Использование переменной $matches

Когда мы использовали регулярные выражения в массиве, мы выводили значение массива. Когда нам нужно вывести значение найденное через регулярное выражение нужно использовать $matches:

$case = 'Text 1234 text'
switch -regex ($case){
'(?<num>\d\d\d\d)' {"В тексте такие цифры $($matches.num)"}
}

powershell switch $matches

$null

С помощь switch удобно проверять на пустые значения:

$str = @($null,'',' ','Значения')
switch ($str){
$null {continue}
' ' {continue}
'' {continue}
'Значения' {'Работает'}
}

Можно обернуть в функцию и обращаться к ней для проверки:

function Check-Null($var){
    $result = switch ($var){
        $null {$false
            continue}
        ' ' {$false 
            continue}
        '' {$false 
            continue}
        default { $true
            continue}
         }
    $result
    return $result
}

Check-Null
Check-Null 'sss'

powershell switch $null

Вложенная проверка

Мы можем делать вложенную проверку, которая выполнит другие условия если первое является истиной. На примере ниже условия выполнятся если каждое из условий True:

# Объявляем имя пользователя
$user_name = 'Administrator'
# Получаем данные с AD
$user_data = Get-ADUser -Identity $user_name -Properties * | select *
# Узнаем устарел ли пароль (True или False)
$user_pass_exp = $user.PasswordExpired
# Заблокирован ли пользователь (True или False)
$user_locked = $user.LockedOut
# Если пользователь найден, то switch работает
$result = switch($user_data){
	# Если пользователь заблокирован, он разблокируется
	$user_locked {Unlock-ADAccount -identity $user_name}
	# Если пароль устаревший, то пароль будет запрошен для смены.
	$user_pass_exp {$password = Read-Host "Enter new password" -AsSecureString
				Set-ADAccountPassword -Identity $user_name -NewPassword $password}
}

О том как получать данные пользователей из AD в Powershell вы можете почитать в предыдущих статьях.

...

Теги: #powershell


Популярные тэги
Каналы
О блоге
Этот блог представляет собой конспекты выученного материала, преобретенного опыта и лучшие практики в системном администрировании и программировании.