admin / 23.09.2018

Функции и фильтры в PowerShell — PKI Extensions

Пока не буду больше ничего писать про новые командлеты в PowerShell V2 CTP3, а вернусь к истории — 1.0.

Как показала практика, функции в скриптах администраторов завоевали очень высокую популярность и этому есть причина — функции позволяют однажды написать блок кода и потом его использовать много раз. Но не все знают всех возможностей функций и их разновидностей в PowerShell. Сегодня мы поговорим о том, на чём чаще всего спотыкаются начинающие пользователи PowerShell.

Аргументы в функциях

В общем смысле функции строятся по такому принципу:

functionFunctionName($arg1,$arg2,$argN){scriptoblock}

сначала мы говорим, что это будет функция и даём ей имя. В скобках указываем список принимаемых аргументов и после, в фигурных скобках указываем блок кода, который будет исполняться при вызове функций. Но функция сама по себе малоинтересна. Как правило в неё передаются какие-то данные и мы их должны как-то получать внутри функции. Данные в функции мы можем передавать двумя методами:

  • используя список аргументов (как в указанном примере)
  • по конвейеру

в первом случае всё просто. Если при объявлении функции мы указываем список аргументов, то при вызове функции эти переменные будут принимать значения. Возьмём простой пример:

functionabc($a,$b,$c){Write-Host'$a = '$aWrite-Host'$b = '$bWrite-Host'$c = '$c}

[vPodans] function abc ($a, $b, $c) { >> Write-Host ‘$a = ‘ $a >> Write-Host ‘$b = ‘ $b >> Write-Host ‘$c = ‘ $c >> } >> [vPodans] abc arg1 arg2 arg3 $a = arg1 $b = arg2 $c = arg3 [vPodans]

Чтобы вызвать функцию — достаточно написать её название и разделяя проблелом передавать ей значения. Вот здесь кроется первая частая ошибка начинающих при работе с PowerShell. Дело в том, что в некоторых языках программирования функции вызываются иначе: functionname (arg1, arg2, argN). В PowerShell же формат вызова функций вот такой: functionname arg1 arg2 argN. При объявлении функции указывать список принимаемых аргументов не обязательно (но рекомендуется для читаемости скрипта). В таком случае все аргументы будут помещены в специальную переменную $args, которая будет являться массивом аргументов. Но кроме аргументов в функции можно передавать параметры-ключи, как в командлетах (например, -Verbose, -WhatIf и т.д.). Это делается при помощи указания типа аргумента. Данный тип называется [switch]:

functionabc($a,$b,[switch]$parameter){Write-Host'$a = '$aWrite-Host'$b = '$bWrite-Host'parameter switch status = '$parameter}

[vPodans] function abc ($a, $b, [switch]$parameter) { >> Write-Host ‘$a = ‘ $a >> Write-Host ‘$b = ‘ $b >> Write-Host ‘parameter switch status = ‘ $parameter >> } >> [vPodans] abc 1 5 -parameter $a = 1 $b = 5 parameter switch status = True [vPodans] abc 1 5 $a = 1 $b = 5 parameter status = False [vPodans]

это очень удобно, когда одним ключом по аналогии с командлетом можно выбирать режим работы функции. Просто в фнукции проверяете статус ключа True или False и в зависимости от этого выбираете режим.

Конвейер и функции

Но часто нам удобней передавать данные в функцию для обработки по конвейеру. И мы безусловно можем так делать. Но тут есть свои тонкости.

[vPodans] function sum {$_ * 2} [vPodans] 1..5 | sum [vPodans]

Мы захотели просто умножить каждое число на 2. Но результата нету.

Это вторая частая ошибка начинающих пользователей, которые путают функцию с конвейерным циклом Foreach-Object:

[vPodans] function sum {$_ * 2} [vPodans] 1..5 | %{sum} 2 4 6 8 10 [vPodans]

а вот теперь получили ожидаемый результат. Дело в том, что в функцию данные поступают не по мере появления их на входе конвейера, а только когда конвейер будет заполнен. Пока конвейер наполняется данными, они помещаются в специальную переменную $input в виде массива. И только после этого начинает исполняться само тело функции. Смотрим:

[vPodans] function input {$input} [vPodans] 1..5 | input 1 2 3 4 5 [vPodans]

Однако, данный метод очень непроизводителен, когда требуется произвести некоторую операцию над каждым элементом конвейера. Поскольку мы должны сначала ждать, пока по конвейеру будут собраны все данные в переменную $input и только потом начнётся сама обработка. Т.к. переменная $input является массивом, то мы не можем прямо к ней использовать переменную текущего элемента $_. Как вариант, можно в самой функции разобрать переменную $input циклом и получить требуемый результат:

[vPodans] function sum {$input | %{$_ * 2}} [vPodans] 1..5 | sum 2 4 6 8 10 [vPodans]

Задача хоть и решена, но кроме потери производительности у нас ещё вырос объём кода. Что тоже не есть хорошо. Чтобы избавиться от переменной $input можно использовать этап функции — Process. Что это такое и с чем его едят можно узнать из замечательного поста Дмитрия Сотникова — $input Gotchas. Материал по ссылке изложен достаточно подробно и он будет понятен даже тем, у кого есть хотя бы базовые навыки английского языка. Итак:

[vPodans] function sum {process {$_ * 2}} [vPodans] 1..5 | sum 2 4 6 8 10 [vPodans]

на этапе Process мы отказываемся в дополнительном разборе переменной $input, поскольку этап Process уже начинает исполняться при поступлении первого элемента на вход конвейера. Следовательно мы получаем выигрыш в скорости работы. Но для таких вещей, как обработка каждого элемента в функции в PowerShell есть одна разновидность функции и называется фильтр! По сути фильтр является той же функцией, которая помещена в цикл Foreach-Object. Фильтры в PowerShell используются так же, как и функции:

filterFilterName($arg1,$arg2){scriptoblock}

[vPodans] filter sum {$_ * 2} [vPodans] 1..5 | sum 2 4 6 8 10 [vPodans]

это то же самое, что и:

[vPodans] function sum {$_ * 2} [vPodans] 1..5 | %{sum} 2 4 6 8 10 [vPodans]

Как видите, вариантов решений задачи в функциях существует много и каждый может использовать тот, что ему по душе. Можно сказать, что это мелочи? Да, можно. Но именно вот такие мелочи будут влиять на эстетическую красоту, производительность и ресурсопотребление ваших скриптов в работе. Причём разница в производительности и ресурсопотреблении может доходить до 100(!) раз, в зависимости от выбранного метода. Об этом я уже говорил в своём предыдущем блоге на примере циклов: Foreach, Foreach-Object и оптимизация циклов в PowerShell.

Обычно я запускаю скрипты powershell из cmd.exe, потому что это переносится (работает на других компьютерах, например, разработчиках или клиентах): не нужно беспокоиться о Set-ExecutionPolicy или связывать расширение .ps1.

Я создаю файл с расширением .cmd(вместо .ps1) и копирую & вставляю короткий, постоянный код для первой строки (строк), которая вызывает powershell.exe и передает остальные файла к нему.
Передача аргументов сложна.

«Antananarivo» — перевод на русский

У меня есть несколько вариантов постоянного кода потому что общий случай болезнен.

  • когда не передаются аргументы, файл .cmd выглядит так:

    Здесь используется аргумент -Command параметра powershell.exe.

    Powershell читает .cmd файл как текст, помещает его в ScriptBlock, когда первая строка закомментирована, и оценивает его с помощью. команда. Далее аргументы командной строки могут быть добавлены к вызову Powershell по мере необходимости (например, -ExecutionPolicy Unrestricted, -Sta и т.д.)

  • при передаче аргументов, которые не содержат пробелов или являются «одинарными», (который не является стандартным в cmd.exe), однострочный:

    также могут быть использованы объявления, не является обязательным.
    используется для компенсации отсутствующей информации .
    Примеры:

  • при передаче аргументов, которые являются «двойными кавычками», но не содержат «и», «Я использую двухстрочный, чтобы заменить все» на «

    (Обратите внимание, что это пространство важно для назначения для аргумент без аргументов.)
    Результаты:

  • наиболее общий случай передает аргументы через переменные среды поэтому выражение Powershell не работает. В этом случае ожидается, что аргументы будут «двойными» и могут содержать «или»; (за исключением пути самого файла .cmd):

    (Обратите внимание, что в первой строке не должно быть пробела.)
    Результат:

  • Rencontres Du Film Court Antananarivo

    Использование переменных для хранения объектовUsing Variables to Store Objects

    • Время чтения: 4 мин
    • Соавторы

    PowerShell работает с объектами.PowerShell works with objects.Можно создавать переменные, главным образом именованные объекты, чтобы сохранять выходные данные для последующего использования.PowerShell lets you create variables, essentially named objects, to preserve output for later use.Если вы привыкли работать с переменными в других оболочках, помните, что переменные PowerShell являются объектами, а не текстом.If you are used to working with variables in other shells remember that PowerShell variables are objects, not text.

    Имена переменных всегда начинаются с символа $ и могут включать любые буквенно-цифровые символы или знаки подчеркивания.Variables are always specified with the initial character $, and can include any alphanumeric characters or the underscore in their names.

    Создание переменнойCreating a Variable

    Чтобы создать переменную, можно ввести для нее допустимое имя:You can create a variable by typing a valid variable name:

    Это не возвращает никаких результатов, так как $loc не имеет значения.This returns no result because $loc does not have a value.Создать переменную и присвоить ей значение можно в одном шаге.You can create a variable and assign it a value in the same step.PowerShell создает переменную, только если она не существует. В противном случае указанное значение назначается существующей переменной.PowerShell only creates the variable if it does not exist; otherwise, it assigns the specified value to the existing variable.Для сохранения текущего расположения в переменной $loc введите:To store your current location in the variable $loc, type:

    При вводе этой команды выходные данные не отображаются, поскольку они отправляются в $loc.There is no output displayed when you type this command because the output is sent to $loc.В PowerShell выходные данные всегда выводятся на экран, если они не перенаправлены в другое расположение.In PowerShell, displayed output is a side effect of the fact that data, which is not otherwise directed, always gets sent to the screen.При вводе $loc отображается ваше текущее расположение:Typing $loc will show your current location:

    Get-Member можно использовать для отображения сведений о содержимом переменных.You can use Get-Member to display information about the contents of variables.Передача $loc в Get-Member покажет, что это объект PathInfo, так же как и выходные данные Get-Location:Piping $loc to Get-Member will show you that it is a PathInfo object, just like the output from Get-Location:

    Работа с переменнымиManipulating Variables

    PowerShell предоставляет несколько команд для работы с переменными.PowerShell provides several commands to manipulate variables.Полный список в удобочитаемой форме можно получить, введя следующее:You can see a complete listing in a readable form by typing:

    Кроме переменных, создаваемых в текущем сеансе PowerShell, существует несколько системных переменных.In addition to the variables you create in your current PowerShell session, there are several system-defined variables.Можно использовать командлет Remove-Variable, чтобы очистить все переменные, которыми не управляет PowerShell.You can use the Remove-Variable cmdlet to clear out all of the variables which are not controlled by PowerShell.Введите следующую команду для очистки всех переменных:Type the following command to clear all variables:

    В результате выводится приведенный ниже запрос на подтверждение.This will produce the confirmation prompt you see below.

    Если вы запустите командлет Get-Variable, отобразятся остальные переменные PowerShell.If you then run the Get-Variable cmdlet, you will see the remaining PowerShell variables.Так как существует диск переменных PowerShell, также можно вывести на экран все переменные PowerShell при помощи следующей команды:Since there is also a variable PowerShell drive, you can also display all PowerShell variables by typing:

    Использование переменных Cmd.exeUsing Cmd.exe Variables

    Хотя средство PowerShell — это не Cmd.exe, оно выполняется в среде командной оболочки и может использовать переменные, доступные в любой среде в Windows.Although PowerShell is not Cmd.exe, it runs in a command shell environment and can use the same variables available in any environment in Windows.Эти переменные предоставляются посредством диска с именем env:.These variables are exposed through a drive named env:.Эти переменные можно просмотреть, введя следующее:You can view these variables by typing:

    Хотя стандартные командлеты переменных не предназначены для работы с переменными env:, их все равно можно использовать, указав префикс env:.Although the standard variable cmdlets are not designed to work with env: variables, you can still use them by specifying the env: prefix.Например, для просмотра корневого каталога операционной системы можно использовать переменную %SystemRoot% командной оболочки из PowerShell, выполнив следующую команду:For example, to see the operating system root directory, you can use the command-shell %SystemRoot% variable from within PowerShell by typing:

    В PowerShell также можно создавать и изменять переменные среды.You can also create and modify environment variables from within PowerShell.Переменные среды из Windows PowerShell соответствует обычным правилам для переменных среды в рамках всей системы Windows.Environment variables accessed from Windows PowerShell conform to the normal rules for environment variables elsewhere in Windows.

    Шпаргалка по PowerShell

    Известно, что хороший специалист — это тот специалист, который знает, где найти информацию, быстро разобраться в ней и решить с помощью нее проблему. Я в своей работе частенько пользуюсь шпаргалками, которые сам для себя написал. ExchangeRUS.ru является примером такой шпаргалки, в голове все тонкости удержать сложно.

    Комментарий постера: для меня лично такой шпорой стал данный сайт


    PowerShell — это новый навык, которым должен будет обладать каждый ИТ-специалист. Хотите ли Вы этого или нет — это дело времени. Я уже давно думал о том, что неплохо было бы создать по нему некую шпаргалку, но оказывается, она уже существует.

    Get-help, конечно же, хорошая команда, но иногда нужна именно выжимка по часто используемым командам. Bruce Payette, Principal Developer в Windows PowerShell team в Microsoft, один из создателей языка PowerShell, написал симпатичную шпаргалку по PowerShell.

    Она включает в себе начальные сведения об использовании Windows PowerShell, включая описание синтаксиса, операторов и других элементов языка. А также приведены примеры использования .NET, COM, ADSI и WMI объектов из PowerShell. Главной фишкой шпаргалки являются Tips&Tricks— короткие примеры выполнения основных задач с помощью PowerShell.

    Чтобы бесплатно скачать шпаргалку, нужно зарегистрироваться на сайте, и по почте придет нужная ссылка.

    НО! Это не единственная шпаргалка. Оказывается, хорошая шпаргалка поставляется вместе с PowerShell и находится в файле

    в русской версии PoSh, я надеюсь, Вы знаете, где искать 🙂

    Больше информации о PowerShell можно найти в блоге Василия Гусева.

    Удачи в освоении PowerShell!

    Например:

    Итак, как вы создаете псевдоним для такой команды?

    Ну, вы этого не сделаете : PowerShell позволит создавать псевдонимы для командлетов, функций, скриптов или файлов.

    Так есть ли способ обойти эту проблему? Конечно, есть: всегда есть способ обойти проблему. (Ну, за исключением случаев, когда этого не происходит.) С одной стороны, вы можете написать скрипт, который запускает эту команду для вас; В этом нет ничего плохого.

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

    Здесь у нас есть небольшая функция с именем itusers, функция, которая возвращает всех пользователей в ИТ-отделе, а затем отображает значения атрибутов DisplayName, Enabled и SipAddress для каждого из этих пользователей (и в таблице с хорошо отформатированным загрузки).

    Инструкции, как показано здесь .

    FILED UNDER : IT

    Submit a Comment

    Must be required * marked fields.

    :*
    :*