Как передать несколько параметров в функцию в PowerShell? Функции powershell


Создание пользовательских функций PowerShell | Windows IT Pro/RE

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

Создание функции

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

function {}

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

function FileSize1 {    dir C:Windows |    where {$_.length –gt 100000} }

Обратите внимание, что при вводе нескольких строк на консоли строки нужно разделять, нажимая клавишу Enter. При этом в начале новой строки отображается запрос ввода >>, означающий, что ввод исполняемого предложения не завершен и необходимо продолжить его. Завершив ввод определения функции, нажмите Enter дважды, чтобы вернуться в обычный режим ввода команд (>).

В приведенном примере видно, что определение функции начинается с ключевого слова function, за которым следует имя функции. Фрагмент кода включает две команды в одном конвейере обработки. Первая команда использует команду Get-ChildItem, представленную псевдонимом dir, для получения содержимого папки C:Windows. Результаты запроса передаются по конвейеру второй команде, которая использует команду Where-Object, представленную псевдонимом where, для фильтрации файлов таким образом, чтобы вернуть в результате только файлы объемом более 100 000 байт.

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

FileSize1

При нажатии клавиши Enter PowerShell выполняет код, включенный в тело функции, и возвращает результат, показанный на экране 1. Это тот же результат, который мы получили бы, введя исполняемые предложения из тела функции в командной строке PowerShell.

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

Обработка аргументов вызова

Одним из способов обработки входных параметров является использование встроенной в PowerShell переменной $args. При вызове функции в PowerShell можно передавать значения аргументов, вводя их сразу после имени функции через пробел. Если PowerShell не удается поставить эти значения в соответствие именованным параметрам функции, они автоматически сохраняются в массиве $args. Значения из этого массива можно обработать в теле функции.

Например, следующее определение функции использует $args:

function FileSize2 {    dir $args [0] |    where {$_.Length -gt 100000} }

Обратите внимание, что первая команда в фрагменте сценария обрабатывает первое значение ($args [0]) из массива $args, а не «зашитое» в коде значение (C:Windows). В результате при вызове функции FileSize2 PowerShell использует первый аргумент из введенной строки вызова для определения папки. Если указать более одного аргумента для этой функции, PowerShell проигнорирует избыточные аргументы, как не обрабатываемые данной функцией.

Для вызова функции FileSize2 нужно просто ввести ее имя и через пробел — путь к папке:

FileSize2 C:Windows

Получив эту команду, Windows PowerShell вызывает нашу функцию, подставляет вместо $args [0] значение C:Windows и возвращает полученные данные о файлах в этой папке, так же как на экране 1. Имейте в виду, что если в пути к папке есть пробелы, то весь путь нужно заключить в кавычки.

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

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

function FileSize3 ($dir, $minSize) {    dir $dir |    where {$_.length -gt $minsize} }

Здесь определены два именованных параметра: $dir и $minSize. Тело функции использует эти параметры для поиска обрабатываемой папки и порогового значения размера файла в байтах соответственно.

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

FileSize3-ir C:Windows    –minSize 100000

Обратите внимание, что в данном случае мне пришлось использовать обратный апостроф (`) для указания второго атрибута на отдельной строке.

При вызове функций с именованными аргументами PowerShell выполняет код функции, заменяя имена параметров в теле функции значениями аргументов вызова. Например, PowerShell заменяет $minSize значением 100000. Затем PowerShell возвращает набор результатов, полученных в ходе работы фрагмента сценария, как показано на экране 2.

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

FileSize3 C:Windows 100000

возвращает тот же результат, что и команда в предыдущем примере.

Определение значений параметров по умолчанию

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

function FileSize4    ($dir=»C:WindowsSystem32»,       $minSize=1000000) {    dir $dir |    where {$_.Length -gt $minSize} }

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

FileSize4

Как показано на экране 3, PowerShell при этом автоматически подставляет значения по умолчанию вместо параметров в теле функции.

Вместо значений по умолчанию при необходимости можно использовать любые другие:

FileSize4 C:Windows 500000

Функция возвращает данные, показанные на экране 4, исходя из указанных значений.

Можно также одни аргументы указать при вызове функции, а другие не указывать. Например, следующая команда передает значение первого параметра ($dir), но не определяет значение второго ($minSize):

FileSize4 C:Windows

При выполнении этой команды для $dir будет использоваться значение C:Windows и заданное в определении функции значение для параметра $minSize. В итоге набор результатов будет содержать список файлов размером более 1 000 000 байт в папке C:Windows.

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

FileSize4-minSize 500000

Функция будет использовать предопределенное значение для $dir и значение 500 000 для $minSize, выводя список файлов размером более 500 000 байт, расположенных в папке C:Windowssystem32. Получив только значение 500000 без имени параметра, PowerShell пришлось бы это значение использовать в качестве параметра $dir, поскольку первым аргументом в определении функции указан $dir. Именно поэтому необходимо было указать имя аргумента.

Типизация аргументов вызова

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

function FileSize5    ([string] $dir="C:Windows",       [int] $minSize=1000000) {    dir $dir |    where {$_.Length -gt $minSize} }

Теперь $dir определен как аргумент типа String, а $minSize — как Int32. Если попытаться задать значение неприводимого типа для одного из аргументов, мы получим сообщение об ошибке. Например, следующая команда задает значение типа String для целочисленного аргумента $minSize:

FileSize5-minSize file

Как показано на экране 5, результатом выполнения будет ошибка, поскольку PowerShell не может преобразовать строковое значение «file» к типу Int32.

Работа с функциями

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

$files = FileSize5 C:Windows 500000 foreach ($file in $files)    {       $file.Name + " is " +          $file.Length + " bytes." }

Этот код использует функцию FileSize5 для получения списка файлов и помещения этого списка в переменную $files. Данная переменная затем используется в качестве коллекции в цикле foreach для вывода имен и размеров файлов, как показано на экране 6.

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

FileSize5 C:Windows 500000 | foreach {$_.name + " is " +    $_.length + " bytes."}

Результаты вызова функции при этом передаются команде ForEach-Object, представленной псевдонимом foreach, которая выводит информацию о каждом из файлов, как показано на экране 7.

Заглянем вперед

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

Роберт Шелдон ([email protected]) — технический консультант и автор книг по технологиям Microsoft Windows и базам данных

Экран 1. Создание и результат выполнения функции FileSize1

Экран 2. Добавление именованных параметров вызова функции

Экран 3. Определение значений по умолчанию для параметров

Экран 4. Использование аргументов вызова для переопределения значений параметров

Экран 5. Жесткая типизация параметров функции

www.osp.ru

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

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

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

function FunctionName ($arg1, $arg2, $argN) { scriptoblock }

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

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

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

function abc ($a, $b, $c) { Write-Host '$a = ' $a Write-Host '$b = ' $b Write-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]:

function abc ($a, $b, [switch]$parameter) { Write-Host '$a = ' $a Write-Host '$b = ' $b Write-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 используются так же, как и функции:

filter FilterName ($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.

www.sysadmins.lv

PowerShell. Пользовательские функции для пользователей / Хабр

Привет! Довольно часто в своей работе приходиться пользоваться самостоятельно написанными функциями и таскать куски кода между разными скриптами. На Хабре уже есть довольно хорошая статья про Повторное использование кода от Mroff, но была необходимость пойти немного дальше, задокументировать и как-то описать свои функции. Как оказалось, поиск выдавал довольно сухую информацию в основном по общей структуре функции и не более того. Упорство было вознаграждено, и я решил поделиться полученной информацией. Добро пожаловать под кат, где мы научимся вносить в свои функции информацию для потомков и коллег. Давайте для начала разберем стандартную структуру функции в PowerShell. Выглядит она следующим образомFunction TestPath ([String]$Path) { Return(Test-Path $Path) } В общем то ничего сложного, как и в других языках задали имя TestPath, в круглых скобках через запятую скормили переменные $Path, выполнили в теле функции необходимые действия и при необходимости вернули Return() значение. А как быть, когда нужно работать с несколькими переменными? Выходов всегда больше одного – постоянно давать мнемонические коды или делать описание переменной, давайте рассмотрим, как это делается:Function TestPath { PARAM ( [PARAMETER(Mandatory=$True,Position=0,HelpMessage = "Путь до проверяемого ресурса",ParameterSetName='Path')]$Path ) Return(Test-Path $Path) } Сложности никакой нет, но появились дополнительные параметры, которые нам упрощают жизнь:Mandatory – Принимает два значения True обязательный для заполнения и False необязательный; HelpMessage – Справка по переменной; ParameterSetName – Имя переменной к которой относятся данные параметры; Position – Позиция переменной при вызове функции; Вроде бы все хорошо теперь у нас есть переменная, у которой есть описание, но для того что бы его узнать необходимо выполнить следующий код:((Get-Command TestPath).ParameterSets.Parameters | Where-Object Name -eq Path).HelpMessage PowerShell ответит нам одной строкой в которой будет написано: Путь до проверяемого ресурса.

В какой-то степени удобно, но если мы привыкли работать с PowerShell, то знаем команду Get-Help которая выводит подробную информацию о функции с примерами ее использования и переменными, которые необходимо передавать.

Немного усложним задачу и подготовим функцию информация о которой по запросу Get-Help будет выводиться в полном объеме:

Function WriteToLog { <# .SYNOPSIS Вывод сообщения в консоль и в файл лога. .DESCRIPTION Данная функция выводит переданную строку в лог файл и в консоль PowerShell .EXAMPLE #WriteToLog -Str "Данное сообщение будет выведено в консоль красным цветом и в файл C:\Log\log.txt" -FileName 'C:\Log\log.txt' -Color Red .EXAMPLE #WriteToLog -Str "Данное сообщение будет выведено в консоль цветом по умолчанию (White) и в файл C:\Log\log.txt" -FileName 'C:\Log\log.txt' .PARAMETER Str Строка, которую необходимо вывести (обязательный параметр) .PARAMETER FileName Имя файла лога (обязательный параметр) .PARAMETER Color Цвет текста сообщения в консоли PowerShell (По умолчанию цвет текста белый (White)) #> param ( [PARAMETER(Mandatory=$True,Position=0)][String]$Str, [PARAMETER(Mandatory=$True,Position=1)][String]$FileName, [PARAMETER(Mandatory=$False,Position=2)][String]$Color='White' ) Write-Host $Str -ForegroundColor $Color If ((Test-Path $FileName) -eq $True) { Add-Content -Path $FileName -Value $Str } Else { Set-Content -Path $FileName -Value $Str } } После выполнения данного кода команда Get-Help 'WriteToLog' -ShowWindow выведет нам следующее окно. Давайте разберем что же мы такого написали:<##> – В данном блоке написаны параметры для справки PowerShell. .SYNOPSIS – блок для краткого описание функции .DESCRIPTION – блок для полного описание функции .EXAMPLE – блок для примера использования функции, может быть несколько .PARAMETR Имя параметра – блок для описания переменной, для каждой переменной свой блок. Как вы могли заметить текстовый комментарий начинается со следующей строки после ключевого названия раздела и может быть многострочным. Окончанием комментария считается закрывающий тег #> или следующий блок.

param () – блок для описания переменных, в котором мы указали их порядок и необходимость передачи параметров при вызове функции. Для переменной $Color мы присвоили значение по умолчанию'White'.

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

Спасибо что дочитали до конца.

habr.com

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

Если Вы думаете что функция PowerShell возвращает значение только через оператор return, то Вам сюда.

Текст про грабли связанные с самоорганизующимися потоками передачи данных (пайпами). И эта фишка портит кровь довольно сильно, т.к. налетаешь на нее с завидной регулярностью.

Для начала простейший пример:

function test($param) { $x = 5 "string" 1 2 return $x }

Вот такая странноватая функция. Вопрос – что вернет?Нет, не 5. Вернет список, точнее массив:@(“string”, 1, 2, 5).

А все потому, что любое “брошенное” (никуда не присвоенное) значение или переменная отправляются на “стандартный вывод”, а в случае с функцией – в ее выходные значения. Это кстати очень удобно, когда нужно вернуть несколько значений, но и проблем доставляет множество. При этом наличие return вообще ни какой роли не играет, но я все равно его пишу чисто для читаемости кода.

Вот еще один кейс – возврат массивов.

function test() { $x = @("hello world", "test") # определили массив из двух элементов return $x }

Вызовем функцию и узнаем тип возврата и первый элемент:(test).GetType().Name(test)[0]

Получили логичные:Object[]“hello world”

А теперь чуть изменим код (оставили в массиве один элемент):

function test() { $x = @("hello world") # определили массив из одного элемента return $x }

И снова вызываем, узнаем тип и первый элемент:(test).GetType().Name(test)[0]

И получаем внезапные:String“h”

PowerShell сумничал и для нашего “удобства” конвертнул массив из одного элемента в значение этого элемента. Что бы такого не происходило, при возврате массива (либо его получения на принимающей стороне) надо писать запятую перед значением, например так:

function test() { $x = @("hello world") # определили массив из одного элемента return ,$x }

Или так:$a = ,(test)

В общем-то эта чудесная фича касается только массивов, я не знаю зачем так сделали и это явн

vms11.wordpress.com

powershell - Как передать несколько параметров в функцию в PowerShell?

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

function Get-Something { Param ( [Parameter(Mandatory=$true, Position=0)] [string] $Name, [Parameter(Mandatory=$true, Position=1)] [int] $Id ) }

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

Get-Something -Id 34 -Name "Blah" Get-Something "Blah" 34

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

PowerShell также имеет возможность определять наборы параметров. Он использует это вместо перегрузки метода и снова весьма полезен:

function Get-Something { [CmdletBinding(DefaultParameterSetName='Name')] Param ( [Parameter(Mandatory=$true, Position=0, ParameterSetName='Name')] [string] $Name, [Parameter(Mandatory=$true, Position=0, ParameterSetName='Id')] [int] $Id ) }

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

Get-Something "some name" Get-Something 23 Get-Something -Name "some name" Get-Something -Id 23

Вы также можете назначить дополнительные параметры для различных наборов параметров. (Очевидно, это был довольно простой пример). Внутри функции вы можете определить, какой набор параметров использовался с свойством $PsCmdlet.ParameterSetName. Например:

if($PsCmdlet.ParameterSetName -eq "Name") { Write-Host "Doing something with name here" }

Затем, в соответствующей заметке, есть также проверка параметров в PowerShell. Это одна из моих любимых функций PowerShell, и она делает код внутри ваших функций очень чистым. Существуют многочисленные проверки, которые вы можете использовать. Несколько примеров:

function Get-Something { Param ( [Parameter(Mandatory=$true, Position=0)] [ValidatePattern('^Some.*')] [string] $Name, [Parameter(Mandatory=$true, Position=1)] [ValidateRange(10,100)] [int] $Id ) }

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

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

Еще один полезный метод - ValidateSet, который позволяет вам явно определять массив допустимых значений. Если что-то еще введено, будет выбрано исключение. Есть и другие, но, вероятно, наиболее полезным является ValidateScript. Это занимает блок script, который должен оцениваться до $true, поэтому небо является пределом. Например:

function Get-Something { Param ( [Parameter(Mandatory=$true, Position=0)] [ValidateScript({ Test-Path $_ -PathType 'Leaf' })] [ValidateScript({ (Get-Item $_ | select -Expand Extension) -eq ".csv" })] [string] $Path ) }

В этом примере мы уверены не только в том, что $Path существует, но в том, что это файл (в отличие от каталога) и имеет расширение .csv. ($ _ относится к параметру, когда внутри вашего скриптового блока.) Кроме того, вы можете передавать гораздо большие многострочные блоки script, если требуется этот уровень, или использовать несколько скриптовых блоков, подобных мне. Это чрезвычайно полезно и обеспечивает отличные чистые функции и интуитивные исключения.

qaru.site

powershell - Обработка конвейера и ввода параметров в функции Powershell

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

Я даже догадаюсь, что второй пример не работает. По крайней мере, я не мог заставить его работать.

Возьмите этот пример...

function PipelineMadness() { [cmdletbinding()] param ( [Parameter(Mandatory = $true, ValueFromPipeline=$true)] [int[]] $InputArray ) Write-Host ('$InputArray.Count {0}' -f $InputArray.Count) Write-Host $InputArray Write-Host ('$input.Count {0}' -f $input.Count) Write-Host $input if($input) { Write-Host "input is true" } else { Write-Host "input is false" } }

результаты...

PS C:\Windows\system32> 1..5 | PipelineMadness $InputArray.Count 1 5 $input.Count 5 1 2 3 4 5 input is true PS C:\Windows\system32> PipelineMadness (1..5) $InputArray.Count 5 1 2 3 4 5 $input.Count 1 input is false

Обратите внимание, что при использовании конвейера переменная $InputArray представляет собой одно значение 5...

Теперь с блоками BEGIN и PROCESS

function PipelineMadnessProcess() { [cmdletbinding()] param ( [Parameter(Mandatory = $true, ValueFromPipeline=$true)] [int[]] $InputArray ) BEGIN { Write-Host 'BEGIN' Write-Host ('$InputArray.Count {0}' -f $InputArray.Count) Write-Host $InputArray Write-Host ('$input.Count {0}' -f $input.Count) Write-Host $input if($input) { Write-Host "input is true" } else { Write-Host "input is false" } } PROCESS { Write-Host 'PROCESS' Write-Host ('$InputArray.Count {0}' -f $InputArray.Count) Write-Host $InputArray Write-Host ('$input.Count {0}' -f $input.Count) Write-Host $input if($input) { Write-Host "input is true" } else { Write-Host "input is false" } } }

Теперь это то, где он становится странным

PS C:\Windows\system32> 1..5 | PipelineMadnessProcess BEGIN $InputArray.Count 0 $input.Count 0 input is false PROCESS $InputArray.Count 1 1 $input.Count 1 1 input is true PROCESS $InputArray.Count 1 2 $input.Count 1 2 input is true ... PROCESS $InputArray.Count 1 5 $input.Count 1 5 input is true

Блок BEGIN вообще не содержит никаких данных. И блок процесса хорошо работает, если у вас есть foreach, как в примере, который он действительно будет работать, но он будет запускать foreach с 1 входом X раз. Или, если вы пройдете в массиве, он будет запускать foreach один раз с полным набором.

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

Также обратите внимание, что даже если блок BEGIN не имел данных, функция прошла проверку синтаксиса.

qaru.site

PowerShell для программиста. Передача параметров в функцию.

PowerShell для программиста. Передача параметров в функцию.

Posted by vms11 on 14.12.2014

Лично для меня PowerShell (PoSh)– это не шел, а скорее средство быстрой разработки под .NET. Он очень могуч (и вообще прекрасен), но имеет и ряд особенностей.

В интернете есть кучи описаний по языку, но почему-то на особо засадные вещи внимание не обращается. Поэтому напишу только о них. А как 2+2 сделать, думаю без проблем найдется где угодно.

Итак, синтаксис PowerShell традиционен, т.е. си-подобный (или php-подобный, или perl-подобный). И эта схожесть дает ложную уверенность, что все можно делать привычными конструкциями. И ведь можно, в смысле ругаться PoSh не станет, но и работать оно тоже не будет. Или хуже – иногда будет, а иногда нет.

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

  • вызов функций всегда делать в стиле командной строки – ключами, а не традиционно в скобках, в PoSh скобки для другого
  • пайпы (потоки ввода/вывода) есть везде, даже если кажется что их нет
  • условия пишутся не угловыми скобками, а ключами : -lt, -gt, -eq, … (JS style)
  • при возврате коллекции из функции, может произойти преобразование к другому типу, если не позаботиться об обратном

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

Дальше подробно распишу про типовые ошибки с передачей параметров (точнее особенностями синтаксиса PowerShell) и заодно будет понятно:

  • как передавать типизированные и не типизированные значения
  • как устанавливать значение параметра по-умолчанию
  • как передавать значение по ссылке [ref]
  • как передавать в параметре другую функцию или произвольный код (например для callback)

Сначала просто про базовый синтаксис на примере:

function hello($name) { write-host "Hello, $name" } hello("Вася") # традиционный синтаксис вызова функции (неправильно) hello -name "Вася" # вызов в стиле PowerShell (правильно)

Оба варианта вызова в данном случае будут ра

vms11.wordpress.com