Примечание
Для доступа к этой странице требуется авторизация. Вы можете попробовать войти или изменить каталоги.
Для доступа к этой странице требуется авторизация. Вы можете попробовать изменить каталоги.
Все, что вы хотели знать об заявлении
Как и многие другие языки, PowerShell имеет инструкции для условного выполнения кода в скриптах. Одним из этих инструкций является оператор If . Сегодня мы рассмотрим одну из самых фундаментальных команд в PowerShell.
Примечание.
Оригинал этой статьи впервые был опубликован в блоге автора @KevinMarquette. Команда PowerShell благодарит Кевина за предоставление этого содержимого нам. Читайте его блог — PowerShellExplained.com.
Условное выполнение
Скрипты часто должны принимать решения и выполнять разные логики на основе этих решений.
Это то, что я имею в виду условное выполнение. Вы можете оценить одну инструкцию или значение, а затем выполнить другой раздел кода на основе этой оценки. Это именно то, что делает оператор if
.
Инструкция if
Ниже приведен базовый пример инструкции if
:
$condition = $true
if ( $condition )
{
Write-Output "The condition was true"
}
Первое, что if
делает оператор, — это оценка выражения в скобках. Если он оценивается $true
, он выполняет scriptblock
фигурные скобки. Если значение было $false
, то он пропустит этот блок скрипта.
В предыдущем примере if
оператор просто оценивает $condition
переменную. Это было $true
бы и было бы выполнено Write-Output
команда внутри скриптблока.
На некоторых языках вы можете разместить одну строку кода после оператора if
, и она будет выполнена. Это не так в PowerShell. Для правильной работы необходимо предоставить полные scriptblock
фигурные скобки.
Операторы сравнения
Наиболее распространенное использование оператора if
— это сравнение двух элементов. PowerShell имеет специальные операторы для различных сценариев сравнения. При использовании оператора сравнения значение в левой части сравнивается со значением справа.
-eq для равенства
Элемент -eq
выполняет проверку равенства между двумя значениями, чтобы убедиться, что они равны друг другу.
$value = Get-MysteryValue
if ( 5 -eq $value )
{
# do something
}
В этом примере я принимаю известное значение 5
и сравниваю его с моим $value
, чтобы узнать, совпадают ли они.
Одним из возможных вариантов использования является проверка состояния значения перед выполнением действия. Вы могли бы получить службу и убедиться, что ее состояние запущено, перед тем как вызывать Restart-Service
.
Это часто используется на других языках, таких как C# ==
для равенства (например: 5 == $value
), но это не работает с PowerShell. Еще одна распространенная ошибка, которую делают люди, — использовать знак равенства (например, 5 = $value
), зарезервированный для назначения значений переменным. Разместив известное значение слева, вы снизите вероятность допустить ошибку.
Этот оператор (и другие) имеет несколько вариантов.
-
-eq
Равенство без учета регистра -
-ieq
Равенство без учета регистра -
-ceq
Равенство с учетом регистра
-ne не равно
Многие операторы имеют соответствующий оператор, который проверяет противоположный результат.
-ne
проверяет, что значения не равны друг другу.
if ( 5 -ne $value )
{
# do something
}
Используйте это, чтобы убедиться, что действие выполняется только в том случае, если значение не равно 5
. Хороший случай использования — проверить, работает ли служба, прежде чем пытаться запустить ее.
Вариации:
-
-ne
Без учета регистра не равно -
-ine
регистронезависимое не равно -
-cne
Учет регистра не равен
Это обратные варианты -eq
. Я сгруппирую эти типы вместе, когда перечислю варианты для других операторов.
-gt -ge -lt -le для больше или меньше
Эти операторы используются при проверке, чтобы узнать, имеет ли значение больше или меньше другого значения.
-gt -ge -lt -le
обозначает Больше, БольшеИлиРавно, Меньше и МеньшеИлиРавно.
if ( $value -gt 5 )
{
# do something
}
Вариации:
-
-gt
Больше -
-igt
больше, чем, без учета регистра -
-cgt
больше, чем, с учетом регистра -
-ge
больше или равно -
-ige
больше или равно, независимо от регистра -
-cge
больше или равно, учитывает регистр -
-lt
Менее -
-ilt
меньше чем, без учета регистра -
-clt
меньше, с учетом регистра -
-le
меньше или равно -
-ile
меньше или равно, без учета регистра -
-cle
меньше или равно, учитывает регистр
Я не понимаю, почему вы использовали бы чувствительные и нечувствительные к регистру параметры для этих операторов.
совпадения, аналогичные подстановочным знакам
PowerShell имеет собственный синтаксис сопоставления шаблонов на основе подстановочных знаков, и его можно использовать с оператором -like
. Эти шаблоны подстановочных знаков являются довольно простыми.
-
?
соответствует любому одному символу -
*
соответствует любому числу символов
$value = 'S-ATX-SQL01'
if ( $value -like 'S-*-SQL??')
{
# do something
}
Важно отметить, что шаблон соответствует всей строке. Если вам нужно сопоставить что-то в середине строки, необходимо поместить *
на обеих концах строки.
$value = 'S-ATX-SQL02'
if ( $value -like '*SQL*')
{
# do something
}
Вариации:
-
-like
Нечувствительный к регистру подстановочный знак -
-ilike
Подстановочный знак без учета регистра -
-clike
Подстановочный знак с учетом регистра -
-notlike
Не соответствует нечувствительной к регистру подстановочной последовательности -
-inotlike
Нечувствительный к регистру подстановочный знак не совпадает -
-cnotlike
Чувствительный к регистру подстановочный знак не был найден
-совпадение регулярным выражением
Оператор -match
позволяет проверить строку на соответствие на основе регулярных выражений. Используйте это, если шаблоны подстановочных знаков недостаточно гибки для вас.
$value = 'S-ATX-SQL01'
if ( $value -match 'S-\w\w\w-SQL\d\d')
{
# do something
}
Шаблон регулярных выражений соответствует в любом месте строки по умолчанию. Таким образом, можно указать подстроку, которую хотите найти, так:
$value = 'S-ATX-SQL01'
if ( $value -match 'SQL')
{
# do something
}
Regex является сложным языком своего собственного и стоит искать. Я рассказываю подробнее о -match
и многих способах использования регулярных выражений в другой статье.
Вариации:
-
-match
нечувствительное к регистру регулярное выражение -
-imatch
регулярное выражение, нечувствительное к регистру -
-cmatch
Regex с учетом регистра -
-notmatch
Регистр не учитывается при сопоставлении регрессии -
-inotmatch
Нечувствительный к регистру регулярное выражение не найдено -
-cnotmatch
Regex с учетом регистра не совпадает
-является типом
Вы можете проверить тип значения оператором -is
.
if ( $value -is [string] )
{
# do something
}
Это можно использовать, если вы работаете с классами или принимаете различные объекты по конвейеру. В качестве входных данных можно использовать службу или имя службы. Затем проверьте наличие службы, и если у вас есть только имя, получите службу.
if ( $Service -isnot [System.ServiceProcess.ServiceController] )
{
$Service = Get-Service -Name $Service
}
Вариации:
-
-is
тип -
-isnot
не является типом
Операторы сбора
При использовании предыдущих операторов с одним значением результатом является $true
или $false
. Процесс обработки немного отличается при работе с коллекцией. Каждый элемент в коллекции вычисляется, и оператор возвращает каждое значение, которое равно $true
.
PS> 1,2,3,4 -eq 3
3
Это по-прежнему работает правильно в инструкции if
. Таким образом, значение возвращается вашим оператором, а вся инструкция равна $true
.
$array = 1..6
if ( $array -gt 3 )
{
# do something
}
Есть одна небольшая ловушка, которая скрывается здесь в деталях, на которую мне нужно указать. При использовании оператора -ne
таким образом, легко ошибочно взглянуть на логику наоборот. Использование -ne
с коллекцией возвращает $true
, если какой-либо элемент в коллекции не соответствует вашему значению.
PS> 1,2,3 -ne 4
1
2
3
Это может выглядеть как умный трюк, но у нас есть операторы -contains
и -in
которые обрабатывают это более эффективно. И -notcontains
делает то, что вы ожидаете.
содержит-
Оператор -contains
проверяет коллекцию на наличие вашего значения. Как только он находит совпадение, он возвращается $true
.
$array = 1..6
if ( $array -contains 3 )
{
# do something
}
Это предпочтительный способ узнать, содержит ли коллекция ваше значение. Использование Where-Object
(или -eq
) проходит весь список каждый раз и значительно медленнее.
Вариации:
-
-contains
Совпадение без учета регистра -
-icontains
Совпадение без учета регистра -
-ccontains
Совпадение с учетом регистра -
-notcontains
Без учета регистра не соответствует -
-inotcontains
Без учета регистра нет совпадения -
-cnotcontains
Чувствительность к регистру не совпадает
-ин
Оператор -in
похож на оператор -contains
, только коллекция находится в правой части.
$array = 1..6
if ( 3 -in $array )
{
# do something
}
Вариации:
-
-in
Совпадение без учета регистра -
-iin
Совпадение без учета регистра -
-cin
Совпадение с учетом регистра -
-notin
Без учета регистра несовпадение -
-inotin
Без учета регистра не соответствует -
-cnotin
Учет регистра не соответствует
Логические операторы
Логические операторы используются для инвертирования или объединения других выражений.
-не
Оператор -not
меняет выражение с $false
на $true
или с $true
на $false
. Вот пример, когда мы хотим выполнить действие, если Test-Path
находится в состоянии $false
.
if ( -not ( Test-Path -Path $path ) )
Большинство операторов, о которых мы говорили, имеют вариант, где не требуется использовать оператор -not
. Но есть еще времена, что это полезно.
! оператор
Вы можете использовать !
в качестве псевдонима для -not
.
if ( -not $value ){}
if ( !$value ){}
Вы можете чаще видеть !
у пользователей из языков программирования вроде C#. Я предпочитаю набирать его, потому что мне трудно его разглядеть, когда я быстро просматриваю свои сценарии.
-и
Выражения можно объединить с оператором -and
. При этом обе стороны должны быть $true
, чтобы всё выражение стало $true
.
if ( ($age -gt 13) -and ($age -lt 55) )
В этом примере $age
должно быть 13 лет или больше для левой стороны и менее 55 для правой стороны. Я добавил дополнительные скобки, чтобы сделать его более понятным в этом примере, но они необязательные, если выражение просто. Вот тот же пример без них.
if ( $age -gt 13 -and $age -lt 55 )
Оценка происходит слева направо. Если первый элемент оценивается $false
, он завершается рано и не выполняет правильное сравнение. Это удобно, если необходимо убедиться, что значение существует перед его использованием. Например, Test-Path
вызывает ошибку, если ему дать путь $null
.
if ( $null -ne $path -and (Test-Path -Path $path) )
-или
Позволяет -or
указать два выражения и возвращать $true
, если один из них имеет значение $true
.
if ( $age -le 13 -or $age -ge 55 )
Как и оператор -and
, оценка выполняется слева направо. За исключением того, что если первая часть является $true
, то весь оператор является $true
и не обрабатывает остальную часть выражения.
Кроме того, обратите внимание на то, как работает синтаксис для этих операторов. Вам потребуется два отдельных выражения. Я видел, как пользователи пытаются сделать что-то подобное $value -eq 5 -or 6
, не осознавая их ошибку.
-xor эксклюзив или
Это немного необычно.
-xor
позволяет вычислять $true
только одно выражение. Таким образом, если оба элемента являются $false
или оба элемента$true
, то целое выражение .$false
Другой способ взглянуть на это состоит в том, что выражение используется только тогда, когда результаты выражения отличаются.
Редко бывает, чтобы кто-нибудь использовал этот логический оператор, и я не могу придумать хороший пример, по которому я бы когда-либо использовал его.
битовые операторы
Побитовые операторы выполняют вычисления битов внутри значений и создают новое значение в качестве результата. Обучение побитовым операторам выходит за рамки этой статьи, но вот их список.
-
-band
двоичная операция AND -
-bor
двоичное ИЛИ -
-bxor
двоичное эксклюзивное ИЛИ -
-bnot
двоичное НЕ -
-shl
сдвиг влево -
-shr
сдвиг вправо
Выражения PowerShell
В условии можно использовать обычный PowerShell.
if ( Test-Path -Path $Path )
Test-Path
возвращает $true
или $false
при выполнении. Это также относится к командам, возвращающим другие значения.
if ( Get-Process Notepad* )
Оценивается в $true
, если есть возвращенный процесс, и в $false
если его нет. Совершенно допустимо использовать выражения конвейера или другие операторы PowerShell, как в этом примере.
if ( Get-Process | where Name -EQ Notepad )
Эти выражения можно сочетать друг с другом с помощью операторов -and
и -or
, но для разбиения на подвыражения может потребоваться использовать скобки.
if ( (Get-Process) -and (Get-Service) )
Проверка $null
Отсутствие результата или значение $null
оценивается как $false
в инструкции if
. При проверке $null
рекомендуется разместить $null
с левой стороны.
if ( $null -eq $value )
Существует несколько нюансов при работе со значениями $null
в PowerShell. Если вы заинтересованы в погружении глубже, у меня есть статья о том, что вы хотели знать о $null.
Назначение переменной в условии
Я почти забыл добавить этот, пока Prasoon Karunan V напомнил мне об этом.
if ($process=Get-Process notepad -ErrorAction Ignore) {$process} else {$false}
Обычно при назначении значения переменной значение не передается в конвейер или консоль. При назначении переменной в подвыражении она передается в конвейер.
PS> $first = 1
PS> ($second = 2)
2
Посмотрите, как назначение $first
не выводит результат, а назначение $second
выводит. Когда задание выполняется в инструкции if
, оно выполняется так же, как и указанное $second
выше назначение. Ниже приведен понятный пример использования:
if ( $process = Get-Process Notepad* )
{
$process | Stop-Process
}
Если $process
присваивается значение, то выполняется оператор $true
, и $process
останавливается.
Убедитесь, что вы не спутаете это с -eq
тем, что это не проверка равенства. Это более скрытая функция, о которой большинство людей не догадывается и которая работает таким образом.
Назначение переменной из скриптового блока
Можно также использовать блок сценария оператора if
для присваивания значения переменной.
$discount = if ( $age -ge 55 )
{
Get-SeniorDiscount
}
elseif ( $age -le 13 )
{
Get-ChildDiscount
}
else
{
0.00
}
Каждый блок скрипта записывает результаты команд или значение в виде выходных данных. Можно присвоить результат инструкции if
переменной $discount
. Этот пример мог бы так же легко присвоить эти значения переменной $discount
непосредственно в каждом блоке скрипта. Я не могу сказать, что я использую это с if
заявлением часто, но у меня есть пример, где я использовал это недавно.
Альтернативный путь выполнения
Оператор if
позволяет указать действие не только в случае, если он выполняется при $true
, но и при $false
. Вот где else
утверждение начинает играть роль.
иначе
Оператор else
всегда является последней частью инструкции if
при использовании.
if ( Test-Path -Path $Path -PathType Leaf )
{
Move-Item -Path $Path -Destination $archivePath
}
else
{
Write-Warning "$path doesn't exist or isn't a file."
}
В этом примере мы проверяем $path
, чтобы убедиться, что это файл. Если мы найдем файл, мы переместим его. В противном случае мы напишем предупреждение. Этот тип логики ветвления очень распространен.
Вложено, если
Операторы if
и else
принимают блок скрипта, поэтому мы можем поместить в них любую команду PowerShell, включая другую инструкцию if
. Это позволяет использовать гораздо более сложную логику.
if ( Test-Path -Path $Path -PathType Leaf )
{
Move-Item -Path $Path -Destination $archivePath
}
else
{
if ( Test-Path -Path $Path )
{
Write-Warning "A file was required but a directory was found instead."
}
else
{
Write-Warning "$path could not be found."
}
}
В этом примере сначала мы тестируем счастливый путь, а затем работаем над ним. Если это не удается, выполните еще одну проверку и укажите более подробную информацию пользователю.
elseif
Мы не ограничены только одной условной проверкой. Мы можем объединить операторы if
и else
вместо их вложения, используя оператор elseif
.
if ( Test-Path -Path $Path -PathType Leaf )
{
Move-Item -Path $Path -Destination $archivePath
}
elseif ( Test-Path -Path $Path )
{
Write-Warning "A file was required but a directory was found instead."
}
else
{
Write-Warning "$path could not be found."
}
Выполнение выполняется сверху внизу. Сначала вычисляется верхняя if
инструкция. Если это $false
, то перемещается вниз к следующему elseif
или else
в списке. Это последнее else
действие выполняется по умолчанию, если ни одно из остальных не приводит к $true
.
выключатель
На этом этапе мне нужно упомянуть о заявлении switch
. Он предоставляет альтернативный синтаксис для выполнения нескольких сравнений со значением.
switch
В этом случае вы указываете выражение и результат сравнивается с несколькими различными значениями. Если одно из этих значений совпадает, выполняется соответствующий блок кода. Ознакомьтесь с этим примером:
$itemType = 'Role'
switch ( $itemType )
{
'Component'
{
'is a component'
}
'Role'
{
'is a role'
}
'Location'
{
'is a location'
}
}
Существует три возможных значения, которые могут соответствовать значению $itemType
. В этом случае он соответствует Role
. Я использовал простой пример, чтобы ознакомить вас с оператором switch
. Я подробнее рассказываю обо всем, что вы когда-либо хотели знать об операторе switch в другой своей статье.
Встроенный массив
У меня есть функция Invoke-SnowSql , которая запускает исполняемый файл с несколькими аргументами командной строки. Ниже приведен клип из этой функции, в которой я создаю массив аргументов.
$snowSqlParam = @(
'--accountname', $Endpoint
'--username', $Credential.UserName
'--option', 'exit_on_error=true'
'--option', 'output_format=csv'
'--option', 'friendly=false'
'--option', 'timing=false'
if ($Debug)
{
'--option', 'log_level=DEBUG'
}
if ($Path)
{
'--filename', $Path
}
else
{
'--query', $singleLineQuery
}
)
$Debug
$Path
Переменные — это параметры функции, предоставляемой конечным пользователем.
Я оцениваю их в процессе инициализации моего массива. Если $Debug
истинно, эти значения попадают в $snowSqlParam
на правильное место. То же самое имеет значение true для переменной $Path
.
Упрощение сложных операций
Это неизбежно, что вы работаете в ситуации, которая имеет слишком много сравнений, чтобы проверить, и ваш if
оператор прокрутит путь от правой стороны экрана.
$user = Get-ADUser -Identity $UserName
if ( $null -ne $user -and $user.Department -eq 'Finance' -and $user.Title -match 'Senior' -and $user.HomeDrive -notlike '\\server\*' )
{
# Do Something
}
Они могут быть трудно читать, и это делает вас более склонными к ошибкам. Мы можем кое-что с этим сделать.
Продолжение строки
В PowerShell есть некоторые операторы, которые позволяют упаковать команду в следующую строку. Логические операторы -and
и -or
являются хорошими для использования, если вы хотите разбить ваше выражение на несколько строк.
if ($null -ne $user -and
$user.Department -eq 'Finance' -and
$user.Title -match 'Senior' -and
$user.HomeDrive -notlike '\\server\*'
)
{
# Do Something
}
Там все еще много происходит, но размещение каждого элемента на своей линии значительно улучшает ситуацию. Обычно я использую это, когда получаю более двух сравнений или если я должен прокручиваться вправо, чтобы прочитать любую логику.
Предварительно вычисляемые результаты
Мы можем вынести это выражение из оператора if
и проверить только результат.
$needsSecureHomeDrive = $null -ne $user -and
$user.Department -eq 'Finance' -and
$user.Title -match 'Senior' -and
$user.HomeDrive -notlike '\\server\*'
if ( $needsSecureHomeDrive )
{
# Do Something
}
Это просто чувствует себя гораздо более чистым, чем предыдущий пример. Вы также можете использовать имя переменной, объясняющее, что именно вы проверяете. Это также и пример самодокументирования кода, который сохраняет ненужные комментарии.
Несколько операторов if
Мы можем разделить это на несколько операторов и проверить их один раз. В этом случае мы используем флаг или переменную отслеживания для объединения результатов.
$skipUser = $false
if( $null -eq $user )
{
$skipUser = $true
}
if( $user.Department -ne 'Finance' )
{
Write-Verbose "isn't in Finance department"
$skipUser = $true
}
if( $user.Title -match 'Senior' )
{
Write-Verbose "Doesn't have Senior title"
$skipUser = $true
}
if( $user.HomeDrive -like '\\server\*' )
{
Write-Verbose "Home drive already configured"
$skipUser = $true
}
if ( -not $skipUser )
{
# do something
}
Мне нужно было инвертировать логику, чтобы флаги работали правильно. Каждая оценка — это отдельное if
утверждение. Преимуществом этого является то, что при отладке можно точно определить, что делает логика. Я смог добавить гораздо более подробную детализацию одновременно.
Очевидный недостаток заключается в том, что нужно написать гораздо больше кода. Код становится более сложным для восприятия, так как он принимает одну строку логики и разбивает её на 25 или более строк.
Использование функций
Мы также можем переместить всю логику проверки в функцию. Посмотрите на то, как чисто это выглядит на первый взгляд.
if ( Test-SecureDriveConfiguration -ADUser $user )
{
# do something
}
Вам по-прежнему нужно создать функцию для проверки, но это упрощает работу с этим кодом. Это упрощает тестирование этого кода. В тестах можно имитировать вызов Test-ADDriveConfiguration
, и вам потребуется только два теста для этой функции. Одно место, где оно возвращается $true
, и место, где оно возвращается $false
. Тестирование другой функции проще, потому что она такая маленькая.
Тело этой функции может остаться тем однострочным кодом, с которого мы начали, или быть развернутой логикой, которую мы использовали в последнем разделе. Это хорошо подходит для обоих сценариев и позволяет легко изменить эту реализацию позже.
Обработка ошибок
Одним из важных способов использования оператора является проверка наличия ошибок, прежде чем столкнуться с ними. Хорошим примером является проверка того, существует ли папка, прежде чем пытаться создать ее.
if ( -not (Test-Path -Path $folder) )
{
New-Item -Type Directory -Path $folder
}
Я люблю говорить, что если вы ожидаете, что произойдет исключение, то это не на самом деле исключение. Поэтому проверьте свои значения и проверьте условия, где можно.
Если вы хотите немного больше ознакомиться с фактической обработкой исключений, у меня есть статья о том, что вы когда-либо хотели знать об исключениях.
Окончательные слова
Это if
такая простая инструкция, но является основной частью PowerShell. Вы найдете себя использовать это несколько раз почти во всех скриптах, которые вы пишете. Надеюсь, у вас есть лучшее понимание, чем у вас раньше.
PowerShell