Advanced PowerShell vol. 1: повторное использование кода. Powershell функции


Возвращаемые значения функций в Windows PowerShell

В отличие от традиционных языков программирования, где функция возвращает единственное значение определенного типа, в Windows PowerShell результаты всех вычислений направляются в так называемый выходной поток. Давайте посмотрим, как это выглядит на практике.

Создадим функцию Primer, которая будет выполнять три математических операции.

Function Primer {1+1; 2*2; 10/2}

Далее запустим функцию и посмотрим на результаты её работы.

Как видим, функция возвращает три значения в качестве результата своей работы.

Данные результаты можно сохранить. Используем для этого переменную $Result.

$Result=Primer

Проверим тип переменной.

$Result.GetType().FullName

Итак, переменная $Result есть не что иное, как массив. Можно просмотреть длину этого массива и значения его элементов.

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

Создадим простенькую функцию, которая будет поздравлять с Новым годом.

Function Primer { $year=Read-Host "Введите год" "С Новым $year годом!" $year }

Посмотрим возвращаемые функцией значения.

Как видим, функция вернула два значения. Хотя, наверное, логичнее было бы, если бы в массив попало только значение переменной $year.

Чтобы избежать попадание в выходной поток ненужных нам данных, мы можем воспользоваться командлетом Write-Host. Такой командлет выведет данные непосредственно в консоль, а не в выходной поток.

Function Primer { $year=Read-Host "Введите год" Write-Host "С Новым $year годом!" $year }

Лишнее также можно отсечь инструкцией Return. Данная инструкция аналогична инструкции Break в циклах PowerShell и выполняет немедленный выход из функции.

Function Primer { "Данная запись выводится на экран" Return "А вот эта запись не выводится на экран" }

webistore.ru

Обработка аргументов функций в Windows PowerShell

В предыдущих статьях о Windows PowerShell мы, в основном, концентрировались на стандартных командлетах, функциональность которых было невозможно изменить по причине недоступности исходного кода. В отличие от них, функции и сценарии доступны для изменения через язык PowerShell.

Обзорно мы разобрали функции ранее. Теперь же поговорим об обработке аргументов, с которыми работают функции.

В Windows PowerShell реализованы два механизма обработки аргументов, а именно, через переменную $Args и через задание формальных параметров. Рассмотрим поочередно оба метода.

Обработка аргументов функции через переменную $Args

Все переменные, с которыми работает функция, автоматически сохраняются в переменной $Args. Таким образом, в $Args содержится массив, элементами которого являются параметры функции, указанные при её запуске.

Для примера добавим переменную $Args в функцию Primer и вызовем её с двумя параметрами.

Function Primer{"Столицей России были $Args"}

Как видим, эти два параметра (в данном случае названия двух российских городов), появляются в выходной строке через пробел. Можно изменить разделитель при помощи специальной переменной $OFS.

Function Primer{ $OFS="," "Столицей России были $Args"}

Так как переменная $Args является массивом, то внутри функции можно обращаться к отдельным её аргументам по их порядковому номеру (нумерация начинается с нуля), а с помощью метода Count посчитать общее количество аргументов. Приведем пример.

Function Summa{"Количество аргументов: $($Args.Count)" $n=0 For($i=0; $i -lt $Args.Count; $i++) {$n+=$Args[$i]} "Сумма аргументов: $n"}

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

Обработка аргументов функции через формальные параметры

Как и в других языках программирования, в PowerShell при описании функции можно задать список формальных параметров, значения которых во время выполнения функции будут заменены значениями фактически переданных аргументов.

Формальные параметры указывают в круглых скобках после имени функции. Для примера создадим функцию с двумя формальными параметрами, один из которых вычитается из другого.

Function Primer ($a, $b) {$a-$b}

В данном случае соответствие формальных параметров переданным аргументам определяется по позиции. Первый аргумент (число 5) подставляется вместо первого параметра, второй (число 3) — вместо второго.

При указании аргументов можно использовать имена формальных параметров, и тогда порядок их перечисления перестаёт играть роль.

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

Можно поступить и по другому. Некоторым аргументам задать имена, а оставшиеся безымянные аргументы будут сопоставлены с оставшимися формальными параметрами по позиции.

Как видим, здесь мы указали конкретный аргумент формальному параметру $d, остальные же аргументы были присвоены параметрам в соответствии с заданным порядком (сначала $a, потом $b, потом $c).

По умолчанию функции в PowerShell полиморфны. Это значит, что тип формальных параметров присваивается автоматически.

В примере выше PowerShell автоматически привел формальные параметры к нужному типа в зависимости от формы записи аргументов. Поэтому в первом случае нам возвращается число 12, а во втором строка «48». Проверить это можно через уже известный нам GetType.

Если это так необходимо, мы можем задать тип вручную. И тогда мы получим нужный нам результат независимо от формы записи.

Function Primer ([int] $a, [int] $b) {$a+$b}

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

В данном случае всё произошло из-за символа f.

Рассмотрим тот случае, когда функции было задано аргументов больше, чем у неё прописано формальных параметров. В таком случае всё оставшиеся аргументы прописываются в массиве $Args.

Function Primer ($a, $b) { "Первый аргумент: $a" "Второй агрумент: $b" "Остальные аргументы: $Args"}

В примере выше мы создали два формальных параметра, а остальные аргументы определил в массив $Args. Когда задан лишь один аргумент, он по позиции присваивается параметру $a. При этом значение параметра $b устанавливается равным $Null, а массив $Args не содержит элементов ($Args.Length=0). Когда заданы два аргумента, они присваиваются соответствующим параметрам, а массив $Args остаётся пустым.

Теперь зададим три и четыре аргумента соответственно.

Как видим, все оставшиеся аргументы попадают в массив $Args.

При определении формальных параметров можно задавать их значения по умолчанию.

Function Primer ($a=5, $b=3) {$a+$b}

В данном случае функция отработала вообще без аргументов.

Если эту же функцию запустить с одним аргументов, то он будет присвоен по порядку параметру $a, а параметр $b примет значение по умолчанию.

Среди формальных параметров функции выделяется параметр-переключатель SwitchParameter, который используется под псевдонимом [Switch].

Function Primer ([Switch] $n) { if ($n) { "Переключатель включен" } else { "Переключатель выключен" } }

В данном примере функция выполняет различные действия в зависимости от того, указываем мы её с параметром $n или нет. Параметр $n является переключателем и определяет, что делать функции.

webistore.ru

Microsoft PowerShell. Функции. - Alexander

Введение

  Привет-привет.  Пребывая в лагере линуксоидов, я с самого начала существования PowerShell относился к нему очень скептически. Раздражал синтаксис, "дурацкие" названия команд и заточенность под одну платформу. Думал, зачем мне изучать оболочку, с помощью которой можно администрировать только одно семейство операционных систем?.. Однако, мечты нихрена не сбылись и в администраторы Linux я так и не ушел, до сих пор в рабочей среде имею дело лишь с Windows. И летом 2014 года мне стало вполне ясно, что без знания PS не обойтись. Версии 1.0 и 2.0 я благополучно пропустил, а начал с 3.0 и всеми вытекающими из нее вкусностями и удобностями. Спасибо работе в Домодедово, где додумались (что странно) пригласить инструктора от MS прочесть нам курс по сабжу.  Долго думал, чего бы такого написать, чтобы и польза была и сильно банальным не оказалось и решил, что функции - самое то. Вроде бы и не самая база, но интересно и самому полезно закрепить, изложив знания на "бумаге".

Что такое функция?  Можно обратиться к статье на Википедии, но если бы меня попросили объяснить своими словами, я бы сказал, что это такой кусок кода, описанный в программе, который можно вызвать в любое время и получить какой-то результат. Удобно, если этот код весьма объемный, а вызывать его нужно не один раз. По мне это избавляет нас от лишних строк и повышает читаемость. А еще функции могут принимать входные значения, что тоже круто. =)  Синтаксис описания простейшей функции на PS выглядит следующим образом:function FunctionName { DO SOMETHING }  Т.е. сперва идет слово function, потом её имя и в фигурных скобках выполняемый код. Как пример, следующая функция добавит пользователю Active Directory asand3r текст "Administrator" в поле описания:function Add-Description { Set-ADUser asand3r -Description "Administrator" }Теперь созданную функцию можно вызвать из текущего сеанса PowerShell в любой момент времени просто напечатав ее имя и атрибут Description обновится.

Параметры  Функции поддерживают передачу им на вход различных параметров. Это довольно удобно, если вы пишите интерактивную функцию, которой хотелось бы иметь возможность задать объект действия. Параметры задаются следующим образом:function FunctionName {param (            $ParameterName         )DO SOMETHING}  Если разбирать на описанном выше примере, то можно предположить, что вам нужно добавлять описание не к одному и тому же пользвателю, а к разным и это хотелось бы указать. Поэтому мы сделаем так:function Add-Description {param(          $UserName       )Set-ADUser $UserName -Description "Admin"}Теперь при вызове Add-Decription мы можем указать параметр -UserName и задать имя пользователя:Add-Description -UserName Vasya  Предположим, мы хотим отдать наш скрипт в пользование коллеге и думаем добавить некоторые удобства. Чтобы скрипт не ругался кучей красных букв на вызванный без параметров скрипт, мы скажем ему, что параметр $UserName является обязательным. Для этого используется атрибут Mandatory:function Add-Description {param(          [Parameter(Mandatory=$True)]$UserName)Set-ADUser $UserName -Description "Admin"}При вызове функции без параметра -UserName, скрипт сам предложит ввести его, не выдав ошибки.  Следующим шагом мы введем в нашу функцию второй параметр. Делается это очень просто, но всё же стоит об этом рассказать. Пармаметры отделяются друг от друга запятой. Предположим, что мы хотим не только изменять описание к учетной записи, но включать/отключать её. Введем для этого новый параметр и немного модернизируем скрипт:function Add-Description {param(          [Parameter(Mandatory=$True)]$UserName,          [Parameter(Mandatory=$False)]$Enabled)Set-ADUser $UserName -Description "Admin" -Enabled $Enabled}Еще одна фишка - мы знаем, что для второго параметра у нас допустимы только два значения - $True и $False - и не хотим, чтобы скрипт обрабатывал введенные туда любые другие типы данных. Для этого параметру можно указать этот самый тип и делается это добавлением еще одного условия, в нашем случае [bool]:function Add-Description {param(          [Parameter(Mandatory=$True)]$UserName,          [bool][Parameter(Mandatory=$False)]$Enabled)Set-ADUser $UserName -Description "Admin" -Enabled $Enabled}Теперь, при попытке передать для -Enabled что-то отличное от $true или $false, скрипт будет выдавать ошибку.  Условий к параметрам можно передать многожество. Это и проверка по шаблону ([ValidatePattern()]), проверка по количеству символов ([ValidateLength()], проверка по числовому диапазону ([ValidateRange()]), можно даже использовать для проверки скрипт ([ValidateScript({ ... })]).Как пример, допустим, мы хотим, чтобы передаваемое имя учетной записи начиналось только на "a" (предположим, что вот такая у нас долбанутая система делегирования полномочий). Выглядеть это будет таким образом:function Add-Description {param(          [ValidateScript({$_ -like "a*"})][Parameter(Mandatory=$True)]$UserName,          [bool][Parameter(Mandatory=$False)]$Enabled)Set-ADUser $UserName -Description "Admin" -Enabled $Enabled}С параметрами стоит поиграться, они могут сильно повысить дружелюбность вашего скрипта.

Вот как-то так и пишутся функции. Пользоваться ими стоит, сильно облегчит жизнь и повысит дружелюбность ваших сценариев.Удачи. =)

asand3r.livejournal.com

повторное использование кода / Хабрахабр

Привет! Как большой поклонник и активный практик PowerShell я часто сталкиваюсь с тем, что мне необходимо повторно использовать ранее написанные куски кода. Собственно, для современных языков программирования code reuse — это обычное дело.PowerShell в этом вопросе не отстает, и предлагает разработчикам (написателям скриптов) сразу несколько механизмов обращения к написанному ранее коду. Вот они по возрастанию сложности: использование функций, дот-сорсинг и написание собственных модулей.

Рассмотрим их все порядку.

В качестве решения лабораторной задачи напишем скрипт, который расширяет раздел C:\ до максимально возможного размера на удаленном Windows-сервере LAB-FS1. Такой скрипт будет состоять из одной строки и выглядеть так:

Invoke-Command -ComputerName LAB-FS1 -ScriptBlock { "rescan", "select volume=c", "extend" | diskpart } Работает это так. Сначала PowerShell устанавливает удаленное соединение с сервером LAB-FS1 и запускает на нем локально набор команд, заключенный в фигурные скобки параметра -ScriptBlock. Этот набор в свою очередь последовательно передает команде diskpart три текстовых параметра, а diskpart выполняет (по очереди) повторное сканирование разделов, выбор раздела C:\ и расширение его до максимально возможного размера.

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

Самый простой вариант.

Предположим, что мы пишем большой скрипт, в котором нам по разным причинам необходимо много раз запускать расширение разделов на разных серверах. Логичнее всего выделить весь этот скрипт в отдельную функцию в этом же .ps1-файле и в дальнейшем просто вызывать ее по необходимости. Помимо этого мы расширим функционал скрипта, позволив администратору явно указывать имя удаленного сервера и букву расширяемого раздела. Имя и букву будем передавать с помощью параметров. Функция и ее вызов будут выглядеть так:

function ExtendDisk-Remotely { param ( [Parameter (Mandatory = $true)] [string] $ComputerName, [Parameter (Mandatory = $false)] [string] $DiskDrive = "c" ) Invoke-Command -ComputerName $ComputerName -ScriptBlock {"rescan", "select volume=$using:DiskDrive", "extend" | diskpart} } ExtendDisk-Remotely -ComputerName LAB-FS1 Здесь для функции ExtendDisk-Remotely заданы два параметра:
  • Обязательный ComputerName;
  • Необязательный DiskDrive. Есть не задать имя диска явным образом, скрипт будет работать с диском C:\
Также можно отметить, что передача локальной переменной в удаленную сессию осуществляется с помощью ключевого слова using.

Сохраним скрипт под именем Example-01-Functions.ps1 и запустим:

Видим, что наша функция успешно вызвалась и расширила раздел C:\ на сервере LAB-FS1.

Усложняем ситуацию. Наша функция по расширению разделов оказалась так хороша, что мы хотим прибегать к ее использованию и в других скриптах. Как быть?

Копировать текст функции из исходного .ps1-файла и вставлять ее во все необходимые? А если код функции регулярно обновляется? А если эта функция нужна сотне скриптов? Очевидно, надо выносить ее в отдельный файл и подключать по мере необходимости.

Создадим отдельный файл для всех наших функций и назовем его Example-02-DotSourcing.ps1. Его содержимое будет таким:

function ExtendDisk-Remotely { param ( [Parameter (Mandatory = $true)] [string] $ComputerName, [Parameter (Mandatory = $false)] [string] $DiskDrive = "c" ) Invoke-Command -ComputerName $ComputerName -ScriptBlock {"rescan", "select volume=$using:DiskDrive", "extend" | diskpart} } Это объявление функции (без вызова), которая теперь хранится у нас в отдельном файле и может быть вызвана в любой момент с помощью техники, которая называется dot-sourcing. Синтаксис выглядит так:. C:\Scripts\Example-02-DotSourcing.ps1 ExtendDisk-Remotely LAB-FS1 Внимательно посмотрите на первую строку кода и проанализируйте ее содержимое: точка, пробел, путь к файлу с описанием функции.

Такой синтаксис позволяет нам подключить к текущему скрипту содержимое файла Example-02-DotSourcing.ps1. Это то же самое, что использовать директиву #include в C++ или команду using в C# — подключение кусков кода из внешних источников. После подключения внешнего файла мы уже во второй строке можем вызвать входящие в него функции, что мы успешно и делаем. При этом задотсорсить внешний файл можно не только в теле скрипта, но и в «голой» консоли PowerShell:

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

Внимание: Я использую в работе PowerShell версии 4. Одна из его особенностей заключается в том, что он автоматически подгружает в оперативную память модули по мере обращения к ним, без использования командлета Import-Module.

В старых версиях PowerShell (начиная с 2) написанное ниже будет работать, но может потребовать дополнительных манипуляций, связанных с предварительным импортом модулей перед их использованием. Мы же будем рассматривать современные среды.

Усложняем ситуацию еще раз.

Мы стали очень хорошими PowerShell-программистами, написали сотни полезных функций, для удобства использования разделили их на десятки .ps1-файлов, и в нужные нам скрипты дотсорсим нужные файлы. А если у нас десятки файлов для дотсорсинга и их надо указать в сотне скриптов? А если мы несколько из них переименовали? Очевидно, что придется менять путь ко всем файлам во всех скриптах — это страшно неудобно.

Поэтому.

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

Что такое модуль Windows PowerShell

Модуль Windows PowerShell — это набор функционала, который в том или ином виде размещен в отдельных файлах операционной системы. Например, все родные Микрософтовские модули являются бинарными и представляют собой скомпилированные .dll. Мы же будем писать модуль скриптовый — скопируем в него код из файла Example-02-DotSourcing.ps1 и сохраним как файл с расширением .psm1.

Чтобы понять, куда сохранять, посмотрим содержимое переменной окружения PSModulePath.

Видим, что по умолчанию у нас есть три папки, в которых PowerShell будет искать модули. Значение переменной PSModulePath можно редактировать с помощью групповых политик, задавая таким образом пути к модулям для всей сети, но это другая история, и рассматривать ее сейчас мы не будем. Зато будем работать с папкой C:\Users\Administrator\Documents\WindowsPowerShell\Modules и сохраним наш модуль в нее. Код остается неизменным:

function ExtendDisk-Remotely { param ( [Parameter (Mandatory = $true)] [string] $ComputerName, [Parameter (Mandatory = $false)] [string] $DiskDrive = "c" ) Invoke-Command -ComputerName $ComputerName -ScriptBlock {"rescan", "select volume=$using:DiskDrive", "extend" | diskpart} } Меняется лишь папка, в которую сохраняется файл, и его расширение.Очень важно! Внутри папки Modules необходимо создать подпапку с именем нашего модуля. Пусть этим именем будет RemoteDiskManagement. Сохраняем наш файл внутрь этой подпапки и даем ему точно такое же имя и расширение .psm1 — получаем файл C:\Users\Administrator\Documents\WindowsPowerShell\Modules\RemoteDiskManagement\RemoteDiskManagement.psm1. Наш модуль готов, и мы можем проверить, что он виден в системе:

Модуль виден, и в дальнейшем мы можем вызывать его функции без предварительного объявления их в теле скрипта или дотсорсинга.PowerShell будет воспринимать нашу функцию ExtendDisk-Remotely как «встроенную» и подключать ее по мере необходимости:

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

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

Интересно? Тогда попробую выдавать по одной статье в неделю.

habr.com

Функции и фильтры в 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.

steptosleep.ru

powershell - Как я могу создать главную функцию PowerShell?

Я использовал много языков сценариев в прошлом, и теперь изучаю PowerShell. На этих других языках я обычно определяю свою основную логику до определения моих функций, поэтому кто-то, читающий код, сначала сосредоточится на основной логике. Часто это принимает форму создания "главной" функции или класса в верхней части файла и вызывая ее внизу.

В PowerShell этот шаблон может выглядеть так:

$main = { ... do-something ... } function do-something() { <function definition here> } & $main

Это хорошо работает, но теперь я хочу использовать возможности PowerShell для удаленного запуска кода. Поскольку $main является объектом PowerShell ScriptBlock, я [думаю, я] могу запустить этот код на удаленной машине следующим образом:

Invoke-Command -ScriptBlock $main -ComputerName whatever;

Однако удаленная машина ничего не узнает о моей функции, так как она определена вне области $main. Я могу, конечно, переместить определение функции в $main, но тогда я должен поставить ее выше основной логики, и я вернусь к своей первой проблеме.

Существует ли общий шаблон для написания сценариев PowerShell, где основная логика находится в функции или script в верхней части файла, похожая на многие традиционные языки? Как люди пишут сложные скрипты - всегда ли они просто пишут их сверху вниз, посыпая функциями по мере необходимости вверху?

Кто-то отметил это как возможный дубликат вопроса Почему мне нужно, чтобы мои функции записывались сначала в моей Powershell script?. Это не дубликат этого. Я знаю, почему функции должны быть определены в первую очередь - я программировал, так как C был классным новым языком.

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

Есть ли общий шаблон для размещения блока main в верхней части powershell script? Синтаксис и идиомы Powershell достаточно отличаются от более традиционных языков и даже многих популярных современных языков сценариев, что шаблон для перемещения основной логики к вершине не является очевидным (или, может быть, и есть, но я просто не нашел правильных примеров или документации)

qaru.site

powershell - Загрузите все функции в PowerShell из определенного каталога

Предположим, вы системный администратор, который использует PowerShell для управления множеством вещей в своей системе.

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

Я написал функцию, которая делает это для меня. Я размещаю его здесь, потому что я хочу быть уверенным в его надежности. Сама функция хранится в allFunctions.ps1, поэтому я исключаю ее в код.

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

. .\allFunctions.ps1

Содержимое этого script таково:

[string]$items = Get-ChildItem -Path . -Exclude allFunctions.ps1 $itemlist = $items.split(" ") foreach($item in $itemlist) { . $item }

Этот script будет сначала собирать каждый файл в вашем каталоге, то есть все файлы, отличные от ps1, которые у вас могут быть там. allFunctions.ps1 будет исключен.

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

Предположим, что у вас более 100 функций, и вы никогда не знаете, какие из них вам понадобятся, а какие нет? Почему бы им не вводить их вместо того, чтобы делать nitpicking?

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

qaru.site