- Как использовать циклы While и Foreach в Powershell Foreach на примерах
- Foreach-Object
- Итерации
- Сохранение через переменные
- Алиасы
- ForEach
- Использование с командами
- Работа с диапазоном или range
- Continue и break
- Вложенные
- Переменные
- Сравнение ForEach и команды ForEach-Object
- Метод foreach()
- Работа с командами
- While
- Break и continue
- Do и While
- Do Until
Как использовать циклы While и Foreach в Powershell Foreach на примерах
22 октября 2019
Основное предназначение циклов в Powershell, так же как и в других языках, выполнение итераций. Проще говоря они помогают выполнять одну и ту же инструкцию для разных значений. Отличительной чертой циклов в Powershell является их количество, всего их 7:
- Foreach-Object — команда;
- Foreach — выражение;
- Foreach() — метод;
- For — цикл;
- While — цикл;
- Do-While — цикл;
- Do-Until — цикл.
Каждый из них по своему выполняет итерации. Само понятие итераций обозначает повторное выполнение действий, например команд. Иногда можно услышать слова «итерируемый объект» или «итератор», которые обозначают объект проходящий через цикл.
Навигация по посту
Foreach-Object
Foreach-Object относится к командам, а не циклам. Чаще всего мы с ним работаем через конвейер.
Итерации
Так же, как и во многих других командах Powershell у Foreach-Object есть параметр InputObject, через который помещается объект для перебора. На примере ниже этот объект в виде массива с числами:
$PSitem это переменная, которая хранит текущее значение массива. Мы ее выводим через параметр Process, в котором можно дополнить логику командами или условиями. Переменная $PSitem аналогична такому написанию $_ .
Если вы имеете опыт работы с Powershell, то чаще использовали с конвейером:
По сути в команде выше происходит то же самое, просто в функциях и командах есть возможность установить параметр, который принимает значения по умолчанию из конвейера. Я так же добавил вывод только имени, так как у объекта из Get-Service есть такое свойство. Более подробно это описывалось статьей по созданию команд и функций в Powershell. Параметры, которые принимают значения из конвейера можно увидеть так:
Когда вам нужно использовать больше логики зажимайте shift + enter для перехода на новую строчку, если работаете из консоли. Скрипт ниже получает список процессов, передает их через конвейер, где через наш командлет происходит анализ время отклика CPU с выводом результата:
Можно использовать и другой синтаксис. Так я получу имена сервисов:
Я не видел, что бы кто-то использовал такой синтаксис, но он возможен. На примере ниже я преобразую строки в массив двумя способами:
Split — это метод, который преобразует строку в массив используя указанный разделитель (в нашем случае запятая). Методы и свойства, доступные у объекта, можно увидеть через Get-Member:
Сохранение через переменные
Результат этого командлета, так же как и любого другого можно сохранить в переменную и использовать дальше:
Алиасы
У этой команды есть алиасы foreach и знак %:
Обратите внимание, что использование следующего синтаксиса приведет к ошибке:
Связано это с тем, что в Powershell работает командлет и метод с одним именем. Каждый из них имеет свой синтаксис и вызывая foreach без конвейера мы используем метод. Он будет разобран следующим.
ForEach
Этот цикл, в отличие от предыдущего командлета, не будет работать через конвейер. Если вы попытаетесь использовать этот метод через конвейер, то будет использован командлет.
Это самый простой цикл Powershell, который переходит от одного значения объекта к другому. Синтаксис следующий:
- $item — хранит текущий элемент из $array. Эту переменную можно вызвать в ScriptBlock;
- $array — это любая коллекция, из которой нужно получить значения;
- Scriptblock — это область для написания сценария и остальной логики.
Для примера с foreach в Powershell выполним перебор значений массива:
Так же как и в предыдущем случае каждый новое действие в ScriptBlock должно выполняться с новой строчки:
Выше было написано, что мы не можем использовать конвейер, но исключение такое написание:
Как вы можете догадаться — это не работа цикла с конвейером, а просто передача массива.
Использование с командами
Как уже писалось выше не стоит использовать метод Powershell foreach через конвейер. Например так мы можем получить список PSProvider:
Можно добавлять выражение в сам цикл, но такой подход как минимум понизит читаемость кода. Самое главное экранировать выражение круглыми скобками:
На примере ниже пример использования цикла и командлета с одни и тем же результатом:
Как видно в случае с командой мы оперируем переменной $PSItem, а с циклом $service, так как мы ее определили еще в начале.
Работа с диапазоном или range
В Powershell можно легко указать диапазон численных значений. Я могу создать массив из чисел с 1 до 10 так:
Так же можно использовать и в итерациях:
Continue и break
Одним из отличий работы с foreach от аналогичной команды является возможность использования contnue и break.
Оператор continue минует выполнение оставшейся части скрипта после своего выполнения. На примере ниже есть два массива и если в одном из них будут встречаться одинаковые числа, то они не будут выведены:
В отличие от continue break останавливает итерации полностью. Его удобно использовать, когда мы ищем нужное значение и нам нужно остановить итерации после его нахождения:
Вложенные
Когда у нас есть массив массивов может потребоваться использовать вложенные циклы Powershell. Само их использование не должно вызывать труда, но если вы попробуете использовать операторы break и continue это сработает иначе:
Как вы видите на примере выше у нас остановился только внутренний цикл. Если нужно избежать таких ситуаций используйте OUTER:
Переменные
В этом типе цикла доступны три специальных переменных:
- $foreach.MoveNext() — переход к следующему элементу;
- $foreach.current — текущий элемент;
- $foreach.reset() — обнуляет итерацию. Перебор начнется заново, что приведет к бесконечному циклу.
Такие возможности есть во многих языках программирования, но мне тяжело вспомнить ситуации что бы я их использовал. Для примера ниже мы используем массив чисел с 1 по 10. Самое первое число 1 будет выведено, после чего будет пропущено следующее:
$current просто выведет ту же переменную, объявленную в цикле:
Сравнение ForEach и команды ForEach-Object
Foreach | ForEach-Object |
---|---|
Загружает все элементы коллекции | Загружает только один элемент в память через конвейер |
Использует больше памяти из-за полной загрузки массивов | Меньшее использование памяти из-за одного элемента |
С небольшим объемом массивов работает быстрее | Работает медленнее |
Нельзя использовать через конвейер. Это не приведет к ошибке, но будет использован алиас командлета | Можно использовать конвейер или параметр InputObject |
Поддерживаются методы break и continue | Нельзя прервать используя методы contiinue и break |
Скорость работы обоих этих методов можно увидеть через следующие скрипты:
Метод foreach()
В версии Powershell 4.0 появился метод foreach() для поддержки DSC. Он немного отличается синтаксисом и подходом от описаны выше. Более простой способ понять, как он работает это посмотреть на его синтаксис:
Как я прочитал этот метод предназначен для работы только с коллекциями и по идеи такой способ должен привести к ошибке:
На всякий случай я бы советовал преобразовывать такие данные в массив:
Работа с командами
Работы с командами не должна вызывать сложности. Для примера так мы получим список имен сервисов, которые остановлены:
Самое главное экранировать результат команды в скобки или выполнять метод для переменной, которая уже хранит значения.
Еще один пример с сервисами:
В Powershell есть еще один способ итераций через for. Его отличие в том, что мы можем изменять основной объект до выполнения ScriptBlock. Синтаксис следующий:
Для примера получим числа с 1 по 10:
Поясню момент, который мог быть вызван написанием $i++, все следующие действия одинаковы, но не все сработают в этом цикле:
Вы можете изменять несколько объектов:
В итерациях вы можете использовать любой тип данных, не только цифры:
Вы можете пропустить любую часть этого цикла, но если ничего не будет указано получится бесконечный цикл:
Возможно использовать этот цикл с командлетами, но пример высосан из пальца:
Операторы break и continue работают так же.
Powershell экспорт и запись в CSV файл
While
Как можно было увидеть выше мы рассматривали циклы, которые перебирали элементы массивов, но существует еще один тип позволяющий управлять этим процессом более гибко. Для примера нам может понадобится выполнять функцию, командлет или скрипт до тех пор пока мы не получим нужны результат и для этого можно использовать While:
Пример выше работает до тех пор, пока переменная $a меньше или равна 10 или, другими словами, пока значение в скобках не станет True.
Более понятный пример это с утилитой ping. Когда мы потеряли доступ к интернету или упал сервер, то мы запускаем команду с ключом -t и она работает до тех пор пока мы не остановим этот процесс руками нажав Ctrl+c. Такая работа в Powershell относится к бесконечным циклам и на примере выглядит так:
Все эти операции можно выполнить и с foreach, но это плохая практика. Например так можно реализовать аналогичный вечный цикл с for:
Break и continue
Ключевой момент работы с while это использование break, который остановит итерации. Мы пинговали сайт, но останавливали итерации руками и что бы этого не делать в дальнейшем нужно добавить условие при котором будет выполнен break:
Очень важно хорошо продумывать логику остановки скрипта. Вечные циклы, которые могут работать в полноценных сриптах, программах и планировщиках будет очень тяжело отлавливать.
Такие итерации останавливают либо методом break, либо счетчиком, который был показан в первом примере и ниже. Если мы будем использовать счетчик и continue, который пропускает выполнения условия, то тоже можем получить вечный цикл:
Я не помню, что бы я хоть раз использовал continue в реальных задачах, но стоит помнить о существовании такой возможности.
Мы можем выполнять команду в условиях и объявлять в ней переменную для дальнейшего использования:
Do и While
Отличие работы этого цикла от предыдущего в том, что он проверяет условия после выполнения операций, а не до. Из-за этого, если условие изначально равно $False, цикл будет выполнен один раз:
Или поставим заведомо ложные условия при котором предыдущий цикл не стал бы работать:
Такие итерации можно использовать со случаями, когда от пользователя ожидается выбор действий:
Если вам интересны или вы не понимаете switch, то я бы советовал почитать «Как работать с Powershell Switch на примерах».
Do Until
Предыдущий цикл выполняет итерации до тех пор, пока главное условие равняется $True. Цикл Do Until имеет такой же синтаксис, но работает до тех пор пока условие не станет $True, то есть пока оно $False: