Powershell функции: Создание функций Powershell и команды с вызовом и передачей параметров

Содержание

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’.

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

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

Создание и использований функций PowerShell

Обновлено 18. 05.2022

Добрый день! Уважаемые читатели и гости одного из крупнейших IT блогов рунета Pyatilistnik.org. В прошлый раз мы с вами очень подробно разобрали, как производится подключение к удаленному рабочему столу в разных операционных системах. Сегодня я вам так же хочу упростить жизнь и научить классным возможностям PowerShell. Мы научимся бороться с рутиной, созданием и использованием функций PowerShell, которые войдут в вашу жизнь так, что вы уже больше не сможете без них представить свое рабочее окружение, ведь проще запомнить одну команду, чем вспоминать, где располагаются ваши скрипты, какое у них имя и так далее.

Что такое функции PowerShell?

Функция — это список операторов Windows PowerShell, которым присвоено имя. Когда вы запускаете функцию, вы вводите имя функции. Операторы в списке запускаются так, как если бы вы ввели их в командной строке. Я бы сказал: внутри функции вы можете размещать коды, операторы, параметры и так далее. У этой функции есть имя.  И это имя используется для запуска вашей функции.

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

Подробнее об этом можно прочитать в справке MS:

  • https://docs.microsoft.com/ru-ru/powershell/scripting/learn/ps101/09-functions?view=powershell-7.1
  • https://docs.microsoft.com/ru-ru/powershell/module/microsoft.powershell.core/about/about_functions?view=powershell-7.1

Представим себе ситуацию, что у вас есть какие-то повседневные задачи, которые вы решаете через скрипты PowerShell, например:

  • Часто ищите ID сессии пользователя на RDS ферме
  • Ищите события блокировки пользователя в Active Directory
  • Тестируете репликацию Active Directory
  • Или доступность основного шлюза

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

Как создавать функции в PowerShell

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

Итак, обо всем по порядку, нам нужно определить, как мы будем запускать delprof2. Для моей функции я решил, что у меня будет стандартное расположение .exe и сделать его необязательным параметром:

Param (

[string]$delprof2 = «c:\windows\system32\delprof2.exe»
)

Я выбрал system32, потому что это начальный путь по умолчанию для PowerShell с повышенными привилегиями, но выберите то, что вам подходит. Чтобы фактически запустить delprof2, мы теперь используем амперсанд &, который является оператором вызова, например:

& $delprof2 ‘/l’

Затем, чтобы получить результат, нам нужно присвоить его переменной:

$output = & $delprof2 ‘/l’

Получив результат, мы воспользуемся foreachциклом для анализа каждой строки, чтобы увидеть, что она собой представляет. \\]+\\)+(?<profile>\S+))»)

Это дает нам больше полезных данных, которые мы можем использовать в возвращаемом объекте:

[pscustomobject]@{
Ignored = $false
Reason = $null
ProfilePath = $Matches.ProfilePath
Profile = $Matches.Profile
}

Поскольку нам действительно нужно иметь возможность определять параметры для этой функции и мы также хотим иметь возможность принимать ввод с некоторыми параметрами. Для paramблока мы можем начать с (Parameter()для краткости исключаю настройки):

param (
[string]$Name
,
[string[]]$Include
,
[string[]]$Exclude
,
[int]$OlderThan
)

Так что нам понадобится пара циклов foreach, чтобы получить все переключатели в массиве:

$switches = & {
«/l»
if ($PSBoundParameters.ContainsKey(‘Include’)) {
foreach ($inc in $include) {
«/id:$inc»
}
}
if ($PSBoundParameters.ContainsKey(‘Exclude’)) {
foreach ($exc in $exclude) {
«/ed:$exc»
}
}
if ($PSBoundParameters. ContainsKey(‘OlderThan’)) {
«/d:$OlderThan»
}
}

Затем, поскольку мы запускаем его на удаленном компьютере, мы должны проверить возможность подключения, все же вы знакомы с командой ping:

if ($PSBoundParameters.ContainsKey(‘Name’) -and ($Name -ne $env:COMPUTERNAME)) {
if (Test-Connection $Name -Count 1 -Quiet) {
$computer += «/c:$Name»
} else {
Throw «Cannot ping $name»
}
}

И теперь наша команда будет выглядеть так:

$return = & $delprof2 $computer $switches

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

Финальная версия созданной функции PowerShell

Теперь все объединим в единую функцию PowerShell.

Function Get-InactiveUserProfiles {
[cmdletbinding()]
param (
[Parameter(
Position = 1,
ValueFromPipeline = $true,
ValueFromPipelineByPropertyName = $true
)]
[Alias(‘Computer’,’ComputerName’,’HostName’)]
[ValidateNotNullOrEmpty()]
[string]$Name = $env:COMPUTERNAME
,
[Parameter()]
[string[]]$include # Supports ? and *
,
[Parameter()]
[string[]]$exclude # Supports ? and *
,
[Parameter()]
[int]$olderThan
,
[string]$delprof2 = «c:\windows\system32\delprof2. \’]+))\'») {
# Access denied
[pscustomobject]@{
Ignored = $true
Reason = ‘Access denied’
ProfilePath = $Matches.ProfilePath
Profile = $Matches.Profile
ComputerName = $Name
}
}
}
}
End{}
}

Как запускать функцию PowerShell?

Тут два варианта запуска:

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

[info]Import-Module C:\Scripts\delprof.ps1 -Force[/info]

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

  • Второй вариант, это создание и использование модуля

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

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

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

Узнайте какая у вас версия PowerShell

Например, давным-давно вам нужно было импортировать модуль Active Directory, чтобы использовать команды PowerShell Active Directory. Выглядит это вот так:

Import-Module ActiveDirectory -Verbose

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

Чтобы показать все модули, которые установлены и могут быть импортированы, запустите

Get-Module -ListAvailable

Модули хранятся в папке

C:\Windows\system32\WindowsPowerShell\v1.0\Modules

  • Папка по умолчанию для модулей, поставляемых с Windows — cd $PSHome\Modules — Не рекомендуется сохранять здесь свой модуль.
  • Папка модулей для всех пользователей — cd $Env:ProgramFiles\WindowsPowerShell\Modules
  • Папка модулей для текущего пользователя — cd $Home\Documents\WindowsPowerShell\Modules

Как сохранить свою функцию как модуль сценария

Откройте PowerShell ISE, щелкните «Файл» и выберите «Сохранить». Чтобы сделать вашу функцию доступной для всех пользователей, сохраните ее в ProgramFiles\WindowsPowerShell\Modules\Get-InactiveUserProfiles.

Это означает, что вы должны создать там папку с тем же именем, что и ваш файл. Выберите Тип psm1.

Щелкните Сохранить. Закройте все сеансы PowerShell. Снова откройте PowerShell и запустите Get-Module, чтобы просмотреть новый модуль сценария.

Get-Module -ListAvailable

А вот и ваш новый модуль и его функция:

Get-Command -Module Get-InactiveUserProfiles | Format-List

Начиная с PowerShell 3. 0 ваш модуль импортируется автоматически, а это означает, что ваша команда доступна мгновенно. Нет необходимости импортировать ваш модуль. Теперь мы можем проверять наличие неактивных профилей пользователей локально или удаленно! Давай попробуем, чтобы проверить локальный компьютер введите:

Get-InactiveUserProfiles | Format-Table

Или если бы мы хотели получить только те профили, которые начинаются с «А» и не использовались более 20 дней:

Get-InactiveUserProfiles -Include ‘А*’ -OlderThan 20 | Format-Table

Помните, что мы можем принимать как входные, так и выходные объекты конвейера? Да, так что мы можем сделать несколько довольно интересных вещей, например, если вам нужно очистить профиль на нескольких компьютерах:

Get-ADComputer -Filter {Name -like ‘RDCB*’} | Get-InactiveUserProfiles -Exclude ‘Administrator’ -OlderThan 10 | Where-Object {-not $_.Ignored}

Это будет список профилей со всех компьютеров, возвращенных в этом запросе к AD, которые не являются профилем Administrator и не были использованы в течение 10 дней.  Обратите внимание, что я использую командлет Where-Object для фильтрации только тех профилей, которые соответствуют этим критериям. Так что вы даже можете использовать Export-Excelи при необходимости создать хороший отчет для руководителя.

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

Get-Content C:\path\to\comps.txt | Get-InactiveUserProfiles | Where-Object {-not $_.ignored}

Как видите создавать свою функцию и свой модуль PowerShell не так уж и сложно, если вы это освоите, то сможете очень многое для себя улучшить. На этом у меня все, с вами был Иван Семин, автор и создатель IT портала Pyatilistnik.org.

функций — PowerShell — SS64.com

функций — PowerShell — SS64.com

  • SS64
  • PowerShell
  • Практическое руководство

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

Синтаксис функции/фильтра:

  функция  [ scope_type :]  имя 
 {
  [параметр(  список_параметров  ) ]
     скрипт_блок
   } 
  фильтр  [  тип_области  :]  имя 
 {
  [параметр(  список_параметров  ) ]
    скрипт_блок 
 } 

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

В случае обычной функции объекты конвейера привязываются к автоматической переменной $input, и выполнение блокируется до тех пор, пока не будут получены все входные данные. Затем функция начинает обработку данных.

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

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

Примеры

По своей сути функция — это просто ключевое слово function , за которым следует имя функции, а затем некоторый код внутри пары фигурных скобок.

функция Add-Numbers {
 $args[0] + $args[1]
}

PS C:\> Add-Numbers 5 10
15

Аналогичная функция с именованными параметрами:

функция Выходной налог с продаж {
param ( [int]$Price, [int]$Tax )
 $Price + $Tax
}

PS C:\> Output-SalesTax -price 1000 -tax 38
1038

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

функция кошки: Add-Numbers
или
${функция:Add-Numbers}
или
(добавить-команда-номера). определение

Чтобы вывести список всех функций в текущем сеансе: функция get-command -CommandType

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

Не добавляйте скобки вокруг параметров функции:

$result = Add-Numbers (5, 10) —Неправильно!
$result = Add-Numbers 5 10    —Право

Функция автоматически принимает позиционные параметры в том порядке, в котором они объявлены, или вы можете передавать именованные параметры в любом порядке. Это также работает при вызове через псевдоним.

Как запустить функцию

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

функция Add-Numbers {
$args[0] + $args[1]
}
Дополнительные номера 5 10

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

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

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

. C:\Scripts\Tools.ps1
Дополнительные номера 5 10

Другой способ сделать функцию доступной для нескольких сценариев/сеансов — включить ее как часть модуля PowerShell . При сохранении в папке системного модуля или папке пользовательского модуля автоматическое обнаружение командлетов (в PowerShell v3 и выше) гарантирует доступность этих функций.

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

Выберите хорошее имя функции

Встроенные псевдонимы PowerShell будут иметь приоритет над функцией (или сценарием) с таким же именем. Чтобы избежать конфликтов, всегда проверяйте, не используется ли это имя, с помощью help name . Выбор хорошего описательного имени для вашей функции поможет с этим

.

Наилучшей практикой является использование выбора имени в формате Глагол-существительное , поскольку он содержит символ ‘-‘, это не будет конфликтовать ни с какими встроенными псевдонимами. Вы можете создать список утвержденных команд PowerShell, запустив командлет Get-Verb 9.0012

Расширенная функция

Расширенная функция PowerShell содержит атрибут [cmdletbinding()] (или атрибут Parameter). Это добавляет несколько возможностей, таких как дополнительная проверка параметров и возможность легко использовать Write-Verbose.
Функция с привязкой командлетов выдаст ошибку, если в командной строке появятся необработанные значения параметров.

Расширенные функции PowerShell обычно включают блоки Begin..Process..End для обработки входных данных, документации и автоматической помощи, включая параметры.

Переменная область видимости

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

Чтобы сохранить переменную, чтобы функцию можно было вызывать повторно, а переменная сохраняла свое последнее значение, добавьте $script: к имени переменной, например $скрипт:myvar

Чтобы сделать переменную глобальной, добавьте $global: к имени переменной, например $global:myvar

Пример функций

Определите, а затем запустите однострочную функцию для запуска Центра обновления Windows через процесс ms-settings.

PS C:\> function update {Start-Process ms-settings:windowsupdate-action}
PS С:\> обновление

Функция для поиска всех файлов на диске C:, принадлежащих определенному пользователю:

  функция  Get-ByOwner
  { 
   Get-ChildItem -recurse C:\ | получить доступ | где {$_.Owner -match $args[0]}
  } 

PS C:\> Get-ByOwner JackFrost

Функция для отображения справки PowerShell на SS64.com, при этом запускается веб-браузер по умолчанию:

  функция  Get-Help2
  {  
параметр([строка]$команда) Запуск-процесс-путь к файлу "https://ss64.com/ps/$command.html" }

Затем вы можете сделать:
PS C:\> Get-Help2 -command set-acl

или потому что параметр всего один:
PS C:\> Get-Help2 set-acl

Функция со значениями по умолчанию:

  функция  цена записи 
 { 
  параметр  (  [строка] $ описание = "неизвестно",
        [целое]$цена = 100  ) 
  Запись-вывод "$описание . .... $цена"
  } 

PS C:\> напишите-цена -цена 250 -описание Молоток 
Молоток ..... 250

Пример фильтров

Фильтр для отображения только файлов меньше заданного размера:

  фильтр  FileSizeBelow($size)  {  if ($_.length -le ​​$size) { $_ }  }  

PS C:\> gci \\server64\workgroups -filter | FileSizeBelow 200 КБ
PS C:\> gci -recurse \\server64\workgroups | ?{!$_.PSIsContainer} | FileSizeBelow 100 МБ

Создайте фильтр с именем «grep», чтобы найти объекты с заданной текстовой строкой в ​​их выходных данных, возвращая объект PowerShell [через Idera]:

 PS C:\> filter grep ([string]$Pattern) {
    if ((Out-String -InputObject $_) -match $Pattern) { $_ }
} 
PS C:\> Get-Service | работает | Select-Object Name, StartType, Status

Фильтр для поиска файлов, принадлежащих определенному пользователю:

  фильтр  принадлежит мне
  { 
  if ($_. Owner -match "JackFrost") {$_}
  } 

PS C:\> gci -recurse C:\ | Get-Acl | где {$_ |  принадлежит мне  } 

«Функция воображения не в том, чтобы упорядочивать странные вещи, а в том, чтобы делать странными устоявшиеся вещи» ~ Г. К. Честертон

Связанные командлеты PowerShell

Расширенные функции — включают функции командлета, общие параметры —verbose, —whatif, —confirm и т. д.
Утверждения — использование фильтра для утверждения определенных предварительных условий.
New-Alias ​​— создайте новый (короткий) псевдоним для вашей функции.
Начало..Процесс..Конец — Обработка входных данных функции.
Scriptblock — Набор операторов.
Ref vars — Передача ссылочной переменной в функцию.


 

Copyright © 1999-2023 SS64.com
Некоторые права защищены.

Руководство по началу работы с функциями Powershell

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

Не читатель? Посмотрите соответствующий видеоурок!

Не видите видео? Убедитесь, что ваш блокировщик рекламы отключен.

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

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

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

Функции и командлеты

Концепция функции может показаться знакомой, потому что она немного напоминает командлеты, которые вы, вероятно, уже использовали. Такие команды, как Start-Service и Write-Host , например, похожи на функции. Это именованные фрагменты кода, которые решают одну проблему. Разница между функцией и командлетом заключается в том, как создается каждая из этих конструкций.

Командлет не написан с помощью PowerShell. Он написан на другом языке, обычно что-то вроде C#. Затем командлет компилируется и становится доступным внутри PowerShell.

Функции, с другой стороны, написаны в PowerShell; не на другом языке.

Вы можете увидеть, какие команды являются командлетами, а какие функциями, используя Командлет Get-Command и его параметр CommandType , как показано ниже

 Get-Command – Функция CommandType 

Эта вышеприведенная команда возвращает все функции, загруженные в данный момент в сеанс PowerShell или в модули, доступные для PowerShell.

Связано: Понимание и создание модулей PowerShell

Предварительные условия

Если вы хотите следовать всем примерам, убедитесь, что у вас есть доступная версия PowerShell. Для этого руководства нет конкретных требований к версии. Кроме того, убедитесь, что у вас есть хороший редактор кода, такой как Visual Studio Code, для копирования, вставки и запуска некоторых фрагментов кода.

Создание простой функции

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

Ниже вы можете увидеть базовую функцию и выполнение этой функции. Эта функция, называемая Install-Software , использует Write-Host для отображения сообщения в консоли. После определения вы можете использовать имя этой функции для выполнения кода внутри ее блока сценария.

 PS> function Install-Software { Write-Host 'Я установил какое-то программное обеспечение. Ура! }
PS>Установка-Программы
Я установил некоторое программное обеспечение, Yippee! 

Именование с глаголом-существительным

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

Имя функции всегда следует начинать с глагола, за которым следует тире и существительное. Чтобы найти список «одобренных» глаголов, используйте Командлет Get-Verb .

Изменение поведения функции

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

 PS> function Install-Software { Write-Host 'Вы установили какое-то программное обеспечение, Ура!' }
PS>Установка-Программы
Вы установили какое-то программное обеспечение, Yay! 

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

Определение расширенной функции

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

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

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

Я предлагаю вам теперь открыть ваш любимый редактор и сохранить функцию в файле .ps1, пока вы работаете с остальной частью учебника.

Добавление параметров к функциям

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

Связано: все, что вы когда-либо хотели знать о параметрах PowerShell

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

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

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

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

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

Создание простого параметра

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

 функция Установка программного обеспечения {
[Привязка командлета()]
параметр()
Write-Host 'Я установил программное обеспечение версии 2.  Ура!'
} 

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

На данный момент функция фактически не устанавливает какое-либо программное обеспечение. Просто используется командлет Write-Host для имитации установки программного обеспечения, чтобы вы могли сосредоточиться на написании функции.

После добавления блока param можно создать параметр, поместив его в скобки блока param , как показано ниже.

 функция Установка программного обеспечения {
[Привязка командлета()]
параметр(
[Параметр()]
[строка] $Версия
)

Write-Host "Я установил программу версии $Version. Yippee!"
} 

Внутри блока param выше вы должны сначала определить блок Parameter. Использование такого блока Parameter() превратит его в «расширенный параметр». Пустой блок параметров, подобный приведенному здесь, ничего не делает, но требуется; Я объясню, как его использовать в следующем разделе.

Вместо этого давайте сосредоточимся на типе [string] перед именем параметра. Помещая тип параметра в квадратные скобки перед именем переменной параметра, вы приводите значение параметра к определенному типу. PowerShell всегда будет пытаться преобразовать любое значение, переданное этому параметру, в строку, если это уже не так. Выше все прошло как $Version всегда будет рассматриваться как строка.

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

Теперь вы также добавляете $Version в свой оператор Write-Host . Это означает, что когда вы запускаете функцию Install-Software с параметром Version и передаете ей номер версии, вы должны получить заявление, говорящее об этом, как показано ниже.

 PS> Установка-Программное обеспечение-Версия 2
Я установил программу версии 2. Ура! 

Посмотрим, что теперь можно сделать с этим параметром.

Обязательный атрибут параметра

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

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

 функция Установка ПО {
[Привязка командлета()]
параметр(
[Параметр (Обязательный)]
[строка]$Версия
)
Write-Host "Я установил программу версии $Version. Yippee!"
} 

Если вы запустите указанную выше функцию, вы должны получить следующее приглашение:

Запрос обязательного параметра

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

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

 Install-Software -Version 2 

Значения параметров по умолчанию

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

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

 функция Установка программного обеспечения {
[Привязка командлета()]
параметр(
[Параметр()]
[строка]$Версия = 2
)
Write-Host "Я установил программу версии $Version.  Yippee!"
} 

Наличие параметра по умолчанию не мешает вам передать его. Ваше переданное значение переопределит значение по умолчанию.

Добавление атрибутов проверки параметров

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

Ограничение информации, которую пользователи (или даже вы!) можете передать вашим функциям или сценариям, устранит ненужный код внутри вашей функции. Например, предположим, что вы передаете значение 3 своей функции Install-Software , зная, что версия 3 является существующей версией.

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

Срок службы без проверки параметров

Ознакомьтесь с приведенным ниже примером использования строки $Version в пути к файлу. Если кто-то передаст значение, которое не дополняет существующее имя папки (например, SoftwareV3 или SoftwareV4), код не будет выполнен.

 функция Установка ПО {
параметр(
[Параметр (Обязательный)]
[строка]$Версия
)
Get-ChildItem -Path \\SRV1\Installers\SoftwareV$Version
}
 

Ошибка при непредвиденных значениях параметров

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

Добавление проверки параметров

Существуют различные виды проверки параметров, но в отношении вашего Install-Software , лучше всего работает [атрибут ValidateSet ] (https://adamtheautomator.com/powershell-validateset/). Атрибут проверки ValidateSet позволяет указать список допустимых значений для параметра. Если вы учитываете только строку 1 или 2 , вы должны убедиться, что пользователь может указать только эти значения; в противном случае функция немедленно завершится ошибкой и уведомит пользователя о причине.

Добавить атрибуты проверки параметров внутри 9Блок 0310 param , прямо под исходным блоком Parameter , как показано ниже.

 функция Установка программного обеспечения {
параметр(
[Параметр (Обязательный)]
[ПроверитьНабор('1','2')]
[строка]$Версия
)
Get-ChildItem -Path \\SRV1\Installers\SoftwareV$Version
} 

Добавив набор элементов ( 1 и 2 ) в завершающие круглые скобки атрибута ValidateSet , это сообщает PowerShell, что единственными допустимыми значениями для версии являются 1 или 2 . Если пользователь попытается передать что-то помимо того, что находится в наборе, он получит сообщение об ошибке, как показано ниже, уведомляющее его о том, что у него есть только определенное количество доступных вариантов.

Проверка параметров останавливает выполнение функции PowerShell

Атрибут ValidateSet является общим атрибутом проверки, но доступны и другие. Полную информацию обо всех способах ограничения значений параметров см. в документации Microsoft.

Принятие входных данных конвейера

До сих пор вы создали функцию с параметром, который можно передать только с использованием типичного синтаксиса -ParameterName . Это работает, но у вас также есть другой вариант передачи значений параметрам с помощью конвейера PowerShell. Давайте добавим возможности конвейера в нашу функцию Install-Software.

Связано: Принятие входных данных конвейера в параметрах ATA PowerShell Статья

Сначала добавьте в код еще один параметр, указывающий компьютер, на который вы хотите установить программное обеспечение. Кроме того, добавьте этот параметр в свой Ссылка Write-Host для имитации установки.

 функция Установка программного обеспечения {
параметр(
[Параметр (Обязательный)]
[строка]$Версия
[ПроверитьНабор('1','2')],

[Параметр (Обязательный)]
[строка]$имя_компьютера
)
Write-Host "Я установил программу версии $Version на $ComputerName.  Yippee!"
} 

После того, как вы добавили в функцию параметр ComputerName , вы теперь можете перебирать список имен компьютеров и передавать значения имени компьютера и версии в функцию .0310 Функция Install-Software , как показано ниже.

 $computers = @("SRV1", "SRV2", "SRV3")
foreach ($pc в $computers) {
Install-Software -Version 2 -ComputerName $pc
} 

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

Обеспечение совместимости конвейера функций

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

Функция PowerShell использует два типа входных данных конвейера: ByValue (весь объект) и ByPropertyName (одно свойство объекта). Здесь, поскольку массив $computers содержит только строки, вы передадите эти строки через ByValue .

Чтобы добавить поддержку конвейера, добавьте атрибут параметра к нужному параметру, используя одно из двух ключевых слов: ValueFromPipeline или ValueFromPipelineByPropertyName , как показано ниже.

 функция Установка ПО {
параметр(
[Параметр (Обязательный)]
[ПроверитьНабор('1','2')]
[строка]$Версия,
[Параметр (обязательный, ValueFromPipeline)]
[строка]$имя_компьютера
)
Write-Host "Я установил программу версии $Version на $ComputerName. Yippee!"
} 

После загрузки функции обновления Instal-Software вызовите ее следующим образом:

 $computers = @("SRV1", "SRV2", "SRV3")
$компьютеры | Install-Software -Version 2 

Запустите скрипт еще раз, и вы должны получить что-то вроде этого:

 Я установил программное обеспечение версии 2 на SRV3. Ура! 

Обратите внимание, что Install-Software выполняется только для последней строки в массиве. В следующем разделе вы увидите, как это исправить.

Добавление блока процесса

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

 функция Установка ПО {
параметр(
[Параметр (Обязательный)]
[ПроверитьНабор('1','2')]
[строка]$Версия,
[Параметр (обязательный, ValueFromPipeline)]
[строка]$имя_компьютера
)
процесс {
Write-Host "Я установил программу версии $Version на $ComputerName. Yippee!"
}
} 

Теперь снова вызовите функцию, как вы это делали ранее. Функция Install-Software теперь будет возвращать три строки (по одной для каждого объекта).

 Я установил программное обеспечение версии 2 на SRV1. Ура!
Я установил программное обеспечение версии 2 на SRV2.