Разное

Cmdletbinding: о функциях Кмдлетбиндингаттрибуте — PowerShell

11.11.1970

Содержание

о функциях Кмдлетбиндингаттрибуте — PowerShell

  • Чтение занимает 3 мин

В этой статье

Краткое описание

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

Подробное описание

CmdletBindingАтрибут является атрибутом функций, которые делают их работать как скомпилированные командлеты, написанные на языке C#. Он предоставляет доступ к функциям командлетов.

PowerShell привязывает параметры функций, имеющих атрибут, так CmdletBinding же, как он привязывает параметры скомпилированных командлетов. $PSCmdletАвтоматическая переменная доступна для функций с CmdletBinding атрибутом, но $Args переменная недоступна.

В функциях, имеющих CmdletBinding атрибут, неизвестные параметры и аргументы, которые не имеют соответствующих параметров позиционирования, приводят к сбою привязки параметра.

Примечание

Скомпилированные командлеты используют Cmdlet атрибут Required, который аналогичен CmdletBinding атрибуту, описанному в этом разделе.

Синтаксис

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

{
    [CmdletBinding(ConfirmImpact=<String>,
    DefaultParameterSetName=<String>,
    HelpURI=<URI>,
    SupportsPaging=<Boolean>,
    SupportsShouldProcess=<Boolean>,
    PositionalBinding=<Boolean>)]

    Param ($Parameter1)
    Begin{}
    Process{}
    End{}
}

ConfirmImpact

Аргумент ConfirmImpact указывает, когда действие функции должно быть подтверждено вызовом метода ShouldProcess . Вызов метода ShouldProcess отображает запрос подтверждения, только если аргумент ConfirmImpact равен значению $ConfirmPreference привилегированной переменной или больше него. (Значение аргумента по умолчанию —

Medium.) Указывайте этот аргумент только в том случае, если также указан аргумент SupportsShouldProcess .

Дополнительные сведения о запросах на подтверждение см. в разделе запрос подтверждения.

DefaultParameterSetName

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

HelpURI

Аргумент HelpURI указывает Интернет-адрес интерактивной версии раздела справки, описывающего функцию. Значение аргумента

HelpURI должно начинаться с «http» или «HTTPS».

Значение аргумента HelpURI используется для значения свойства HelpURI объекта CommandInfo , который Get-Command возвращает значение для функции.

Однако если файлы справки установлены на компьютере, а значение первой ссылки в разделе релатедлинкс файла справки является URI, а значение первой .Link директивы в справке на основе комментариев — URI, URI в файле справки используется в качестве значения свойства

HelpUri для функции.

Get-HelpКомандлет использует значение свойства HelpURI , чтобы определить Интернет-версию раздела справки по функции, если в команде указан параметр Online Get-Help .

суппортспагинг

Аргумент суппортспагинг добавляет в функцию первые параметры, Skip и IncludeTotalCount . Эти параметры позволяют пользователям выбирать выходные данные из очень большого результирующего набора.

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

Этот аргумент появился в Windows PowerShell 3,0.

  • First: возвращает только первые «n» объектов.
  • Пропустить: пропускает первые объекты «n», а затем получает оставшиеся объекты.
  • IncludeTotalCount: сообщает количество объектов в наборе данных (целое число), за которыми следуют объекты. Если командлет не может определить общее число, возвращается значение «Неизвестный общий счетчик».

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

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

function Get-Numbers {
    [CmdletBinding(SupportsPaging = $true)]
    param()

    $FirstNumber = [Math]::Min($PSCmdlet. PagingParameters.Skip, 100)
    $LastNumber = [Math]::Min($PSCmdlet.PagingParameters.First +
      $FirstNumber - 1, 100)

    if ($PSCmdlet.PagingParameters.IncludeTotalCount) {
        $TotalCountAccuracy = 1.0
        $TotalCount = $PSCmdlet.PagingParameters.NewTotalCount(100,
          $TotalCountAccuracy)
        Write-Output $TotalCount
    }
    $FirstNumber .. $LastNumber | Write-Output
}

SupportsShouldProcess

Аргумент SupportsShouldProcess добавляет в функцию параметры Confirm и WhatIf . Параметр Confirm запрашивает у пользователя перед выполнением команды для каждого объекта в конвейере. Параметр WhatIf перечисляет изменения, которые могут быть внесены командой, вместо выполнения команды.

PositionalBinding

Аргумент поситионалбиндинг определяет, являются ли параметры в функции позиционированными по умолчанию. Значение по умолчанию — $True. $False Для отключения позиционированной привязки можно использовать аргумент поситионалбиндинг со значением.

Аргумент поситионалбиндинг появился в Windows PowerShell 3,0.

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

Если параметры не являются позиционированными (они называются «именованными»), в команде требуется имя параметра (или аббревиатура или псевдоним имени).

Если поситионалбиндинг имеет значение $True , параметры функции по умолчанию являются позиционированными. PowerShell присваивает номера позиций параметрам в том порядке, в котором они объявляются в функции.

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

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

Аргумент расположения атрибута Parameter имеет приоритет над значением по умолчанию поситионалбиндинг . Аргумент « позиционирование » можно использовать для указания значения параметра «значение». Дополнительные сведения о аргументе » Расположение » см. в разделе about_Functions_Advanced_Parameters.

Примечания

Аргумент SupportsTransactions не поддерживается в расширенных функциях.

Keywords

about_Functions_CmdletBinding_Attribute

См. также

about_Functions

about_Functions_Advanced

about_Functions_Advanced_Methods

about_Functions_Advanced_Parameters

about_Functions_OutputTypeAttribute

Что такое [cmdletbinding()] и как он работает?



Согласно get-help about_Functions_CmdletBindingAttribute

Атрибут CmdletBinding-это атрибут функций, который заставляет их работать как скомпилированный cmdlets

Мы можем использовать его в верхней части наших сценариев. Какова функция в данном случае? Внутренняя неявная функция «main», вызываемая движком PowerShell для всех его входов?

Что касается этого синтаксиса:

[CmdletBinding(ConfirmImpact=<String>,
                     DefaultParameterSetName=<String>,
                     HelpURI=<URI>,
                     SupportsPaging=<Boolean>,
                     SupportsShouldProcess=<Boolean>,
                     PositionalBinding=<Boolean>)]

Что мы делаем? Создание экземпляра объекта cmdlbinding и передача списка аргументов его конструктору? Этот синтаксис можно найти в param() — например: [Parameter(ValueFromPipeline=$true)] . Есть ли у этого синтаксиса определенное имя, и можно ли его найти в другом месте?

Наконец, можем ли мы, как простой PowerShellers, имитировать эту функциональность и изменять поведение скриптов, устанавливая атрибут?

powershell binding
Поделиться Источник Loïc MICHEL     03 февраля 2013 в 09:21

3 ответа


  • Что такое INT 21H и как он работает?

    Что такое INT 21H и как это работает. Нужно сделать четыре различные функции в assembly 8086 с помощью turbo pascal7. Я хотел бы знать, как работает INT 21H и как получить системную дату, используя AH = 2Bh, поскольку я не уверен, как это работает, и не могу найти никаких достойных объяснений в…

  • Что такое VertiPaq и как он работает

    Я изучаю индекс хранилища столбцов (функция Denali CTP3) и узнал, что он использует архитектуру VertiPaq для сжатия данных. Мне стало интересно узнать, что это такое, как это работает, это архитектура. Я проверил в google, но удовлетворительного результата не получил. Не мог бы кто-нибудь подробно…



16

CmdletBinding, Параметр и т. Д.-Это специальные классы атрибутов, которые скриптеры могут использовать для определения поведения PowerShell, например, сделать функцию расширенной функцией с возможностями командлета.

Когда вы вызываете их, например, через [CmdletBinding()] , вы инициализируете новый экземпляр класса.

Подробнее о классе CmdletBindingAttribute читайте по адресу: MSDN

Подробнее о классе ParameterAttribute читайте по адресу: MSDN

Подробнее о классах атрибутов здесь и здесь

Поделиться Frode F.     03 февраля 2013 в 12:19



13

Вообще говоря, CmdletBinding-это то, что делает функцию из расширенной функции. Помещая его в начало сценария, вы создаете сценарий «advanced». Функции и сценарии во многом совпадают, где имя файла сценария эквивалентно имени функции, а содержимое сценария эквивалентно разделу scriptblock функции.

атрибуты CmdletBinding дают вам контроль над возможностями функций, такими как добавление подтверждения и поддержки WhatIf (через SupportsShouldProcess), Отключение позиционной привязки параметров и так далее.

Поделиться Shay Levy     03 февраля 2013 в 09:51



2

Что касается вопроса о синтаксисе, формат близко соответствует тому, как вы применяете класс атрибутов . NET к члену, используя именованные параметры в C#.

Сравните (упрощенный) grammar для атрибутов из раздела B.2.4 спецификации языка PowerShell с атрибутами из раздела C.2.13 спецификации языка C# :

B.2.4 Атрибуты   (PowerShell)

атрибут:
  [ атрибут-имя ( атрибут-аргументы ) ]

атрибут-аргументы:
  атрибут-аргумент
  атрибут-аргумент
, атрибут-аргументы

атрибут-аргумент:
  простое имя
= выражение


C.2.13 Атрибуты   (C#)

атрибут:
  [ атрибут-имя ( named-argument-list ) ]

named-argument-list:
  именованный аргумент
  named-argument-list
, именованный аргумент

именованный аргумент:
  идентификатор
= attribute-argument-expression


Я согласен, что было бы неплохо из чувства концептуальной краткости, например, повторно использовать синтаксис инициализации хэш-таблицы для инициализации атрибутов. Тем не менее, я могу себе представить, что поддержка всех опций из хэш-таблиц (например, [A(P=v)] , [A('P'=v)] , $n = 'P'; [A($n=v)] и т. Д. Или какого-то конкретного их подмножества) Просто для использования ; в качестве символа-разделителя была бы более сложной, чем того стоило.

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

Поделиться Emperor XLII     31 марта 2013 в 23:46



Похожие вопросы:


Что такое print <<EOF; и как он работает?

Возможный Дубликат : Помогите мне понять это утверждение Perl с <<‘ESQ’ Что именно делает утверждение в https://stackoverflow.com/questions/4151279/perl-print-eof ? Я наткнулся на…


Что такое SVG и как он работает?

Как работает SVG в CSS? Например, для того, чтобы иметь градиенты в IE9, я использовал этот редактор. http:/ / www.colorzilla.com / градиент-редактор / Он выплевывает какой-то код для IE9, который…


Что такое TinyPG и как он работает?

Что такое TinyPG и как он работает? Я знаю, что это compiler-compiler, но как мне начать работу и создать свой собственный компилятор в C#?


Что такое INT 21H и как он работает?

Что такое INT 21H и как это работает. Нужно сделать четыре различные функции в assembly 8086 с помощью turbo pascal7. Я хотел бы знать, как работает INT 21H и как получить системную дату, используя…


Что такое VertiPaq и как он работает

Я изучаю индекс хранилища столбцов (функция Denali CTP3) и узнал, что он использует архитектуру VertiPaq для сжатия данных. Мне стало интересно узнать, что это такое, как это работает, это…


Что такое AJAX и как он работает?

Возможный Дубликат : Как работает AJAX? Примечание : это сообщение сообщества wiki Я часто слышал, что AJAX используется для предоставления пользователю динамического контента. Что это такое и как…


Что такое сборщик журналов и как он работает?

Что такое сборщик журналов и как он работает? Пожалуйста, помогите мне понять это.


PowerShell рабочий процесс и атрибут CmdletBinding

В расширенных функциях PowerShell атрибут [CmdletBinding()] используется для добавления полезных метаданных и обеспечения того, чтобы функция действовала как скомпилированный командлет PowerShell….


Как загрузить другой файл powershell перед CmdletBinding?

Я использую powershell 5. Я создал перечисление в другом файле ps1, и мне нравится загружать его в другой ps1, который имеет CmdletBinding. Я попробовал код ниже, но ничего не вышло. Есть ли…


Как работает CmdletBinding() поверх файла .ps1?

Рассматривая пример кода PowerShell здесь : Он имеет [CmdletBinding()] поверх файла .ps1 scipt. Обратите внимание, что [CmdletBinding()] находится поверх файла, а не функции. Как вызвать этот файл. ..

powershell — Как проверить, что функция PowerShell имеет атрибут cmdletbinding

Я пытаюсь написать управляемый тестами код PowerShell с помощью Pester. Есть ли способ проверить, имеет ли функция определенный атрибут CmdletBinding, например ПоддерживаетShouldProcess и ConfirmImpact:

function Remove-Something {
    [CmdletBinding(SupportsShouldProcess, ConfirmImpact = 'High')]
    param ()
...

Доступны ли такие метаданные в результате, например, Get-Command?

$functionUnderTest = Get-Command Remove-Something
# How to test if $functionUnderTest has SupportsShouldProcesses defined?

1

Hans-Eric 26 Апр 2021 в 12:57

1 ответ

Лучший ответ

Это немного сложно, но вы можете попробовать что-то вроде этого, чтобы получить атрибуты:

function Invoke-MyFunction {
    [CmdletBinding(SupportsShouldProcess, ConfirmImpact = 'High')]
    param ()
}

(get-command Invoke-MyFunction). ScriptBlock.Ast.Body.ParamBlock.Attributes

#PositionalArguments : {}
#NamedArguments      : {SupportsShouldProcess, ConfirmImpact}
#TypeName            : CmdletBinding
#Extent              : [CmdletBinding(SupportsShouldProcess, ConfirmImpact = 'High')]
#Parent              : param ()

А затем вам нужно будет отфильтровать это, чтобы найти атрибут с именем «CmdletBinding» и проверить указанные в нем аргументы.

$command       = Get-Command -Name "Invoke-MyFunction";
$attributes    = $command.ScriptBlock.Ast.Body.ParamBlock.Attributes;

$cmdletBinding         = $attributes | where-object { $_.TypeName.FullName -eq "CmdletBinding" };
$supportsShouldProcess = $cmdletBinding.NamedArguments | where-object { $_.ArgumentName -eq "SupportsShouldProcess" };
$confirmImpact         = $cmdletBinding.NamedArguments | where-object { $_.ArgumentName -eq "ConfirmImpact" };

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

Примечание — обработка ошибок оставлена ​​в качестве упражнения для читателя 🙂

2

mclayton 26 Апр 2021 в 14:08

about_Functions_Cmdletbindingattribute


РАЗДЕЛ
	about_Functions_CmdletBindingAttribute

КРАТКОЕ ОПИСАНИЕ
	Описывает атрибут, который объявляет функцию, действие которой 
	похоже на действие скомпилированного командлета.

ПОЛНОЕ ОПИСАНИЕ
	При написании функций можно добавлять атрибут CmdletBinding, 
	чтобы среда Windows PowerShell привязывала параметры функции так 
	же, как выполняется привязка параметров скомпилированных 
	командлетов. Если этот атрибут объявлен, среда Windows PowerShell 
	также задает автоматическую переменную $PSCmdlet.


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

	Примечание. Скомпилированные командлеты используют обязательный 
	атрибут Cmdlet, действие которого похоже на действие описываемого 
	в этом разделе атрибута CmdletBinding. 


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

		{
		[CmdletBinding(SupportsShouldProcess=<Boolean>,
					 ConfirmImpact=<String>,
					 DefaultParameterSetName=<String>)]

		Param ($Parameter1)
		Begin{}
		Process{}
		End{}
	}


  SupportsShouldProcess

	Если аргумент SupportsShouldProcess имеет значение true, это 
	значит, что функция поддерживает вызовы метода ShouldProcess, 
	который запрашивает у пользователя подтверждение, прежде чем функция 
	изменит систему.  Если этот аргумент задан, для функции включаются 
	параметры Confirm и WhatIf.
 

	Дополнительные сведения о запросах подтверждения см. в разделе 
	"Запрос подтверждения" библиотеки MSDN (Microsoft Developer 
	Network) по адресу http://go.microsoft.com/fwlink/?LinkId=136658.


  DefaultParameterSetName
 
	Аргумент DefaultParameterSetName задает имя набора параметров, 
	который среда Windows PowerShell будет пытаться использовать, 
	если ей не удастся определить нужный набор параметров. Этой 
	ситуации можно избежать, сделав уникальный параметр каждого из 
	наборов параметров обязательным.


  ConfirmImpact

	Аргумент ConfirmImpact определяет, в каком случае действие 
	функции должно быть подтверждено вызовом метода ShouldProcess. Вызов 
	метода ShouldProcess отображает запрос подтверждения только тогда, когда 
	аргумент ConfirmImpact больше или равен значению привилегированной 
	переменной $ConfirmPreference.  (По умолчанию этот аргумент имеет значение 
	Medium.) Этот аргумент следует задавать только в том случае, когда задан 
	аргумент SupportsShouldProcess.


СМ. ТАКЖЕ
	about_Functions_Advanced
	about_Functions_CmdletBindingAttribute
	about_Functions_ParameterAttributes

about_Functions_Advanced_Parameters — Разные уроки по Программированию

КРАТКОЕ ОПИСАНИЕ
    Описывает, как добавлять статические и динамические параметры в функции,
    в которых объявлен атрибут CmdletBinding.

ПОЛНОЕ ОПИСАНИЕ
    При написании функций можно объявлять собственные параметры, а
    также можно писать функции, которые могут обращаться к общим
    параметрам, которые доступны скомпилированными командлетам.
    Дополнительные сведения об общих параметрах Windows PowerShell
    см. в разделе about_CommonParameters.

Статические параметры
    В следующем примере показано объявление параметра, в котором
    определяется параметр ComputerName. Этот параметр обладает следующими
    характеристиками:

        — он является обязательным;
        — он принимает входные данные из конвейера;
        — в качестве входных данных он принимает массив строк;

        Param
          (
            [parameter(Mandatory=$true,
            ValueFromPipeline=$true)]
            [String[]]
            $ComputerName
          )
 

    Единственным обязательным атрибутом, который необходимо
    использовать при объявлении параметра, является атрибут
    Parameter. Но можно также объявить атрибут Alias и несколько
    аргументов проверки. Количество атрибутов, которые можно включить в
    объявление параметра, не ограничено.


  Атрибут Parameter

      Атрибут Parameter служит для объявления параметра функции.
      У этого атрибута есть следующие именованные аргументы, которые
      служат для определения характеристик параметра, например
      обязательности параметра.


    Именованный аргумент Mandatory

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

        Param
          (
            [parameter(Mandatory=$true)]
            [String[]]
            $ComputerName
          )


    Именованный аргумент Position

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

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

        Param
          (
            [parameter(Position=0)]
            [String[]]
            $ComputerName
          )


    Именованный аргумент ParameterSetName

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

        Param
          (
            [parameter(Mandatory=$true,
                      ParameterSetName=»Computer»)] [String[]]
            $ComputerName
          )

        Param
          (
            [parameter(Mandatory=$true,
                      ParameterSetName=»User»)] [String[]]
            $UserName
          )

        Дополнительные сведения о наборах параметров см. в разделе
        «Наборы параметров командлетов» библиотеки MSDN по адресу
        http://go.microsoft.com/fwlink/?LinkId=142183.


    Именованный аргумент ValueFromPipeline

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

        Param
          (
            [parameter(Mandatory=$true,
                      ValueFromPipeline=$true)] [String[]]
            $ComputerName
          )


    Именованный аргумент ValueFromPipelineByPropertyName

        Аргумент valueFromPipelineByPropertyName определяет, что параметр
        принимает входные данные из свойства объекта конвейера. Этот атрибут
        следует указывать, если выполняются следующие условия:

            — параметр используется для доступа к объекту конвейера;

            — имя свойства совпадает с именем параметра или псевдоним
              свойства совпадает с псевдонимом параметра.

        Например, если у функции есть параметр ComputerName, а у объекта
        конвейера есть свойство ComputerName, значение свойства ComputerName
        будет присвоено параметру ComputerName функции.

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

        Param
          (
            [parameter(Mandatory=$true,
                      ValueFromPipelineByPropertyName=$true)] [String[]]
            $ComputerName
          )


    Именованный аргумент ValueFromRemainingArguments

        Аргумент ValueFromRemainingArguments определяет, что параметр
        принимает все оставшиеся аргументы, которые не привязаны к
        параметрам функции. В следующем примере показано объявление
        параметра ComputerName, который принимает все оставшиеся аргументы
        входного объекта, передаваемого функции.

        Param
          (
            [parameter(Mandatory=$true,
                      ValueFromRemainingArguments=$true)] [String[]]
            $ComputerName
          )


    Именованный аргумент HelpMessage

        Аргумент HelpMessage задает сообщение, которое содержит
        краткое описание параметра. В следующем примере показано
        объявление параметра, в котором определяется описание параметра.

        Param
          (
            [parameter(Mandatory=$true,
                      HelpMessage=»An array of computer names.»)]
            [String[]]
            $ComputerName
          )


  Атрибут Alias

      Атрибут Alias задает другое имя параметра. Для параметра можно
      определить произвольное число псевдонимов. В следующем примере
      показано объявление обязательного параметра, в котором для параметра
      ComputerName определен псевдоним CN.

        Param
          (
            [parameter(Mandatory=$true)]
            [alias(«CN»)]
            [String[]]
            $ComputerName
          )


  Атрибуты проверки параметров

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


    Атрибут проверки AllowNull

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

        Param
          (
            [parameter(Mandatory=$true)]
            [String]
            [AllowNull()]
            $ComputerName
          )


    Атрибут проверки AllowEmptyString

        Атрибут AllowEmptyString позволяет задавать в качестве аргумента
        обязательного параметра командлета пустую строку. В следующем примере
        параметр ComputerName может содержать пустую строку («»), даже если
        параметр является обязательным.

        Param
          (
            [parameter(Mandatory=$true)]
            [String]
            [AllowEmptyString()]
            $ComputerName
          )


    Атрибут проверки AllowEmptyCollection

        Атрибут AllowEmptyCollection позволяет задавать в качестве
        аргумента обязательного параметра командлета пустую коллекцию.

        Param
          (
            [parameter(Mandatory=$true)]
            [String[]]
            [AllowEmptyCollection()]
            $ComputerName
          )


    Атрибут проверки ValidateCount

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

        Param
          (
            [parameter(Mandatory=$true)]
            [String[]]
            [ValidateCount(1,5)]
            $ComputerName
          )


    Атрибут проверки ValidateLength

        Атрибут ValidateLength задает минимальную и максимальную
        длину аргумента параметра. Среда выполнения Windows
        PowerShell создает ошибку, если длина аргумента параметра
        выходит за эти пределы.
        В следующем примере задаются имена компьютеров, длина которых
        должна лежать в интервале от 1 до 10 знаков.

        Param
          (
            [parameter(Mandatory=$true)]
            [String[]]
            [ValidateLength(1,10)]
            $ComputerName
          )


    Атрибут проверки ValidatePattern

        Атрибут ValidatePattern задает регулярное выражение, которое
        проверяет шаблон аргумента параметра. Среда выполнения Windows
        PowerShell создает ошибку, если аргумент параметра не соответствует
        этому шаблону. В следующем примере аргументом параметра должно быть
        четырехзначное число, каждый разряд которого может содержать число от
        0 до 9.

        Param
          (
            [parameter(Mandatory=$true)]
            [String[]]
            [ValidatePattern(«[0-9][0-9][0-9][0-9]»)]
            $ComputerName
          )


    Атрибут проверки ValidateRange

        Атрибут ValidateRange задает минимальное и максимальное значение
        аргумента параметра. Среда выполнения Windows PowerShell создает
        ошибку, если аргумент параметра выходит за эти пределы. В следующем
        примере аргумент параметра не может быть меньше 0 или больше 10.


        Param
          (
            [parameter(Mandatory=$true)]
            [Int[]]
            [ValidateRange(0,10)]
            $Count
          )


    Атрибут проверки ValidateScript

        Атрибут ValidateScript задает скрипт, который используется
        для проверки аргумента параметра. Среда выполнения Windows
        PowerShell создает ошибку, если результатом выполнения
        скрипта является значение false или если скрипт создает
        исключение. В следующем примере значение параметра Count
        должно быть менее 4.

        Param
          (
            [parameter()]
            [Int]
            [ValidateScript({$_ -lt 4})]
            $Count
          )


    Атрибут ValidateSet

        Атрибут ValidateSet задает набор допустимых значений аргумента
        параметра. . Среда выполнения Windows PowerShell создает ошибку, если
        аргумент параметра не совпадает ни с одним из значений в наборе.
        В следующем примере аргумент параметра может содержать только
        имена Steve, Mary и Carl.

        Param
          (
            [parameter(Mandatory=$true)]
            [String[]]
            [ValidateRange(«Steve», «Mary», «Carl»)]
            $UserName
          )


    Атрибут проверки ValidateNotNull


        Атрибут ValidateNotNull определяет, что аргумент параметра не
        может иметь значение Null. Среда выполнения Windows
        PowerShell создает ошибку, если параметр имеет значение Null. 

        Param
          (
            [parameter(Mandatory=$true)]
            [String[]]
            [ValidateNotNull()]
            $UserName
          )


    Атрибут проверки ValidateNotNullOrEmpty

        Атрибут ValidateNotNullOrEmpty определяет, что аргумент
        параметра не может иметь значение Null и не может быть
        пустым. Среда выполнения Windows PowerShell создает ошибку, если
        параметр задан, но имеет значение Null, пустой строки или пустого
        массива. 

        Param
          (
            [parameter(Mandatory=$true)]
            [String[]]
            [ValidateNotNullOrEmpty()]
            $UserName
          )

Динамические параметры

    Динамические параметры — это параметры командлета, функции или скрипта,
    доступные только при определенных условиях. 

    Например, у некоторых командлетов поставщика могут быть параметры,
    доступные только при использовании командлета в пути поставщика.
    Одним из динамических параметров является параметр Encoding
    командлета Set-Item, который доступен только при использовании командлета
    Set-Item в пути поставщика FileSystem.

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

    Синтаксис выглядит следующим образом/

    DynamicParam {<список_инструкций>} 

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

    Используйте командлет New-Object для создания объекта
    System.Management.Automation.RuntimeDefinedParameter, представляющего
    параметр и задающего его имя. 

    Также можно использовать команду New-Object для создания объекта
    System.Management.Automation.ParameterAttribute, представляющего атрибуты
    параметра (например, Mandatory, Position или ValueFromPipeline)
    или его набор параметров.

    В следующем примере показана функция со стандартными параметрами Name и
    Path, а также с дополнительным динамическим параметром DP1. Параметр DP1
    находится в наборе параметров PSet1 и принадлежит к типу Int32.
    Параметр DP1 доступен в функции Sample только в том случае, если
    в значении параметра Path содержится строка «HKLM:», указывающая
    на использование командлета на диске реестра HKEY_LOCAL_MACHINE.
    
     
        function Sample {
          Param ([String]$Name, [String]$Path)
     
          DynamicParam
          {
            if ($path -match «*HKLM*:»)
            {
              $dynParam1 = new-object 
                System.Management.Automation.RuntimeDefinedParameter(«dp1»,
                [Int32], $attributeCollection)
     
              $attributes = new-object System.Management.Automation.ParameterAttribute
              $attributes.ParameterSetName = ‘pset1’
              $attributes.Mandatory = $false
     
              $attributeCollection = new-object 
                -Type System.Collections.ObjectModel.Collection«1[System.Attribute]
              $attributeCollection.Add($attributes)
    
              $paramDictionary = new-object 
                System.Management.Automation.RuntimeDefinedParameterDictionary
              $paramDictionary. Add(«dp1», $dynParam1)
            
              return $paramDictionary
            } End if
          }
        }  
     
    Дополнительные сведения см. в разделе «Класс RuntimeDefinedParameter»
    библиотеки MSDN (Microsoft Developer Network)
    по адресу http://go.microsoft.com/fwlink/?LinkID=145130.        


СМ. ТАКЖЕ
    about_Advanced Functions
    about_Functions_Advanced_Methods 
    about_Functions_CmdletBindingAttribute

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

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

Представим, что каждое утро вы проверяете 50 последних логов за 14 часов журнала Application с помощью этой команды:


Get-EventLog -LogName Application -Newest 50 | where TimeWritten -ge (Get-Date).AddHours(-14)

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


function Get-DayLog {
    Get-EventLog -LogName Application -Newest 50 | where TimeWritten -ge (Get-Date).AddHours(-14)
}

Любая функция обязательно должна состоять из трех вещей:

  • function — объявляет и говорит что после нее будет название;
  • имя функции — название, по которому мы будем ее вызывать. В нашем случае имя Get-DayLog;
  • скобки — обозначают начало и конец выражения.

После написания функции она вызывается по имени:


Get-DayLog

Учитывая, что нам может потребоваться получить данные не за последние 14 часов и более чем за 50 дней нам может потребуется изменить ее передав параметры.

 

Не обязательно использовать имя такого же плана, как принято в Powershell, то есть вместо «Get-DayLog» можно писать «daylog». Такой подход рекомендуем и является распространенной практикой, который поможет отличить запуск сторонней программы от функции. 

Функции в Powershell всегда именуются по следующему признаку. Первое слово это глаголы типа:

  • Get — получить;
  • Set — изменить;
  • Install — установить;
  • New — создать.

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

 

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


function Get-DayLog ($param1,$param2) {
    Get-EventLog -LogName Application -Newest $param1 | where TimeWritten -ge (Get-Date).AddHours($param2)
}

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

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


Get-DayLog -param1 50 -param2 -14

При вызове функции мы передаем два обязательных параметра со значениями. Эти значения, внутри функции, будут доступны под названиями $param1 и $param2. Эти переменные мы передаем в команду получения и фильтрации логов.

Установка значений по умолчанию

В нашей задаче, чаще всего, мы получаем только 50 последних логов и нам не хочется указывать их каждый раз. Если мы не будем указывать этот параметр в существующей функции, то получим ошибку. Что бы этого избежать нужно указать значение по умолчанию. На примере ниже я присвоил $param1 значение 50. Оно будет использоваться только в том случае, если мы не используем этот параметр при вызове:


function Get-DayLog ($param1=50,$param2) {
     Get-EventLog -LogName Application -Newest $param1 | where TimeWritten -ge (Get-Date).AddHours($param2)
}
Get-DayLog -param2 -7

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


function Get-DayLog ($param2,$param1=50) {
     Get-EventLog -LogName Application -Newest $param1 | where TimeWritten -ge (Get-Date). AddHours($param2)
}
Get-DayLog -7 1
Get-DayLog -7

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

Возвращение значений

В отличие от других языков, если мы присвоим переменной $result результат функции Get-DayLog, то она будет содержать значения:


$result = Get-DayLog -7 1

Это будет работать до тех пор, пока мы не решим изменить функцию присвоив переменные:


function Get-DayLog ($param2,$param1=50) {
     $events = Get-EventLog -LogName Application -Newest $param1 | where TimeWritten -ge (Get-Date).AddHours($param2)
}
$result = Get-DayLog -7
$result
$events 

Мы не можем получить результат используя переменную $result, так как функция не выводит информацию, а хранит ее в переменной $events. Вызывая $events мы тоже не получаем информацию, так как тут работает понятие «область видимости переменных».

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


function Get-DayLog ($param2,$param1=50) {
     $events = Get-EventLog -LogName Application -Newest $param1 | where TimeWritten -ge (Get-Date).AddHours($param2)
return $events
}
$result = Get-DayLog -7
$result

Я бы рекомендовал всегда возвращать значения через return, а не использовать вывод используя команды типа Write-Output внутри функции. Использование return останавливает работу функции и возвращает значение, а это значит что его не стоит ставить по середине логики если так не планировалось.

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


function Get-Salary ($Zarplata) {
$nalog = $Zarplata * 0.13
$zarplata_bez_nds = $Zarplata - $nalog
return $nalog,$zarplata_bez_nds
}
Get-Salary -Zarplata 100000

Я вернул оба значения разделив их запятой. По умолчанию всегда возвращается массив. Массивы в Powershell это набор не именованных параметров. Более подробно  о них мы уже писали.

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


$result = Get-Salary -Zarplata 100000
# Определяем тип данных
$result.GetType()
Write-Host "это зарплата" $result[1]
Write-Host "это налог" $result[0]

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


function Get-Salary ($Zarplata) {
$nalog = $Zarplata * 0. 13
$zarplata_bez_nds = $Zarplata - $nalog
return @{"Налог"=$nalog;"Зарплата"=$zarplata_bez_nds;}
}
Get-Salary -Zarplata 100000

Подробно о хэш таблицах в Powershell вы можете почитать в предыдущих статьях. Далее так же будет несколько примеров с ними.

Вы можете возвращать любой тип данных и в любом формате и последовательности. Каждый из них имеет своё преимущество.

Область видимости переменных

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


$Zarplata = 100000
function Get-Salary {
$nalog = $Zarplata * $nalog
$zarplata_bez_nds = $Zarplata - $nalog
return @{"Налог"=$nalog;"Зарплата"=$zarplata_bez_nds;}
}
$nalog = 0.20
Get-Salary

Такой подход не запрещает переопределить переменную внутри функции дав ей другое значение:


$Zarplata = 100000
function Get-Salary {
$Zarplata = 200000
$nalog = $Zarplata * $nalog
$zarplata_bez_nds = $Zarplata - $nalog
return @{"Налог"=$nalog;"Зарплата"=$zarplata_bez_nds;}
}
$nalog = 0. 20
Get-Salary
$Zarplata

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

Такие переменные называются глобальными. Объявляются приставкой $global:


$Zarplata = 100000
function Get-Salary {
#Глобальная переменная
$global:Zarplata = 200000
$nalog = $Zarplata * $nalog
$zarplata_bez_nds = $Zarplata - $nalog
return @{"Налог"=$nalog;"Зарплата"=$zarplata_bez_nds;}
}
$nalog = 0.20
Get-Salary
$Zarplata

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

 

Строгие типы данных

Powershell автоматически преобразует типы данных. В отличие от других языков результат этого выражения будет число 3, а не «111»:


3 * "1"

Такой подход может привести к ошибке. Мы можем исправить это объявляя типы:


function Get-Size ([int]$Num){
    $size = 18 * $Num
    return $size
}
Get-Size 5
Get-Size "str"

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

Таких типов данных в Powershell  всего 13:

  • [string] — строка;
  • [char] — 16-битовая строка Unicode;
  • [byte] — 8 битовый символ;
  • [int] — целое 32 битовое число;
  • [long] — целое 64 битовое число;
  • [bool] — булево значение True/False;
  • [decimal] — 128 битовое число с плавающей точкой;
  • [single] — 32 битовое число с плавающей точкой;
  • [double] — 64 битовое число с плавающей точкой;
  • [DateTime] — тип данных даты и времени;
  • [xml] — объект xml;
  • [array] — массив;
  • [hashtable] — хэш таблица.

Примеры работы с некоторыми типами данных вы увидите далее.

$args

В языках программирования есть понятие позиционного параметра. Это такие параметры, которые могут передаваться без имен:


function Get-Args {
    Write-Host "Пример с arg: " + $args[0] -BackgroundColor Red -ForegroundColor Black
    Write-Host "Пример с arg: " + $args[1] -BackgroundColor Black -ForegroundColor Red
}

Get-Args "Первый" "Второй"

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

Обязательные параметры Mandatory

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


function Get-ItemCreationTime ($item){
    Get-Item -Path $item | select LastWriteTime
}

Get-ItemCreationTime "C:\Windows\explorer. exe"
Get-ItemCreationTime

Первый вызов функции прошел успешно, так как мы передали параметры. Во втором случае мы не передаем значения, а значит переменная $item равна $null (неопределенному/неизвестному значению). Во многих языках, в таких случаях, у нас появилась бы ошибка еще в момент вызова функции Get-ItemCreationTime, а не во время выполнения Get-Item.

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


function Get-ItemCreationTime ([parameter(Mandatory=$true)]$item){
    Get-Item -Path $item | select LastWriteTime
}

Get-ItemCreationTime "C:\Windows\explorer.exe"
Get-ItemCreationTime

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

Param()

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


function Get-ItemCreationTime {

	param (
		[parameter(Mandatory=$true)]$item
		)

    Get-Item -Path $item | select LastWriteTime
	}

Get-ItemCreationTime "C:\Windows\explorer.exe"
Get-ItemCreationTime

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

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


function Get-PlusPlus {
	param (
		[parameter(Mandatory=$true, Position=0)]
		[int]
		$item1,
        [parameter(Position=1)]
        [int]
        $item2,
        [parameter(Position=2)]
        [string]
        $item3
        )

    $summ = $item1 + $item2
    Write-Output $item3 $summ
	}

Get-PlusPlus 2 5 "Summ"

Position говорит под каким номером передается значение.

Одно из преимуществ работы с param() в том, что у нас становятся доступны ключи типа -Confirm и -Verbose. 

CmdletBinding()

Использование этого атрибута позволяет расширять возможность по созданию командлетов. Microsoft пишет, что использование CmdletBinding или Parameter расширяет возможность функций в Powershell, но по моему опыту не всегда все срабатывает и нужно ставить оба атрибута.

На примере ниже я установил ограничение на длину строк с 1 по 13 символов с помощью ValidateLength(1,13). Position=1 говорит об индексе элемента в массиве:


function Get-LenStr {
    [CmdletBinding()]
	param (        
		[parameter(Mandatory=$true,
                        Position=1
                        )]        
        [ValidateLength(1,13)]
		[string]
		$len1,
		[parameter(Mandatory=$true, 
                        Position=0
                        )]
		[string]
		$len2
        )
    Write-Host $len2 $len1
	}

Get-LenStr "Это строка 1" "Это строка 2"

Таких дополнительных аргументов для команд достаточно много. Для примера еще несколько атрибутов, которые можно добавить в блок parameter:

  • HelpMessage = «Текст»  — подсказка по использованию переменной. Это пояснение можно увидеть при запросе справки через Get-Help;
  • ParameterSetName=»Computer» — указывает к какой переменной относятся параметры;

Отдельные блоки типа [ValidateLength]:

  • [Alias(‘t’)] — устанавливает алиас для этого параметра в виде буквы t;
  • [PSDefaultValue(Test=’Test’)] — устанавливает значение по умолчанию переменной Test;
  • [string[]] — такое использование говорит, что значение принимает массив строк
  • [AllowNull()] — позволяет обязательным параметрам быть $null
  • [AllowEmptyString()] — позволяет обязательным параметрам быть пустой строкой
  • [AllowEmptyCollection()] — обязательный параметр с пустым массивом
  • [ValidateCount(1,5)] — минимальное и максимальное количество значений.
  • [ValidatePattern(«[0-9]»)] — проверка на шаблон используя регулярного выражения

Больше примеров и аргументов на сайте Microsoft.

 

Передача массивов в виде параметров

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

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


function Get-ServiceStopped ([array]$Computers){
    $services = Get-Service -ComputerName $Computers | where Status -eq Stopped
    return $services
}

Get-ServiceStopped '127. 0.0.1','localhost'

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


function Get-ServiceStopped ([array]$Computers){
    $services = Get-Service -ComputerName $Computers[0,-2] | where Status -eq $Computers[-1]
    return $services
}

Get-ServiceStopped '127.0.0.1','localhost','Stopped'

Хэш таблицы

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


function Get-ServiceStopped ([hashtable]$Params){
    $services = Get-Service @Params | where Status -eq Stopped
    $services = Start-Service $services
    return $services
}

Get-ServiceStopped @{Name='WinRM';ComputerName=@('127.0.0.1','localhost')}

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

 

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

IF

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


function Get-SiteResponse {
    # Начало отсчета
    $start_time = Get-Date
    # Выполнение запроса
    $request = Invoke-WebRequest -Uri "https://fixmypc.ru"
    # Фиксирование окончания выполнения
    $end_time = Get-Date
    # Высчитываем разницу во времени
    $result =  $end_time - $start_time
    # Проверка и возвращение результата
    if ($result.Milliseconds -lt 76) {
        return "Скорость ответа нормальная " + $result. Milliseconds}
    else{
        return "Сайт отвечает долго " + $result.Milliseconds }
    
}

Get-SiteResponse

Switch

Мы уже говорили про Powershell Switch в предыдущих статьях. Если коротко, то это более удобные условия. Используя предыдущий пример, но со Switch, это будет выглядеть так:


function Get-SiteResponse {
    # Начало отсчета
    $start_time = Get-Date
    # Выполнение запроса
    $request = Invoke-WebRequest -Uri "https://fixmypc.ru"
    # Фиксирование окончания выполнения
    $end_time = Get-Date
    # Высчитываем разницу во времени
    $result =  $end_time - $start_time
    # Проверка и возвращение результата
    switch($result.Milliseconds) {
        {$PSItem -le 76} {
            return "Скорость ответа нормальная " + $result.Milliseconds}
        default {
            return "Сайт отвечает долго " + $result. Milliseconds }
    }
}

Get-SiteResponse

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


function Install-SQLUpdates {
	# делаем установку
	return "Установка обновлений на SQL сервер прошла успешно"
}

function Install-ADUpdates {
	# делаем установку
	return "Установка обновлений на сервер AD прошла успешно"
}

function Install-FileServerUpdates {
	# делаем установку
	return "Установка обновлений на файловый сервер прошла успешно"
}

function Make-Switch ($computer) {
	# Проверка имени компьютера
	$result = switch($computer){
		{$computer -like "SQL*"} {Install-SqlUpdates}
		{$computer -like "AD*"} {Install-ADUpdates}
		{$computer -like "FileServer*"} {Install-FileServerUpdates}
		default {"Такого типа компьютеров нет"}
	}
	return $result

}

Make-Switch "AD1"

Со switch так же удобно передавать булевы значения. В примере ниже если указан ключ -On сервис включится, а если его нет выключится:


function Switch-ServiceTest ([switch]$on) {
    if ($on) {Write-Output "Сервис включен"}
    else {"Сервис выключен"}
}


Switch-ServiceTest -On
Switch-ServiceTest

 

Вы наверняка работали через команды Powershell, которые позволяли использовать конвейер следующим образом:


Get-Process -Name *TestProc* | Stop-Process

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


function Get-SomeNum {
    # Генерация числа
    $num = Get-Random -Minimum 5 -Maximum 10
    return $num
}

function Plus-SomeNum ($num) {
    Write-Host "Прибавление числа " $num 
    $num += $num
    return $num
}

Get-SomeNum
Plus-SomeNum 5
Get-SomeNum | Plus-SomeNum

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


Get-Help Stop-Process -Parameter Name

Таких атрибутов всего два:

  • ValueFromPipelineByPropertyName — получение значения из конвейера по имени;
  • ValueFromPipeline — получение через конвейер только значения .

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


function Get-SomeNum { 
        $num = Get-Random -Minimum 5 -Maximum 10
        return $num
}

function Plus-SomeNum {
    [cmdletbinding()]
    Param (
            [parameter(ValueFromPipeline=$True)]
            [int]
            $num
        )
    process {  
    Write-Host "Прибавление числа " $num 
    $num += $num
    return $num
    }
}

1..5 | Plus-SomeNum
Get-SomeNum | Plus-SomeNum

[cmdletbinding()] — атрибут расширения функции, который добавляет некоторые возможности в функции позволяя им работать как команду.

Если бы мы не указали блок Process функция бы вернула только последней результат из массива 1..5:

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


function Get-SomeNum { 
    $num = Get-Random -Minimum 5 -Maximum 10
    $object = [pscustomobject]@{num=$num}
    return $object
}

function Plus-SomeNum {
    [cmdletbinding()]
    Param (
            [parameter(ValueFromPipelineByPropertyName=$True)]
            [int]
            $num
        )
    process {  
    Write-Host "Прибавление числа " $num 
    $num += $num
    return $num
    }
}

Get-SomeNum | Plus-SomeNum
[pscustomobject]@{num=5} | Plus-SomeNum
[pscustomobject]@{bad=5} | Plus-SomeNum

Как уже писалось ValueFromPipelineByPropertyName принимает только именованные параметры и в случае с именем «bad» мы получаем ошибку:

  • Не удается привязать объект ввода к любым параметрам команды, так как команда не принимает входные данные конвейера
  • The input object cannot be bound to any parameters for the command either because the command does not take pipeline input or the input and its properties do not match any of the parameters that take pipeline input.

Причем передавать именованные параметры через хэш таблицы мы не можем, только через pscustomobject.

Вы можете указывать сразу два атрибута таким образом:


[parameter(ValueFromPipelineByPropertyName,ValueFromPipeline)]

Это позволит использовать и значение с именем, если оно указано либо без него. Это не спасет вас от ситуации, если вы передаете параметр с другим именем:

Передача через конвейер нескольких значений

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


function Get-SomeNum { 
    $number1 = Get-Random -Minimum 5 -Maximum 10
    $number2 = Get-Random -Minimum 1 -Maximum 5
    $object = [pscustomobject]@{num1=$number1;num2=$number2}
    return $object
}

function Plus-SomeNum {
    [cmdletbinding()]
    Param (
            [parameter(ValueFromPipelineByPropertyName=$true,
                        ValueFromPipeline=$true,
                        Mandatory=$true)]
            [int]
            $num1,
            [parameter(ValueFromPipelineByPropertyName=$true,
                        ValueFromPipeline=$true,
                        Mandatory=$true)]
            [int]
            $num2
        )
    begin {$num1 += $num1
           $num2 = $num2 * $num2}
    process {  
    return @{"Результат сложения"=$num1; "Результат умножения"=$num2}
    }
}

Get-SomeNum | Plus-SomeNum

 

При вызове справки на любой командлет мы получим такую информацию:

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


function Get-SomeNum { 
  <#
  .SYNOPSIS
  (короткое описание) Получение случайного числа
  .DESCRIPTION
  (полное описание) Получение случайного числа от 1 до 3
  .EXAMPLE
  (пример) Get-Random
  .EXAMPLE
  (второй)
  .PARAMETER num
  (описание параметра) Параметр ни на что не влияет
  .PARAMETER num2
  (описание второго)
  #>
    [CmdletBinding()]
    param (
           [int]
           $num
    )
    $num = Get-Random -min 1 -Max 3
    return $num
}

Get-SomeNum

Некоторые виды описаний, например Examples, можно использовать несколько раз.

 

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

Импорт на множество компьютеров

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


Import-Module C:\funct.ps1 -Force

После выполнения этой команды мы сможем использовать нашу функцию.

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

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

Загрузка как модуля

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

Первое что нужно сделать это получить пути окружения Powershell:


$env:PSModulePath

Выберете один из путей, где лежат модули или перейдите по следующему:


C:\Users\%username%\Documents\WindowsPowerShell\Modules

В указанной папке Modules вам нужно создать папку и файл с одинаковыми именами. Файлу добавляете расширение «.psm1» и помещаете в него свой скрипт.

В моём случае путь выглядит так:


C:\Users\%username%\Documents\WindowsPowerShell\Modules\Test\Test.psm1

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


Get-Module -ListAvailable -Name "*Часть имени папки*"

 

Теги: #powershell

Применение параметров–Force,–WhatIf,–Confirm, –Verbose и–Debug в скриптах

Мы с Васей Гусевым задумали утопичную идею составить какой-то набор гæдлайнов как правильно писать скрипты для PowerShell. Так исторически сложилось, что каждый пишет скрипты так, как он хочет/удобней/умеет. PowerShell один из самых новых языков скриптования (в отличии от vbs/cmd) и он внёс совершенно новый синтаксис и идею оформления кода, который как правило несовместим с жизнью с другими языками.

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

Итак, сегодняшняя тема (посты в категории guildelines не будут последовательными) — как правильно реализовывать специальные параметры –Force, –WhatIf, –Confirm –Verbose и –Debug в скриптах и функциях.

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

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


Remove-Item C:\Windows\notepad.exe -WhatIf

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

Если ваш скрипт выполняет какие-то серьёзные и/или деструктивные действия (например, как командлет Set-ExecutionPolicy), следует применять параметр Confirm.

Определение этих параметров в коде

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


function Remove-File {
[CmdletBinding(
    ConfirmImpact = 'High',
    SupportsShouldProcess = $true
)]
    param(
        [string]$Path,
        [switch]$Force
    )
    if ($Force -or $PSCmdlet. ShouldProcess($Path,"Delete file")) {
        Remove-Item $Path
    }
}

И вот вывод какое у нас получится поведение:


[↓] [vPodans] Remove-File .\Desktop\qsca.txt

Confirm
Are you sure you want to perform this action?
Performing operation "Delete file" on Target ".\Desktop\qsca.txt".
[Y] Yes  [A] Yes to All  [N] No  [L] No to All  [S] Suspend  [?] Help (default is "Y"): n
[↓] [vPodans] Remove-File .\Desktop\qsca.txt -WhatIf
What if: Performing operation "Delete file" on Target ".\Desktop\qsca.txt".
[↓] [vPodans] Remove-File .\Desktop\qsca.txt -Force
[↓] [vPodans]

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

Как мы добились такого поведения? Во-первых, конструкция в начале скрипта [CmdletBinding()] определяет общее поведение всего скрипта. У него есть разные атрибуты. В данном случае были использованы:

Этот атрибут указывает, должен ли код ожидать ответ от пользователя на выполнение операции. Т.е. он включает обработчик для параметров –Confirm и –WhatIf.

Этот атрибут указывает уровень воздействия кода на систему и включает обработчик параметра –Confirm. Возможные значения:

  1. None (или атрибут не указан вообще) — никаких сообщений подтверждения операции выводиться не будет. Даже если вы явно укажете параметр Confirm.
  2. Low — код оказывает минимальное воздействие на систему с минимальным риском потери данных.
  3. Medium — код оказывает среднее воздействие с некоторым риском потерять данные или произвести деструктивные действия.
  4. High — выполняемый код обладает высоким риском потери данных. Например, уровень High выставлен у командлета Set-ExecutionPolicy.

По умолчанию в сессии PowerShell уровень воздействия выставлен в High (можно посмотреть в переменной $ConfirmPreference). И все командлеты, у которых уровень воздействия на систему выше или такой же, как в $ConfirmPreference, запрос на подтверждение будет выводиться всегда.

Например, в сессии у нас $ConfirmPreference = ‘High’, а у командлета/функции тоже ‘High’ будет выведен запрос подтверждения. Как в случае с Set-ExecutionPolicy. Если у командлета/функции ConfirmImpact ниже (Low или Medium) запрос подтверждения по умолчанию выводиться не будет. Но возможно указать –Confirm для принудительного вывода запроса подтверждения. Если посмотреть на наш код, мы увидим, что уровень воздействия на систему высокий, поэтому мы каждый раз получаем запрос подтверждения. Если мы изменим уровень воздействия в уровень ‘Medium’, наша функция не будет по умолчанию выводить никаких запросов. Но будет выводить его при указании параметра –Confirm:


function Remove-File {
[CmdletBinding(
    ConfirmImpact = 'Medium',
    SupportsShouldProcess = $true
)]
    param(
        [string]$Path,
        [switch]$Force
    )
    if ($Force -or $PSCmdlet. ShouldProcess($Path,"Delete file")) {
        Remove-Item $Path
    }
}

И вот какое у нас будет поведение:


[↓] [vPodans] Remove-File .\Desktop\qsca.txt -Confirm

Confirm
Are you sure you want to perform this action?
Performing operation "Delete file" on Target ".\Desktop\qsca.txt".
[Y] Yes  [A] Yes to All  [N] No  [L] No to All  [S] Suspend  [?] Help (default is "Y"): n
[↓] [vPodans] Remove-File .\Desktop\qsca.txt
[↓] [vPodans]

Теперь запрос выводится только когда мы явно указываем параметр –Confirm. Параметры мы подключили, как реализовать код? Для этого есть специальная переменная $PsCmdlet, которая используется для обработки параметров командлета/функции. У этой переменной есть метод ShouldProcess(«Target»,»Action description»). В аргумент Target указываете название объекта (в нашем случае — имя файла), над которым будет совершено действие, а в Action description пишите, какое действие будет произведено.

Указание параметра –WhatIf и/или –Confirm вызывает метод ShouldProcess и в зависимости от параметров выполняет нужное действие — выводит запрос или эмулирует выполнение команды. Поэтому мы просто засовываем $PSCmdlet.ShouldProcess() в условный оператор IF и в конструкции Then пишем код, который будет выполнять действие.

Чтобы реализовать функционал параметра –Force, я его поместил в то же условие. Причём, он должен проверяться первым. Это связано с тем, что при выполнении оператора –or, сначала проверяется выражение слева от оператора. Если оно возвращает True, выражение справа от оператора не проверяется. Следовательно, если параметр –Force указан, метод ShouldProcess() просто не вызовется.

При распитиинаписании скриптов, весьма целесообразно включать отладочную информацию в скрипт, которую можно посмотреть, если что-то идёт не так. Запомните, НИКАКИХ этих ваших Write-Host или чего-то ещё. Для этого предусмотрены параметры Verbose и Debug. Verbose применяется для вывода на экран общего хода выполнения скрипта. Debug применяется для включения уже детальной отладочной информации и возможно переключение в пошаговое исполнение скрипта. Эти параметры не надо определять в параметрах функции, они автоматически добавляются к коду при использовании конструкции [CmdletBinding()].

Вот как правильно определять поведение этих параметров:


function Get-Something {
[CmdletBinding()]
    Param()
    if ($PSBoundParameters.Verbose) {$VerbosePreference = "Continue"}
    if ($PSBoundParameters.Debug) {$DebugPreference = "Continue"}
    Write-Verbose "Type some verbose information"
    Write-Debug "Type some debug information"
}

Как мы уже знаем, если указана конструкция [CmdletBinding()], эти параметры автоматически подключаются к функции и мы их не определяем в секции param(). Чтобы отловить эти параметры, мы используем специальную переменную $PSBoundParameters. Более подробней об этой переменной я писал в статье: Cmdlet wrapping и PsBoundParameters. По умолчанию, $VerbosePreference и $DebugPreference = ‘SilentlyContinue’, т.е. даже при указании этих параметров вы ничего не увидите. Поэтому, если параметр указан при вызове функции, мы переводим их в состояние ‘Continue’, что включает вывод для Verbose и Debug.

Давайте посмотрим более реальный случай в несферическом вакууме — сброс пароля локального администратора:


function Reset-LocalAdministratorPassword {
[CmdletBinding(
    ConfirmImpact = 'High',
    SupportsShouldProcess = $true
)]
    param(
        [string]$Password,
        [switch]$Force
    )
    if ($Verbose) {$VerbosePreference = "Continue"}
    if ($Debug) {$DebugPreference = "Continue"}
    $Computer = $Env:COMPUTERNAME
    Write-Debug "Connecting to ADSI provider on '$Computer'"
    $winnt = [ADSI]("WinNT://$Computer,computer")
    Write-Debug "Attempting to retrieve local administrator object"
    $User = $winnt.psbase.children.Find("administrator")
    Write-Debug "Write new password for local administrator. New password '$Password'"
    $User.psbase.invoke("SetPassword",$Password)
    if ($Force -or $PsCmdlet.ShouldProcess("Administrator","Set new password for")) {
        Write-Verbose "Setting new password for local administrator on '$env:computername'"
        Write-Debug "Writing new password for local administrator on '$env:computername'"
        $User.psbase.CommitChanges()
    }
}

И вот вывод в консоли для –Verbose:


[↑] [system32] Reset-LocalAdministratorPassword -Password "P@ssw0rd" -Verbose

Confirm
Are you sure you want to perform this action?
Performing operation "Set new password for" on Target "Administrator".
[Y] Yes  [A] Yes to All  [N] No  [L] No to All  [S] Suspend  [?] Help (default is "Y"):
VERBOSE: Setting new password for local administrator on 'THOR'
[↑] [system32]

для –Debug:


[↑] [system32] Reset-LocalAdministratorPassword -Password "P@ssw0rd" -Debug
DEBUG: Connecting to ADSI provider on 'THOR'

Confirm
Continue with this operation?
[Y] Yes  [A] Yes to All  [H] Halt Command  [S] Suspend  [?] Help (default is "Y"):
DEBUG: Attempting to retrieve local administrator object

Confirm
Continue with this operation?
[Y] Yes  [A] Yes to All  [H] Halt Command  [S] Suspend  [?] Help (default is "Y"):
DEBUG: Write new password for local administrator. New password 'P@ssw0rd'

Confirm
Continue with this operation?
[Y] Yes  [A] Yes to All  [H] Halt Command  [S] Suspend  [?] Help (default is "Y"):

Confirm
Are you sure you want to perform this action?
Performing operation "Set new password for" on Target "Administrator".
[Y] Yes  [A] Yes to All  [N] No  [L] No to All  [S] Suspend  [?] Help (default is "Y"):
DEBUG: Writing new password for local administrator on 'THOR'

Confirm
Continue with this operation?
[Y] Yes  [A] Yes to All  [H] Halt Command  [S] Suspend  [?] Help (default is "Y"):
[↑] [system32]

Так же, мы видим, что Debug включает пошаговое исполнение скрипта, вне зависимоти от состояния параметра Force. Это только в случае, если у нас включен SupportsShouldProcess.

На сегодня вроде всё.


о функциях CmdletBindingAttribute — PowerShell

  • 4 минуты на чтение

В этой статье

Краткое описание

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

Длинное описание

Атрибут CmdletBinding — это атрибут функций, который делает их работают как скомпилированные командлеты, написанные на C #.Он обеспечивает доступ к функциям командлетов.

PowerShell связывает параметры функций, у которых есть CmdletBinding атрибут таким же образом, как он связывает параметры скомпилированных командлетов. В $ PSCmdlet Автоматическая переменная доступна для функций с CmdletBinding , но переменная $ Args недоступна.

В функциях с атрибутом CmdletBinding неизвестные параметры и позиционные аргументы, у которых нет совпадающих позиционных параметров, вызывают сбой привязки параметров.

Примечание

Скомпилированные командлеты используют обязательный атрибут Cmdlet , который аналогичен к атрибуту CmdletBinding , описанному в этом разделе.

Синтаксис

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

  {
    [CmdletBinding (ConfirmImpact = ,
    DefaultParameterSetName = ,
    HelpURI = ,
    SupportsPaging = ,
    SupportsShouldProcess = ,
    PositionalBinding = )]

    Param ($ Parameter1)
    Начинать{}
    Процесс{}
    Конец{}
}
  

Подтвердить Воздействие

Аргумент ConfirmImpact указывает, когда действие функции должно быть подтверждено вызовом метода ShouldProcess .Призыв к ShouldProcess отображает запрос на подтверждение только тогда, когда ConfirmImpact аргумент больше или равен значению $ ConfirmPreference предпочтительная переменная. (Значение аргумента по умолчанию — Средний .) Указывайте этот аргумент, только если SupportsShouldProcess также указывается аргумент.

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

DefaultParameterSetName

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

HelpURI

Аргумент HelpURI указывает интернет-адрес онлайн-версии. раздела справки, в котором описывается функция. Значение HelpURI аргумент должен начинаться с «http» или «https».

Значение аргумента HelpURI используется для значения HelpURI свойство CommandInfo объекта, которое Get-Command возвращает для функция.

Однако, когда файлы справки установлены на компьютере и значение первая ссылка в разделе RelatedLinks файла справки — это URI или значение первой директивы . Link в справке на основе комментариев — это URI, URI в файл справки используется как значение свойства HelpUri функции.

Командлет Get-Help использует значение свойства HelpURI для поиска онлайн-версия раздела справки по функциям, когда параметр Online Get-Help указывается в команде.

ПоддерживаетСтраница

Аргумент SupportsPaging добавляет First , Skip и IncludeTotalCount параметров функции. Эти параметры позволяют пользователям для выбора вывода из очень большого набора результатов. Этот аргумент предназначен для командлеты и функции, возвращающие данные из больших хранилищ данных, поддерживающих данные выбор, например, база данных SQL.

Этот аргумент появился в Windows PowerShell 3.0.

  • Первый : получает только первые n объектов.
  • Пропустить : игнорирует первые n объектов, а затем получает оставшиеся объекты.
  • IncludeTotalCount : сообщает количество объектов в наборе данных ( целое число), за которым следуют объекты. Если командлет не может определить общую count, возвращается «Неизвестное общее количество».

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

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

  функция Get-Numbers {
    [CmdletBinding (SupportsPaging = $ true)]
    param ()

    $ FirstNumber = [Math] :: Min ($ PSCmdlet.PagingParameters.Skip, 100)
    $ LastNumber = [Math] :: Min ($ PSCmdlet.PagingParameters.First +
      $ FirstNumber - 1, 100)

    if ($ PSCmdlet.PagingParameters.IncludeTotalCount) {
        $ TotalCountAccuracy = 1,0
        $ TotalCount = $ PSCmdlet.PagingParameters.NewTotalCount (100,
          $ TotalCountAccuracy)
        Запись-вывод $ TotalCount
    }
    $ FirstNumber .. $ LastNumber | Запись-вывод
}
  

Поддерживает процесс

Аргумент SupportsShouldProcess добавляет Подтвердить и WhatIf параметры функции. Параметр Confirm запрашивает пользователя перед он запускает команду для каждого объекта в конвейере. Параметр WhatIf перечисляет изменения, которые команда внесет, вместо выполнения команды.

Позиционная привязка

Аргумент PositionalBinding определяет, будут ли параметры в функции по умолчанию позиционные. Значение по умолчанию — $ True . Ты можешь использовать аргумент PositionalBinding со значением $ False для отключения позиционная привязка.

Аргумент PositionalBinding представлен в Windows PowerShell 3.0.

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

Если параметры не являются позиционными (они «именованные»), параметр имя (или аббревиатура, или псевдоним имени) является обязательным в команде.

Когда PositionalBinding имеет значение $ True , параметры функции позиционируются По умолчанию. PowerShell присваивает параметрам номер позиции в следующем порядке: которые они объявлены в функции.

Когда PositionalBinding имеет значение $ False , параметры функции не являются позиционными. по умолчанию. Если аргумент Position атрибута Parameter не объявлено в параметре, имя параметра (или псевдоним, или аббревиатура) должен быть включен, когда параметр используется в функции.

Аргумент Позиция атрибута Параметр имеет приоритет над значение по умолчанию PositionalBinding .Вы можете использовать аргумент Position чтобы указать значение позиции для параметра. Для получения дополнительной информации о Позиция аргумент, см. about_Functions_Advanced_Parameters.

Банкноты

Аргумент SupportsTransactions не поддерживается в расширенных функциях.

Ключевые слова

about_Functions_CmdletBinding_Attribute

См. Также

about_Functions

about_Functions_Advanced

about_Functions_Advanced_Methods

about_Functions_Advanced_Parameters

about_Functions_OutputTypeAttribute

Weekend Scripter: атрибут Cmdletbinding упрощает функции PowerShell

Dr Scripto

Резюме : Разработчик сценариев Microsoft, Эд Уилсон, рассказывает об использовании атрибута cmdletbinding для упрощения функций Windows PowerShell.Разработчик сценариев Microsoft, Эд Уилсон, здесь. Этим утром я сидел, играя с Windows PowerShell, и понял, что мало писал об атрибуте cmdletbinding . Итак, начнем … Первым шагом в создании расширенной функции является добавление атрибута cmdletbinding . Это единственное добавление добавляет несколько возможностей, таких как дополнительная проверка параметров и возможность простого использования командлета Write-Verbose . Чтобы использовать атрибут cmdletbinding , вы помещаете атрибут в тег атрибута с квадратной скобкой и включаете его в первую строку без комментариев в функции.Кроме того, атрибут cmdletbinding требует использования ключевого слова param . Если ваша расширенная функция не требует параметров, вы можете использовать ключевое слово без указания каких-либо параметров. Этот метод показан здесь:

функция моя функция

{

[cmdletbinding ()]

Param ()

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

функция моя функция

{

[cmdletbinding ()]

Param ()

«Подробный поток» с расширенной записью

}

Простые подробные сообщения

При загрузке функция разрешает использовать переключаемый параметр подробный . Использование этого параметра приводит к записи каждой инструкции Write-Verbose в выходные данные консоли Windows PowerShell. Когда функция работает без переключателя verbose , вывод из потока verbose не отображается.Самое замечательное в использовании Write-Verbose заключается в том, что подробная информация (например, о ходе выполнения удаленных подключений, загрузки модулей и других операций, которые могут привести к сбою сценария) выводится по мере возникновения событий. Это обеспечивает встроенный диагностический режим для расширенной функции практически без дополнительного программирования.

Автоматическая проверка параметров

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

функция моя функция

{

# [cmdletbinding ()]

Param ($ a)

долл. США

# $ args

} Когда эта функция запускается, любое значение, указанное для параметра –a , появляется в выходных данных, как показано здесь:

PS C: Usersed.IAMMRED> my-function -a 1,2,3,4

1

2

3

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

PS C: Usersed.IAMMRED> my-function -a 1 2,3,4

1 Остальные параметры появятся в автоматической переменной $ args . Размещение переменной $ args в функции иллюстрирует это. Сначала добавьте автоматическую переменную $ args , как показано здесь:

функция моя функция

{

# [cmdletbinding ()]

Param ($ a)

долл. США

$ аргументы

} Теперь при вызове функции без первой запятой появляется следующий вывод.

PS C: Usersed.IAMMRED> my-function -a 1 2,3,4

1

2

3

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

функция моя функция

{

# [cmdletbinding ()]

Param ($ a)

долл. США

$ args.количество

} При передаче в функцию нескольких аргументов значение свойства count увеличивается. В выводе, показанном здесь, первая цифра 1 возвращается из позиции –a . Число 3 — это количество дополнительных аргументов (то есть тех, которые не указаны для указанного аргумента).

PS C: Usersed.IAMMRED> my-function 1 2 3 4

1

3 Используя эту функцию и проверяя свойство count для $ args , одна строка кода предотвращает поступление дополнительных аргументов в функцию.Это изменение показано здесь:

функция моя функция

{

# [cmdletbinding ()]

Param ($ a, $ b)

долл. США

млрд долларов

if ($ args.count -gt 0) {Ошибка записи «предоставлены необработанные аргументы»}

} При запуске, как показано в следующем коде, первые два предоставленных параметра принимаются для параметров –a и –b . Два оставшихся параметра входят в автоматическую переменную $ args .Это увеличивает свойство count для $ args до значения больше 0, и поэтому возникает ошибка.

PS C: Usersed.IAMMRED> my-function 1 2 3 4

1

2

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

В строке: 1 символ: 12

+ моя-функция <<<< 1 2 3 4

+ CategoryInfo: NotSpecified: (:) [Ошибка записи], исключение WriteErrorException

+ FullyQualifiedErrorId: Microsoft.PowerShell.Commands.WriteErrorException, my-

функция Самый простой способ определить необработанные параметры, передаваемые функции Windows PowerShell, — использовать атрибут cmdletbinding . Одной из особенностей использования атрибута cmdletbinding является то, что он генерирует ошибку, когда необработанные значения параметров появляются в командной строке. Следующая функция иллюстрирует атрибут cmdletbinding .

функция моя функция

{

[cmdletbinding ()]

Param ($ a, $ b)

долл. США

млрд долларов

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

PS C: Используется.IAMMRED> моя-функция 1 2 3 4

моя-функция: не найден позиционный параметр, который принимает аргумент «3».

В строке: 1 символ: 12

+ моя-функция <<<< 1 2 3 4

+ CategoryInfo: InvalidArgument: (:) [моя-функция], ParameterBindingE

xception

+ FullyQualifiedErrorId: PositionalParameterNotFound, моя функция Я приглашаю вас подписаться на меня в Twitter и Facebook. Если у вас есть какие-либо вопросы, отправьте мне письмо по адресу scripter @ microsoft.com, или разместите свои вопросы на официальном форуме Scripting Guys. До завтра. А пока мир. Эд Уилсон, специалист по сценариям Microsoft

Доктор Скрипто

Скриптер, PowerShell, vbScript, BAT, CMD

Подписаться

powershell — Как определить функции в сценарии CmdletBinding ()?

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

  [CmdletBinding ()]
парам (
    [Строка] $ Значение
)

НАЧИНАТЬ {
    Функция f () {
        param ([String] $ m)
        Write-Host $ m
    }

    f ("Начать")
}

ПРОЦЕСС {
    f ("Процесс:" + $ Значение)
}

КОНЕЦ {
    f («Конец»)
}
  

Цитата из about_Functions :

Трубопровод от объектов к функциям

Любая функция может принимать входные данные из конвейера. Вы можете контролировать, как функция обрабатывает ввод из конвейера, используя ключевые слова Begin, Process и End.В следующем примере синтаксиса показаны три ключевых слова:

  функция <имя> {
    begin {<список операторов>}
    процесс {<список операторов>}
    конец {<список операторов>}
}
  

Список операторов Begin запускается только один раз в начале функции.

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

После того, как функция получит все объекты в конвейере, список операторов End запускается один раз. Если не используются ключевые слова Begin, Process или End, все операторы обрабатываются как список операторов End.


Если ваш код не обрабатывает ввод конвейера, вы можете полностью отбросить блоки begin , process и end и поместить все в тело скрипта:

  [CmdletBinding ()]
парам (
    [Строка] $ Значение
)

Функция f () {
    param ([String] $ m)
    Write-Host $ m
}

f ("Начать")
f ("Процесс:" + $ Значение)
f («Конец»)
  

Изменить: Если вы хотите поместить определение f в конец вашего скрипта, вам необходимо определить остальную часть вашего кода как функцию worker / main / any и вызвать эту функцию в конце вашего скрипта. , д.г .:

  [CmdletBinding ()]
парам (
    [Строка] $ Значение
)

function Main {
    [CmdletBinding ()]
    парам (
        [Строка] $ Param
    )

    НАЧАТЬ {f ("Начать")}
    ПРОЦЕСС {f ("Процесс:" + $ Param)}
    КОНЕЦ {f ("Конец")}
}

Функция f () {
    param ([String] $ m)
    Write-Host $ m
}

Основное значение $
  

Когда использовать CmdletBinding в PowerShell?

В Sabin.IO мы - большие сторонники чистого кода. Мы часто используем PowerShell для автоматизации и хотим, чтобы наш код был чистым.Вы ведь все автоматизируете? Если нет, посмотрите слайд с недавней встречи:

Для меня чистый код в PowerShell означает (и не ограничивается):

  1. Небольшие автономные функции, которые несут единственную ответственность
  2. Количество аргументов для функция должна быть как можно меньше
  3. Согласованное форматирование
  4. Отсутствие дублирования кода
  5. Модули, которые скрывают внутренние функции и предоставляют только то, что необходимо

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

Get-Help about_CommonParameters

Вот отрывок из файла справки:

В следующем списке показаны общие параметры. Их псевдонимы указаны в скобках:
.

-Debug (db)
-ErrorAction (ea)
-ErrorVariable (ev)
-InformationAction
-InformationVariable
-OutVariable (ov)
-OutBuffer (ob)
-PipelineVariable (pv) 90se589 WarningAction (wa)
-Переменная предупреждения (wv

Параметры снижения риска:
-WhatIf (wi)
-Confirm (cf)

Все они становятся доступны вам в ваших функциях, когда вы используете [CmdletBinding ()] в верхней части функции.Однако есть некоторые подводные камни, так что давайте рассмотрим их.

Рассмотрим следующий код:

Если мы поставим точку в источнике этого файла и вызовем функцию Get-Message без параметров, мы получим:

В приведенном выше примере мы не указали параметр - UseInternal , поэтому функция не вызывает внутреннюю функцию Get-MessageFromInternalFunction . Обратите внимание, что подробное сообщение не было напечатано. Это связано с тем, что параметр –Verbose не был передан функции И для переменной предпочтения $ VerbosePreference установлено значение по умолчанию SilentlyContinue.Для получения информации о переменных предпочтений см. Справку по

get-help about_preference_variables

Если мы передадим –Verbose сейчас, мы должны увидеть подробный вывод:

Теперь, как вы думаете, что произойдет, если мы вызовем Get- Сообщение с параметром –UseInternal и – Verbose ? Подумайте об этом, потому что это меня удивило.

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

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

Давайте изменим код нашей внутренней функции и добавим CmdletBinding .Если мы вызываем Get-Message с теми же параметрами, что и раньше, он ведет себя так же.

Что, если вы хотите вызвать функцию Get-Message и просмотреть подробные сообщения, но вы хотите подавить подробные сообщения во внутренних (или внутренних) функциях? Если вы не укажете CmdletBinding во внутренних функциях, вы не сможете этого сделать. Рассмотрим этот код, особенно строки 2 и 14:

Если мы сейчас вызовем Get-Message –UseInternal –Verbose:

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

Нам нужно знать о поведении переменных предпочтений и о том, что пользователи ваших модулей могут установить для него значения, отличные от значений по умолчанию. По умолчанию для – Verbose установлено значение SilentlyContinue , что означает, что подробные сообщения не выводятся, если не установлен параметр Verbose. Что, если бы я выполнил указанную выше функцию с $ VerbosePreference = ‘Continue’? Подробные сообщения печатаются без использования –Verbose в качестве параметра.

Обратите внимание, что параметр -Verbose: $ False соблюдается, даже если для $ VerbosePreference установлено значение «Продолжить».

Если теперь мы вызываем Get-Message –UseInternal

Подробные сообщения во внешней функции отображаются без указания –Verbose в качестве параметра, но подробные сообщения во внутренней функции подавляются.

Используйте CmdletBinding во всех своих публичных и внутренних функциях.

Написать чистый код.

Все автоматизировать.

Создание более безопасных функций PowerShell - powershell.one

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

В PowerShell 2 команда добавила расширенных функций , которые теперь поддерживают тот же набор функций командлетов. Однако ограниченные Simple Functions все еще существуют, и с атрибутом [CmdletBinding ()] вы убедитесь, что получаете мощные Advanced Functions вместо ограниченных Simple Functions .

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

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

Включение дополнительных функций

Атрибут [CmdletBinding ()] может быть присоединен к блокам param () внутри функций PowerShell и управляет основным поведением вашей функции.Наиболее распространенным вариантом использования является превращение простой функции в расширенную функцию . Возможно, вы наткнулись на такой код:

  функция Out-PsoPdf
{
  [CmdletBinding ()]
  парам
  (
    [Нить]
    $ Путь,
  
    [int]
    $ Timeout = 5,
    
    [выключатель]
    $ Показать
  )
  
  # здесь есть место для фактического кода
  # пока пусто
}
  

Как видите, [CmdletBinding ()] добавляется к блоку param () .Но почему? В конце концов, атрибут полностью пуст и не определяет значений в скобках.

Простые и расширенные функции

Если функция использует хотя бы один (любой) атрибут, PowerShell превращает его в расширенную функцию и включает все ее функции. Наиболее заметное изменение происходит в его параметрах: Advanced Functions автоматически добавляет все общие параметры, такие как -Verbose и -ErrorAction . Простая функция отображает только параметры, которые вы определили в своем блоке param () .

Протестируйте: запустите приведенный выше код, затем запустите Out-PsoPdf и посмотрите его параметры. Вы получите все стандартные параметры, такие как -ErrorAction и -Verbose , бесплатно.

Автоматически добавленные общие параметры полностью функциональны. Поэтому, когда вы вызываете свою функцию с помощью -ErrorAction Ignore , этот параметр будет передан всем командам PowerShell в вашей функции и подавит все ошибки. Точно так же, если вы используете Write-Verbose в своем коде для вывода сообщений, они будут скрыты, если функция не вызывается с общим параметром (переключателем) -Verbose .

На самом деле: -Verbose устанавливает значение по умолчанию для $ VerbosePreference , тогда как -ErrorAction устанавливает значение по умолчанию для $ ErrorActionPreference .

После удаления [CmdletBinding ()] из приведенного выше кода вы получите простую функцию , и при ее запуске вы увидите только свои собственные параметры, которые были определены внутри param () . Все общие параметры исчезли. Они являются функцией Advanced Functions .

Любой атрибут включает атрибуты

Фактически, любой атрибут включает расширенных функций . Как только вы начнете использовать атрибуты [Parameter ()] для управления функциями параметров, вы также получите Advanced Functions , и технически вы можете удалить пустой атрибут [CmdletBinding ()] :

  функция Out-PsoPdf
{
  парам
  (
    [Параметр (обязательный)]
    [Нить]
    $ Путь,
  
    [int]
    $ Timeout = 5,
    
    [выключатель]
    $ Показать
  )
  
  # здесь есть место для фактического кода
  # пока пусто
}
  

Рекомендуется всегда добавлять [CmdletBinding ()] к вашему блоку param () , чтобы гарантировать создание расширенной функции , даже если вы используете другие атрибуты и в этом нет особой необходимости.

Существует множество функций PowerShell , которые работают только с расширенными функциями , например, поддержка значений параметров по умолчанию (определенных в $ PSDefaultParameterValues ​​). Чтобы случайно не столкнуться с проблемами совместимости, рекомендуется регулярно использовать [CmdletBinding ()] в вашем коде.

Доступные значения

[CmdletBinding ()] может установить ряд параметров. В одном из вспомогательных скриптов из статьи для начинающих доступны следующие значения:

  PS> $ attributes.CmdletBinding

Тип имени
---- ----
PositionalBinding System.Boolean
DefaultParameterSetName System.String
ПоддерживаетShouldProcess System.Boolean
Поддерживает Paging System.Boolean
SupportsTransactions System.Boolean
Подтвердите ударную систему.Management.Automation.ConfirmImpact
HelpUri System.String
RemotingCapability System.Management.Automation.RemotingCapability
  

Значения атрибута управляют четырьмя отдельными областями:

  • Risk Mitigation : SupportsShouldProcess и ConfirmImpact контролируют, насколько рискован ваш код и поддерживает ли он снижение рисков, добавляя общие параметры -WhatIf и -Confirm .Это то, что мы освещаем сегодня.

Остальные области рассматриваются в других частях этой серии:

  • Paging : SupportsPaging автоматически добавляет общие параметры -First , -Skip и -IncludeTotalCount , предназначенный для обработки больших наборов данных
  • Параметры : PositionalBinding и DefaultParameterSetName управляют тем, как аргументы привязываются к вашим параметрам
  • Информация : HelpUri и RemotingCapability предоставляют такую ​​информацию, как URL-адрес для справочной информации, и типы методов удаленного взаимодействия, используемые вашим кодом

SupportsTransaction устарело, поскольку PowerShell больше не поддерживает транзакции (и никогда не поддерживала).

Снижение рисков

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

Моделирование и подтверждение

Это можно сделать, просто смоделировав код ( -WhatIf ) или подтвердив каждую отдельную операцию (-Подтвердить ):

  Stop-Service -Name a * -WhatIf
  

Снижение риска имеет смысл только для команд, которые на самом деле являются рискованными.Если команда только считывает данные, например Get-Date , нет особого смысла в ее моделировании, поэтому -WhatIf и -Confirm недоступны в для каждой команды PowerShell .

Другими словами, когда команда, которую вы собираетесь использовать , имеет параметр -WhatIf и -Confirm , вы точно знаете одно: будьте осторожны, это может быть рискованно.

Хотя приведенный выше код явно указывает на ограничение карьеры , переход (CLM) на производственных серверах, часто риски не так очевидны.Вот почему PowerShell иногда автоматически добавляет -Confirm к командам, и вы получаете неожиданные (но иногда спасающие жизнь) всплывающие окна подтверждения.

Автоматическое подтверждение

Оба параметра снижения риска представляют собой отличную подстраховку при условии, что вы запросили их до того, как запустил рискованную команду. Как узнать, насколько рискованна команда? Именно здесь срабатывает режим снижения рисков PowerShells и помогает автоматически обнаруживать рискованные команды до того, как вы их запускаете.

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

  • Команда : каждый автор команды может объявить уровень риска (насколько велика вероятность испортить ситуацию) и выбрать один из трех уровней: Низкий , Средний и Высокий . Уровень риска Высокий будет операцией, которую нельзя отменить, т.е.е. удаление учетной записи пользователя или файла.

  • Вы, , можете объявить свой личный уровень риска (определенный в $ ConfirmPreference ), который может зависеть от вашего опыта, от того, с какой системой вы работаете в настоящее время и насколько она чувствительна.

Когда команда имеет уровень риска, равный или выше вашего уровня риска, PowerShell автоматически включает режим подтверждения, как если бы вы вручную запросили подтверждение с помощью параметра -Confirm .Доступные уровни риска определены здесь:

  [Enum] :: GetNames ([Management.Automation.ConfirmImpact])
  

Просто проверьте это! Это объясняет, почему некоторые команды запрашивают подтверждение, а другие - нет, и как это можно контролировать:

  # проверить текущее предпочтение подтверждения (по умолчанию 'High')
$ ConfirmPreference

# запускаем команду с определенным риском и, следовательно, поддерживающую -Confirm
# (команды без -Confirm и -WhatIf не участвуют в PowerShells
# снижение риска либо потому, что они не меняют систему и
# нет риска, или потому что автор не реализовал меры по снижению риска
#  служба поддержки)
# Создание нового файла меняет систему и поддерживает снижение рисков:
Новый элемент -Path $ env: temp \ testfile.txt -Подтвердить

# попробуйте то же самое без явного запроса подтверждения:
# (диалоговое окно подтверждения не открывается)
Новый элемент -Путь $ env: temp \ testfile.txt

# трусливо измените ConfirmPreference на "Low" сейчас:
$ ConfirmPreference = 'Низкий'

# попробуй еще раз:
Новый элемент -Путь $ env: temp \ testfile.txt
  

Диалоги более или менее подтверждения

Вы можете контролировать, как часто PowerShell будет отображать диалоговые окна подтверждения, изменив $ ConfirmPreference :

  • Если вы работаете в сверхчувствительной среде или впервые используете PowerShell , вы можете установить для него значение «Низкий».Любая рискованная команда, даже если она просто создает новый файл, теперь запросит подтверждение.
  • Если вы хотите запустить код PowerShell в автоматическом режиме и хотите закрыть для любое диалоговое окно подтверждения , которое может блокировать выполнение, установите для него значение «Нет». Теперь PowerShell никогда не будет автоматически выдавать подтверждения, даже если ваш код массово удаляет весь ваш Active Directory .
  # включить подтверждение для ВСЕХ команд PowerShell
$ ConfirmPreference = "Низкий"

# ПРИМЕЧАНИЕ: это НЕ рекомендуемая конфигурация по умолчанию.
# Теперь вы можете столкнуться с ТОННАМИ диалоговых окон подтверждения
  

Хотя $ ConfirmPreference управляет диалоговым окном подтверждения, вы также можете задать PowerShell еще более строгие ограничения и использовать -WhatIf для всех рискованных команд: установите $ WhatIfPreference на $ true .Это может быть хорошей защитой от детей для PowerShell на производственных серверах , но с вы также гарантированно ничего не сделаете.

Вид. Помните, что снижение рисков PowerShell (например, -WhatIf ) применяется только к командам PowerShell : командлетам и функциям. Такие приложения, как shutdown.exe или format.exe , не заботятся.

Определение уровней риска

Давайте изменим перспективу и посмотрим на команды: как они объявляют, насколько они рискованны? Это когда [CmdletBinding ()] становится важным.Двоичный командлет авторы добавляют этот атрибут в свой код. Итак, давайте начнем с чтения заявленных уровней риска двоичных командлетов .

New-Item выскакивало диалоговое окно подтверждения в предыдущем примере всякий раз, когда для $ ConfirmPreference было установлено значение Low , но не со значением по умолчанию High . Таким образом, уровень риска New-Item должен быть либо Low , либо Medium .

Вот код, который может считывать значения атрибута [CmdletBinding ()] из двоичного файла.NET-сборки. Считывает значения для команды New-Item :

  # получить интересующий вас командлет
# (должен быть командлет!)
$ cmdletName = 'Новый элемент'
$ cmd = Get-Command -Name $ cmdletName -CommandType Cmdlet
# получить тип .NET, реализующий команду:
$ type = $ cmd.ImplementingType
# получить атрибут [CmdletBinding ()], присвоенный этому типу:
# (этот атрибут определен как тип .NET в
# пространство имен "System.Management.Automation" и имя типа
# имеет суффикс "Атрибут".Всегда верно для всех атрибутов PS)
$ attribute = $ type.GetCustomAttributes ([System.Management.Automation.CmdletAttribute], $ true)

# отобразить настройки:
$ attribute | Выбрать-объект -Свойство *
  

Результат выглядит так:

  Имя существительное: Предмет
VerbName: Новый
DefaultParameterSetName: pathSet
SupportsShouldProcess: True
SupportsPaging: False
ПоддерживаетОперации: True

ConfirmImpact: средний

HelpUri: https: // go.microsoft.com/fwlink/?LinkID=113353
Возможность удаленного взаимодействия: PowerShell
TypeId: System.Management.Automation.CmdletAttribute
  

New-Item имеет ConfirmImpact из Medium . В этом есть смысл: запись новых файлов может повлиять на систему, но если это было сделано случайно, удаление нового файла вполне возможно, так что это средний риск.

Давайте проверим ConfirmImpact всех командлетов в вашей системе и определим очень рискованные командлеты:

  # получить все командлеты...
Get-Command -CommandType Cmdlet |
  # убедитесь, что модуль командлета загружен ...
  Foreach-Object {
    Get-Command -CommandType Cmdlet -Name $ _. Name
  } |
  # получить значение атрибута cmdletinfo:
  Foreach-Object {
    [PSCustomObject] @ {
      Имя = $ _. Имя
      ConfirmImpact = $ _. ImplementingType.GetCustomAttributes ([System.Management.Automation.CmdletAttribute], $ true) .ConfirmImpact
    }
  } |
  Сортировка-Объект -Свойство ConfirmImpact-По убыванию |
  Out-GridView
  

Результат отсортирован по ConfirmImpact с командлетами в категории High вверху.

Вы можете задаться вопросом, почему код вызывает Get-Command дважды. Первый вызов перечисляет все доступные командлеты в вашей системе, включая те, которые поступают из модулей, которые в настоящее время не загружены в память.

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

Объявление «ConfirmImpact»

Если ваши функции PowerShell делают что-то рискованное и каким-либо образом изменяют систему, пора добавить поддержку уровней риска. Это начинается с объявления о том, насколько на самом деле рискованна ваша функция:

  функция Out-PsoPdf
{
  [CmdletBinding (ConfirmImpact = 'Low')]
  парам
  (
    [Нить]
    $ Путь,
  
    [int]
    $ Timeout = 5,
    
    [выключатель]
    $ Показать
  )
  
  Write-Host "Что-то делает" -ForegroundColor Green
}
  

Атрибут использует ConfirmImpact для объявления уровня риска.Запустите код, затем запустите функцию Out-PsoPdf . Он выводит зеленый текст.

Затем измените ConfirmImpact на Low и снова запустите код. Затем снова запустите Out-PsoPfd . Ой, без изменений! Зеленый текст снова отображается! Вы можете догадаться, что случилось? Если нет, см. Ниже.

Добавление поддержки для снижения рисков

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

Итак, ConfirmImpact всегда следует комбинировать с SupportsShouldProcess , который добавляет общие параметры -WhatIf и -Confirm :

  функция Out-PsoPdf
{
  [CmdletBinding (ConfirmImpact = 'High', SupportsShouldProcess)]
  парам
  (
    [Нить]
    $ Путь,
  
    [int]
    $ Timeout = 5,
    
    [выключатель]
    $ Показать
  )
  
  Write-Host "Что-то делает" -ForegroundColor Green
}
  

Это все равно не принесет много пользы, потому что, когда вы вручную вызываете -Confirm (который теперь присутствует благодаря SupportsShouldProcess ), ваш код функции не сообщает PowerShell , что делать:

Добавление обработчиков подтверждений

Для поддержки снижения рисков вам нужно спросить PowerShell , можно ли выполнять рискованный код или нет.Затем используйте одно или несколько условий для выполнения рискованного кода, только если система снижения рисков * PowerShells дала положительный результат:

  функция Out-PsoPdf
{
  [CmdletBinding (ConfirmImpact = 'High', SupportsShouldProcess)]
  парам
  (
    [Нить]
    $ Путь,
  
    [int]
    $ Timeout = 5,
    
    [выключатель]
    $ Показать
  )
  
  # спросите PowerShell, должен ли выполняться код:
  $ shouldProcess = $ PSCmdlet.ShouldProcess ($ env: COMPUTERNAME, "что-то безумное")
    
  # это ВСЕГДА будет выполняться
  "ConfirmPreference: $ ConfirmPreference"
  "WhatIfPreference: $ WhatIfPreference"
  
  # по возможности используйте условие, чтобы определить,
  # код должен выполняться:
  если ($ shouldProcess)
  {
    Write-Host "Выполняется!" -ForegroundColor Зеленый
  }
  еще
  {
    Write-Host "Пропускаю!" -ForegroundColor Красный
  }
  
  # любой внешний код всегда будет выполняться
  "Сделанный."
  
  # используйте условия так часто, как это необходимо
  # поскольку вы используете сохраненный результат в $ shouldProcess,
  # больше нет надоедливых всплывающих окон с подтверждением:
  если ($ shouldProcess)
  {
    Write-Host "Выполняется снова!" -ForegroundColor Зеленый
  }
  еще
  {
    Write-Host "Опять пропускаю!" -ForegroundColor Красный
  }
}
  

Теперь Out-PsoPdf полностью поддерживает систему снижения рисков. Заявлен уровень собственного риска Высокий :

  • Если для $ ConfirmPreference задано значение High (значение по умолчанию), PowerShell автоматически запрашивает подтверждение, а когда пользователь принимает, $ PSCmdlet.ShouldProcess () возвращает $ true , иначе $ false . Таким образом, в зависимости от того, что выбрал пользователь, вы увидите зеленый или красный текст.
  • Когда пользователь вручную добавляет -Confirm , диалоговое окно подтверждения работает таким же образом
  • Когда пользователь вручную добавляет -WhatIf , $ PSCmdlet.ShouldProcess () возвращает $ false , и вы видите красный текст.

Есть пара важных ошибок:

  • Каждый раз, когда ваш код запускает новое отдельное действие, он должен вызывать $ PSCmdlet.ShouldProcess () и отправьте содержательный текст описания, чтобы пользователь получал запрос на каждое действие.
  • Каждый раз, когда вы вызываете $ PSCmdlet.ShouldProcess () , убедитесь, что вы сохранили результат в переменной и повторно использовали результат , а не снова вызывали $ PSCmdlet.ShouldProcess () для того же действия. Каждый раз, когда вы вызываете $ PSCmdlet.ShouldProcess () , может появиться диалоговое окно подтверждения.

Последние штрихи (и ошибки)

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

Понимание проблемы

Чтобы полностью понять систему снижения рисков, возьмите свежий кофе и проглотите этот код:

  функция Out-PsoPdf
{
  [CmdletBinding (ConfirmImpact = 'Medium', SupportsShouldProcess)]
  парам
  (
    [Нить]
    $ Путь,
  
    [int]
    $ Timeout = 5,
    
    [выключатель]
    $ Показать
  )
  
  # спросите PowerShell, должен ли выполняться код:
  $ shouldProcess = $ PSCmdlet.ShouldProcess ($ env: COMPUTERNAME, «что-то чрезвычайно рискованное»)
    
  # это ВСЕГДА будет выполняться
  "ConfirmPreference: $ ConfirmPreference"
  "WhatIfPreference: $ WhatIfPreference"
  
  # по возможности используйте условие, чтобы определить,
  # код должен выполняться:
  если ($ shouldProcess)
  {
    Новый элемент -Path $ env: temp \ test.txt-Force
    Новый элемент -Путь $ env: temp \ test.txt -Force
    Write-Host "Выполняется!" -ForegroundColor Зеленый
  }
  еще
  {
    Новый элемент -Путь $ env: temp \ test.txt -Force
    Write-Host "Пропускаю!" -ForegroundColor Красный
  }
}
  

Out-PsoPdf имеет заявленный уровень риска Средний . Убедитесь, что в вашем предпочтении установлено значение по умолчанию Высокий :

  $ ConfirmPreference = 'Высокий'
  

Затем запустите приведенный выше код и запустите Out-PsoPdf .Функция показывает зеленое сообщение и выполняется. Это ожидаемо, потому что его уровень риска был на ниже уровня риска в $ ConfirmPreference .

Теперь измените свои предпочтения на Средний :

  $ ConfirmPreference = 'Средний'
  

Повторите шаги. Теперь вы видите диалоговое окно подтверждения с вашим собственным подтверждающим сообщением, вызванное вызовом $ PSCmdlet.ShouldProcess () . Это ожидаемо, потому что уровень риска вашей функции ( Средний ) теперь равен или превышает порог в $ ConfirmPreference ( Средний ).Щелкните Да .

Теперь вы видите еще одно диалоговое окно подтверждения, запускаемое New-Item , и когда вы нажимаете Yes , открывается еще одно диалоговое окно подтверждения, запускаемое другим экземпляром New-Item . То есть , а не : ваш условный код должен быть атомом. Либо пользователь хочет его запускать, либо нет.

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

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

Откроется диалоговое окно подтверждения. Щелкните Да . Подтверждение открывается еще дважды.Каждый раз нажимайте Да . Теперь у вас есть зеленый результат, и когда вы посмотрите на переменные предпочтений, они изменились:

  PS> Out-PsoPdf-Подтвердить
ConfirmPreference: низкий
WhatIfPreference: False
  

Поскольку пользователь указал -Confirm , PowerShell временно изменил $ ConfirmPreference на Low (обеспечение всех команд с подтверждением триггера любого уровня риска).

Причина, по которой оболочка PowerShell ведет себя так странно, заключается в том, что она представляет собой средство снижения риска для бедняков : только включив -WhatIf и -Подтвердите , вы получите автоматическое снижение рисков путем пересылки настроек всем команды, используемые внутри вашей функции.

Однако вы можете получить множество нежелательных и избыточных диалогов, поэтому Smart Man’s Risk Mitigation вызывает $ PSCmdlet.ShouldProcess () и управляет выполнением кода. Чтобы полностью контролировать его, вам необходимо сбросить переменные предпочтений (см. Ниже).

Сбросить предпочтительные переменные

После того, как вы используете $ PSCmdlet.ShouldProcess () и сами решите, какой код должен выполняться, когда, вы также должны сбросить некоторые из предпочтительных переменных, чтобы убедиться, что все другие команды, которые вы используете, действуют соответствующим образом:

  функция Out-PsoPdf
{
  [CmdletBinding (ConfirmImpact = 'Medium', SupportsShouldProcess)]
  парам
  (
    [Нить]
    $ Путь,
  
    [int]
    $ Timeout = 5,
    
    [выключатель]
    $ Показать
  )
  
  # спросите PowerShell, должен ли выполняться код:
  $ shouldProcess = $ PSCmdlet.ShouldProcess ($ env: COMPUTERNAME, "что-то безумное")
  
  # отключить автоматические диалоги подтверждения для всех команд
  $ ConfirmPreference = 'Нет'
  
  # по возможности используйте условие, чтобы определить,
  # код должен выполняться:
  если ($ shouldProcess)
  {
    Новый элемент -Путь $ env: temp \ test.txt -Force
    Новый элемент -Путь $ env: temp \ test.txt -Force
    Write-Host "Выполняется!" -ForegroundColor Зеленый
  }
  еще
  {
    Новый элемент -Путь $ env: temp \ test.txt -Force
    Write-Host "Пропускаю!" -ForegroundColor Красный
  }
}
  

Теперь все работает как положено:

  • Только вы можете контролировать, когда и где подходит диалоговое окно подтверждения, вызывая $ PSCmdlet.ShouldProcess ()
  • Любое диалоговое окно автоматического подтверждения подавляется путем установки $ ConfirmPreference на $ false . Поскольку это локальная переменная, она применяется только к внутренней части вашей функции
  • .

Вы можете возразить, что, установив для $ ConfirmPreference значение $ false , любая команда вне вашего условия всегда будет выполняться. И это правильно. Как только вы возьмете дело в свои руки, ваша ответственность - определить все рискованные команды и поместить их в свой условный код.Таких условий может быть сколько угодно.

Заключение

На этот раз было рассмотрено много вещей, и атрибут [CmdletBinding ()] может предложить гораздо больше (что мы рассмотрим в следующей части этой серии). Позвольте мне быстро резюмировать наиболее важные моменты:

  • Как обычный пользователь, используйте $ ConfirmPreference , чтобы контролировать, как часто вы хотите видеть диалоговые окна автоматического подтверждения, или установите значение None , чтобы запускать код в автоматическом режиме.
  • При создании функций PowerShell убедитесь, что вы создали расширенных функций , используя хотя бы один атрибут, даже если он пуст, то есть [CmdletBinding ()] .
  • Когда ваша функция PowerShell вносит изменения в систему или иным образом может испортить ситуацию, добавьте поддержку системы снижения рисков PowerShells :
    • Добавьте в код уровень ConfirmImpact , который описывает уровень риска ( низкий , средний , высокий )
    • Добавьте поддержку для -WhatIf и -Подтвердите , добавив значение * SupportsShouldProcess
    • Выполнить рискованный код в зависимости от условий. $ PSCmdlet.ShouldProcess () сообщает вам, должны ли выполняться эти условия.
    • Reset $ ConfirmPreference to None внутри вашей функции, чтобы убедиться, что вы отключили все другие всплывающие окна подтверждения и полностью управляете выполнением в соответствии с вашими условиями.

Что дальше

В этой части подробно рассматривается система снижения рисков , которая является одной из областей, охватываемых атрибутом [CmdletBinding ()] .В следующей части мы рассмотрим оставшиеся уловки, которые можно проделать с этим атрибутом.

Так что следите за обновлениями, если вы жаждете большего! И убедитесь, что на вашем радаре есть PowerShell Conference EU 2020. Если вам нравятся такие вещи, то это место в июне. Увидимся там!

рекомендаций по разработке функций PowerShell - Microsoft Certified Professional Magazine Online

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

Лучшие практики для проектирования функций PowerShell

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

  • Автор: Адам Бертрам
  • 27.10.2016

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

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

Передовой опыт 1. Использование дополнительных функций
В PowerShell вы можете создавать базовые и расширенные функции.Базовые функции сильно ограничены встроенными возможностями по сравнению с расширенными функциями. Вы когда-нибудь видели случаи, когда люди использовали параметр Verbose для получения желтого текста или, возможно, –ErrorAction для подавления ошибок, исходящих от функции? Все эти и многие другие входят в стандартную комплектацию при создании расширенной функции.

«Преобразовать» базовую функцию в расширенную очень просто. Просто добавьте ключевое слово CmdletBinding к функции или используйте ключевое слово [Parameter ()] при определении хотя бы одного параметра.Вот пример ниже, где я выделяю два ключевых слова.

 функция Do-Something {
[CmdletBinding ()]
param (
[Parmeter ()]
[строка] $ Param1
)
}

Расширенные функции дают вам много преимуществ по сравнению с базовыми функциями. Если вы сегодня не создаете расширенные функции, я настоятельно рекомендую вам проверить их. Вы можете узнать больше из моего курса Pluralsight под названием «Создание расширенных функций и модулей PowerShell».

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

 function Do-Something {
[CmdletBinding ()]
param ()
## здесь какой-то код
Get-Content –Path C: \ Computers.txt
## здесь какой-то код
}

Теперь это работает, поскольку у вас есть текстовый файл с именем «Компьютеры».txt на жестком диске, но как насчет завтра или послезавтра? Всегда ли там находится файл? Возможно, нет. Если бы вы это сделали и вам нужно было использовать этот файл в своей функции, вам придется каждый раз заходить в свою функцию и изменять ее. Гораздо лучше создать из него параметр, чтобы вы могли передать в функцию любой файл, который хотите, без необходимости изменять саму функцию.

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

 function Do-Something {
[CmdletBinding ()]
param (
[Parameter ()]
[string] $ FilePath
)
## здесь какой-то код
Get-Content –Path $ FilePath
## какой-то код здесь
}

Do-Something –FilePath 'C: \ Computers.txt'

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

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

 функция Do-Something {
[CmdletBinding ()]
param (
[Parameter ()]
[ValidateScript ({Test-Path –Path $ _ -PathType Leaf})]
[строка] $ FilePath
)
## здесь какой-то код
Get-Content –Path $ FilePath
## здесь какой-то код
}

Чтобы добавить этот атрибут параметра, обратите внимание, как я добавил его внутри блока параметров прямо над объявлением параметра FilePath. Атрибут ValidateScript требует блока сценария, в котором вы можете запускать любой код, какой захотите.Просто убедитесь, что он возвращает $ true, чтобы пройти проверку. Выше я запускаю Test-Path для файла, чтобы убедиться, что он существует, заменяя путь к файлу на $ _, чтобы представить текущее используемое значение параметра.

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

[Щелкните изображение, чтобы увеличить.] Рисунок 1.

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


Об авторе

Адам Бертрам - ветеран ИТ с 20-летним стажем. Он инженер по автоматизации, блогер, консультант, писатель-фрилансер, автор курсов Pluralsight и советник по контент-маркетингу в нескольких технологических компаниях.Адам также основал популярную платформу электронного обучения TechSnips. В основном он специализируется на DevOps, технологиях системного управления и автоматизации, а также на различных облачных платформах, в основном в пространстве Microsoft. Он является MVP по Microsoft Cloud and Datacenter Management, он получает знания из области ИТ и объясняет их в простой для понимания форме. Следите за статьями Адама на adamtheautomator.com, подключитесь к LinkedIn или подпишитесь на него в Twitter на @adbertram или в учетной записи TechSnips Twitter @techsnips_io.


Как использовать наборы параметров с примерами в функциях PowerShell - улучшение сценариев

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

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

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

Почему мы хотим создавать наборы параметров PowerShell

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

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

Позвольте мне быстро проиллюстрировать это несколькими примерами.

Я хотел получить информацию, когда группа серверов была в последний раз перезагружена, поэтому я написал свой собственный CmdLet Get-LastBootUpTime с параметром « компьютеров », который принимает список строковых массивов, представляющих имена серверов.

ВАЖНО: Исходный код этого CmdLet находится здесь. Get-LastBootUpTime является частью проекта PowerShell Efficiency Booster, который является библиотекой многих замечательных CmdLet, поэтому, пожалуйста, ознакомьтесь с ним.

Получить время последней загрузки с помощью сценария PowerShell

Get-LastBootUpTime Сценарий CmdLet находится здесь … \ [My] Documents \ WindowsPowerShell \ Modules \ 03common

Get-LastBootUpTime Расположение сценария CmdLet

Вот пример для запуска Get-LastBootUpTime CmdLet с одним именем сервера для компьютеров Параметр :

  Get-LastBootUpTime -computers 'localhost' -client «OK» -решение «FIN» -errorlog | Out-GridView  

Вот набор результатов:

Результат Get-LastBootUpTime CmdLet для одного компьютера

Вот еще один пример запуска CmdLet с двумя именами серверов для параметра « компьютеров »:

  Get-LastBootUpTime - компьютеры 'localhost', 'localhost' -клиент "OK" -решение "FIN" -errorlog | Out-GridView  

Вот результат:

Результат Get-LastBootUpTime CmdLet для двух компьютеров

Я надеюсь, вы уловили картину, поскольку я добавляю все больше и больше имен серверов в параметр « компьютеров », чем вызов Get-LastBootUpTime CmdLet становится все длиннее и длиннее, что, на мой взгляд, не очень аккуратно, и код очень быстро становится загроможденным.

Разве не было бы неплохо иметь другой параметр в том же самом CmdLet, который будет принимать имя текстового файла, и этот текстовый файл будет содержать список серверов?

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

Так я и сделал. Я создал новый параметр « filename », который принимает имя текстового файла, и вот пример вызова с этим параметром:

  Get-LastBootUpTime -filename «OKFINservers.txt "-errorlog -client" OK "-solution" FIN "-Verbose | Out-GridView  

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

Результат Get-LastBootUpTime CmdLet с использованием параметра имени файла

Если вам интересно, каково содержимое файла OKFINservers.txt и где он находится. Вот содержимое текстового файла:

OKFINservers.txt содержимое текстового файла

ПРИМЕЧАНИЕ : Поскольку у меня дома нет сети машин, я просто повторил localhost для запуска того же CmdLet несколько раз, просто чтобы смоделировать, что мы находимся в сети с кучей машин.В реальном примере у нас будет список имен серверов в этом текстовом файле.

И расположение файла, если вы загрузили zip с исходным кодом: \ [My] Documents \ WindowsPowerShell \ Modules \ 01servers

Расположение текстового файла OKFINservers.txt

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

Заключение

Решением для удовлетворения всех требований было наличие двух наборов параметров .

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

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

Другое использование входного параметра filenames - это когда список серверов сегментируется по некоторым критериям, таким как, например, среда (тест, производство, курс, приемка и т. Д.).В этом сценарии мы можем создать несколько текстовых файлов, например

  • OKFINTestServers,
  • OKFINCourseServers,
  • OKFINAllServers,
  • OKFINProductionServers и т. Д.

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

для своего собственного CmdLet :

  1. Используйте ParameterSetName Argument в пределах Parameter Attribute для каждого входного параметра CmdLet, который должен быть в наборе параметров, как в пример ниже:
    [Parameter (ParameterSetName = 'some_name')]
  2. Определите, какой набор параметров используется по умолчанию как DefaultParameterSetName, аргумент из CmdletBinding Attribute .
    [CmdletBinding (DefaultParameterSetName = 'some_name')]
  3. Реализуйте в теле функции код ParameterSetName из Автоматическая переменная $ PsCmdlet (при необходимости), как в приведенном ниже примере:
    if ($ PsCmdletName. eq «FileName») {} else {}
  4. Протестируйте код набора параметров

Давайте посмотрим на несколько примеров, в которых мы реализуем шаги, определенные выше.

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

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

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

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

Получить информацию о процессоре (ЦП) с помощью сценария PowerShell

Get-CpuInfo CmdLet находится в папке … \ [My] Documents \ WindowsPowerShell \ Modules \ 03common папка

Get-CpuInfo Расположение исходного кода CmdLet

Шаг 1. Мы создаем входной параметр « компьютеров », который принадлежит к « ServerNames» Набор параметров .Мы использовали ParameterSetName Argument со значением « ServerNames » в атрибуте Parameter Attribute , когда мы определили входной параметр « computers » функции Get-CPUInfo .

  Функция Get-CPUInfo {
[CmdletBinding ()]
парам (
    [Параметр (ValueFromPipeline = $ true,
                ValueFromPipelineByPropertyName = $ true,
                ParameterSetName = "ServerNames",
                HelpMessage = "Список имен компьютеров, разделенных запятыми.")]
    [Псевдоним ('хосты')]
    [строка []] $ компьютеры = "локальный хост"
    )
}  

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

Как создать параметры в PowerShell, шаг за шагом

Повторите шаг 1. Мы создаем второй входной параметр « имя файла », который принадлежит к « FileName » Parameter Set .Мы использовали ParameterSetName Argument со значением « FileName » в пределах Parameter Attribute , когда мы определили входной параметр имени файла для функции Get-CPUInfo .

  Функция Get-CPUInfo {
[CmdletBinding ()]
парам (
    [Параметр (ValueFromPipeline = $ true,
                ValueFromPipelineByPropertyName = $ true,
                ParameterSetName = "ServerNames",
                HelpMessage = "Список имен компьютеров, разделенных запятыми.")]
    [Псевдоним ('хосты')]
    [строка []] $ computers = 'localhost',
    
    [Параметр (ParameterSetName = "FileName",
                HelpMessage = "Имя txt-файла со списком серверов. Txt-файл должен находиться в папке 01servers.")]
    [строка] $ filename
    )
}  

Повторите шаг 1. Мы создаем третий входной параметр « errorlog », который принадлежит обоим наборам параметров. Поскольку мы не использовали ParameterSetName Argument в объявлении параметра, это означает, что этот параметр принадлежит обоим наборам параметров.

  Функция Get-CPUInfo {
 [CmdletBinding ()]
 Param
     (
     [Параметр (ValueFromPipeline = $ true,
                ValueFromPipelineByPropertyName = $ true,
                ParameterSetName = "ServerNames",
                HelpMessage = "Список имен компьютеров, разделенных запятыми.")]
    [Псевдоним ('хосты')]
    [строка []] $ computers = 'localhost',
    [Параметр (ParameterSetName = "FileName",
                HelpMessage = "Имя txt файла со списком серверов. Файл txt должен находиться в папке 01servers.")]
    [строка] $ filename,
    [Параметр (Обязательный = $ false,
                HelpMessage = "Записывать в файл журнала ошибок или нет.")]
    [переключатель] $ errorlog
     )
 }  

Шаг 2. Мы определили « ServerNames » как Набор параметров по умолчанию , реализовав DefaultParametersetName Argument в атрибуте CmdletBinding .

  Функция Get-CPUInfo {
[CmdletBinding (DefaultParametersetName = "ServerNames")]
 Param
     (
     [Параметр (ValueFromPipeline = $ true,
                ValueFromPipelineByPropertyName = $ true,
                ParameterSetName = "ServerNames",
                HelpMessage = "Список имен компьютеров, разделенных запятыми.")]
    [Псевдоним ('хосты')]
    [строка []] $ computers = 'localhost',
    [Параметр (ParameterSetName = "FileName",
                HelpMessage = "Имя txt-файла со списком серверов. Txt-файл должен находиться в папке 01servers.")]
    [строка] $ filename,
    [Параметр (Обязательный = $ false,
                HelpMessage = "Записывать в файл журнала ошибок или нет.")]
    [переключатель] $ errorlog
     )
 }  

Шаг 3. « FileName» Набор параметров был реализован в блоке BEGIN .В основном код читает текстовый файл со списком серверов, чтобы создать массив строк с именами серверов. Мы использовали значение свойства ParameterSetName автоматической переменной $ PsCmdlet для реализации определения набора параметров.

  Функция Get-CPUInfo {
[CmdletBinding (DefaultParametersetName = "ServerNames")]
 Param
     (
     [Параметр (ValueFromPipeline = $ true,
                ValueFromPipelineByPropertyName = $ true,
                ParameterSetName = "ServerNames",
                HelpMessage = "Список имен компьютеров, разделенных запятыми.")]
    [Псевдоним ('хосты')]
    [строка []] $ computers = 'localhost',
    [Параметр (ParameterSetName = "FileName",
                HelpMessage = "Имя txt-файла со списком серверов. Txt-файл должен находиться в папке 01servers.")]
    [строка] $ filename,
    [Параметр (Обязательный = $ false,
                HelpMessage = "Записывать в файл журнала ошибок или нет.")]
    [переключатель] $ errorlog
     )
 Начинать
 {
     if ($ PsCmdlet.ParameterSetName -eq "FileName") {
        if (Test-Path -Path "$ home \ Documents \ WindowsPowerShell \ Modules \ 01servers \ $ filename" -PathType Leaf) {
            Write-Verbose «Прочитать содержимое из файла: $ filename»
            $ computers = Get-Content ("$ home \ Documents \ WindowsPowerShell \ Modules \ 01servers \ $ filename")
        } еще {
            Предупреждение при записи «Этот путь к файлу НЕ существует: $ home \ Documents \ WindowsPowerShell \ Modules \ 01servers \ $ filename»
            Запись-Предупреждение "Создайте файл $ filename в папке $ home \ Documents \ WindowsPowerShell \ Modules \ 01servers со списком имен серверов."
            перерыв;
                 }
        }
     }
 Процесс
 {
     }
 Конец
 {
     }
 }  

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

Шаг 4. Мы можем протестировать оба набора параметров с разными вызовами Get-CPUInfo CmdLet.

ПРИМЕЧАНИЕ: Загрузите исходный код, чтобы получить результаты, которые я показываю здесь, иначе вам придется написать свой собственный код в CmdLet.

  Get-CPUInfo -компьютеры 'localhost' -клиент "OK" -решение "FIN" -errorlog | Out-GridView  
Результат Get-CPUInfo CmdLet с набором параметров ServerNames
  Get-CPUInfo -filename "OKFINservers.txt" -errorlog -client "OK" -solution "FIN" | Out-GridView  
Результат Get-CPUInfo CmdLet с набором параметров FileName

Как мы узнаем, что функция или CmdLet имеет наборы параметров

Если вы запустите Get-Command CmdLet с синтаксическим параметром , как в следующем примере и как В результате вы получите более одной строки результата, что означает, что CmdLet имеет наборы параметров.

  Get-Command Get-Service -Syntax  

Итак, Get-Service CmdLet имеет три набора параметров , поскольку мы получили три строки в наборе результатов.

Get-Service CmdLet с тремя наборами параметров

Или другой пример с Get-Process CmdLet

  Get-Command Get-Process -Syntax  

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

Get-Process CmdLet с шестью наборами параметров

Как узнать, какой параметр принадлежит какому набору параметров

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

  • Использовать Get- Help PowerShell CmdLet
  • Укажите имя CmdLet, для которого мы хотим найти набор параметров для указанного входного параметра.
  • Используйте параметр Parameter в Get-Help CmdLet со значением входного параметра, для которого мы хотим узнать набор параметров.Мы можем использовать подстановочные знаки, а также «*» для всех параметров вместо определенного входного параметра.
Пример 1 - Параметр набора параметров компьютеров из Get-CPUInfo CmdLet

Вот пример моего собственного CmdLet Get-CPUInfo:

  Get-Help Get-CPUInfo -Parameter компьютеры  
Параметры компьютеров принадлежат ServerNames Набор параметров
Пример 2 - Наборы параметров параметра Id из Get-Process CmdLet

Мы можем использовать Get-Process PowerShell CmdLet в качестве примера.Параметр Id принадлежит к наборам параметров: Id и IdWithUserName

  Get-Help Get-Process -Parameter Id  
Идентификатор параметра принадлежит двум наборам параметров: Id и IdWithUserName
Пример 3 - Исследовать все параметры некоторого PowerShell CmdLet

Если мы хотим исследовать все параметры Get-Process CmdLet, мы должны запустить следующую команду:

  Get-Help Get-Process -Parameter *  

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

ПРИМЕЧАНИЕ: Важно знать, что этот результат зависит от версии PowerShell , на которой вы работаете. Версии ниже 5.1 не дадут нам информацию об имени набора параметров, но версии 6 и 7 подойдут.

Уведомление о значении поля «Имя набора параметров» для каждого параметра

Каковы требования к набору параметров PowerShell

Вот список требований, которые применяются ко всем наборам параметров:

  • Каждый набор параметров должен иметь хотя бы один уникальный параметр.
  • Набор параметров, содержащий несколько позиционных параметров, должен определять уникальные позиции для каждого параметра. Одно и то же положение для двух позиционных параметров не допускается.
  • Только один параметр в наборе может объявить ключевое слово ValueFromPipeline со значением true.
  • Несколько параметров могут определять ключевое слово ValueFromPipelineByPropertyName со значением true.
  • Параметр принадлежит ко всем наборам параметров, если для параметра не указан набор параметров.

Как указать PowerShell, какой набор параметров должен быть набором параметров по умолчанию

Чтобы сделать один из наборов параметров по умолчанию в функции PowerShell, мы будем использовать аргумент DefaultParameterSetName в атрибуте CmdletBinding.

  [CmdletBinding (DefaultParameterSetName = "ServerNames")]  

Подробнее о синтаксисе атрибута CmdletBinding см. В следующем разделе.

Как использовать атрибут CmdletBinding с наборами параметров

Атрибут CmdletBinding - это атрибут функций, которые делают их похожими на CmdLets, поставляемые с Microsoft PowerShell. По сути, позволяет нам использовать общие параметры PowerShell ( Debug (db), ErrorAction (ea), ErrorVariable (ev), Verbose (vb) и т. Д.).

Синтаксис CmdletBinding очень прост:

  [CmdletBinding ()]  

CmdletBinding следует объявить в теле функции прямо над конструкцией Param и после определения функции, как показано ниже. пример:

  Функция Имя_функции
{
    [CmdletBinding ()]
    Параметр ($ ParameterA)
    Начинать{}
    Процесс{}
    Конец{}
}  

CmdletBinding принимает несколько аргументов, определенных внутри (), а в контексте раздела «Наборы параметров» особенно полезным аргументом является DefaultParameterSetName , который может быть реализован следующим образом:

  [CmdletBinding (DefaultParameterSetName = "ServerNames ")]  

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

Другие аргументы из атрибута CmdletBinding :

  • ConfirmImpact = ,
  • HelpURI = ,
  • SupportsPaging = ,
  • SupportsShouldBinding
  • , Position 6

Вот пример реализации аргумента DefaultParametersetName в атрибуте CmdletBinding.

  Функция Get-CPUInfo {
[CmdletBinding (DefaultParametersetName = "ServerNames")]
 Param
     (
     [Параметр (ValueFromPipeline = $ true,
                ValueFromPipelineByPropertyName = $ true,
                ParameterSetName = "ServerNames",
                HelpMessage = "Список имен компьютеров, разделенных запятыми.")]
    [Псевдоним ('хосты')]
    [строка []] $ computers = 'localhost',
    [Параметр (ParameterSetName = "FileName",
                HelpMessage = "Имя txt-файла со списком серверов. Txt-файл должен находиться в папке 01servers.")]
    [строка] $ filename,
    [Параметр (Обязательный = $ false,
                HelpMessage = "Записывать в файл журнала ошибок или нет.")]
    [переключатель] $ errorlog
     )
 Начинать
 {
     if ($ PsCmdlet.ParameterSetName -eq "FileName") {
        if (Test-Path -Path "$ home \ Documents \ WindowsPowerShell \ Modules \ 01servers \ $ filename" -PathType Leaf) {
            Write-Verbose «Прочитать содержимое из файла: $ filename»
            $ computers = Get-Content ("$ home \ Documents \ WindowsPowerShell \ Modules \ 01servers \ $ filename")
        } еще {
            Предупреждение при записи «Этот путь к файлу НЕ существует: $ home \ Documents \ WindowsPowerShell \ Modules \ 01servers \ $ filename»
            Запись-Предупреждение "Создайте файл $ filename в папке $ home \ Documents \ WindowsPowerShell \ Modules \ 01servers со списком имен серверов."
            перерыв;
                 }
        }
     }
 Процесс
 {
     }
 Конец
 {
     }
 }  

Как реализовать наборы параметров в вашем собственном коде

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

  если ($ PsCmdlet.ParameterSetName -eq "FileName") {
        if (Test-Path -Path "$ home \ Documents \ WindowsPowerShell \ Modules \ 01servers \ $ filename" -PathType Leaf) {
            Write-Verbose «Прочитать содержимое из файла: $ filename»
            $ computers = Get-Content ("$ home \ Documents \ WindowsPowerShell \ Modules \ 01servers \ $ filename")
        } еще {
            Предупреждение при записи «Этот путь к файлу НЕ существует: $ home \ Documents \ WindowsPowerShell \ Modules \ 01servers \ $ filename»
            Запись-Предупреждение "Создайте файл $ filename в папке $ home \ Documents \ WindowsPowerShell \ Modules \ 01servers со списком имен серверов."
            перерыв;
                 }
 }  

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

Полезные команды PowerShell

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

  Get-Command Get-Service -Syntax  
  Get-Help Get-Process -Id параметра  
  Get-Help Get-Process -Parameter *  
  Get-Help Get-Service  

Полезные статьи о наборе параметров PowerShell

Вот несколько полезных статей и ресурсов:

Подробнее

О Деян Младенович

Всем привет! Я надеюсь, что эта статья, которую вы читаете сегодня, перенесла вас из места разочарования в место радости кодирования! Пожалуйста, дайте мне знать обо всем, что вам нужно для Windows PowerShell, в комментариях ниже, которые могут помочь вам в достижении ваших целей!
У меня более 18 лет опыта в сфере ИТ, и вы можете проверить мои учетные данные Microsoft.

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *