Поделиться через


Windows PowerShell: Создание командлетов в сценарии

Дон Джонс

Одна из классных новинок Windows PowerShell версии 2 — возможность создавать расширенные функции. Такие функции полностью создаются на языке сценариев, но обладают такими же возможностями, что и «настоящий» командлет, написанный на C# или Visual Basic и скомпилированный в Visual Studio. Поддержка этих расширенных функций (на ранних этапах разработки версии 2 их называли «сценарными командлетами») позволяет создавать более гибкие функции, которые в дальнейшем можно легко использовать вместе с настоящими командлетами.

Все дело в привязке

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

Работайте со своими модулями

Так как это поможет вам в более простом распространении своих сценариев? Ответ кроется во втором типе модуля, модуле сценария. Это обычный сценарий Windows PowerShell с расширением .psm1, а не .ps1. Если поместить mymodule.psm1 в папку \modules, можно запустить Import-Module MyModule, и сценарий будет выполняться.

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

function Get-Inventory {
    [CmdletBinding()]
    param (
        [parameter(Mandatory=$true,ValueFromPipeline=$true)]
        [string[]]$computername,
        
        [parameter(Mandatory=$false)]
        [alias("PF")]
        [switch]$pingfirst,
        
        [parameter(Mandatory=$true,Position=0)]
        [AllowEmptyString()]
        [string]$class
        
    )
    PROCESS {
    }
}

Здесь я объявил три параметра:

  • computername представляет собой одну строку или массив строк. Этот обязательный параметр принимает строки по конвейеру, то есть переданные строки автоматически попадут в переменную $computername;
  • pingfirst не обязательный параметр, но при его применении надо использовать псевдоним -PF. Это избавит от лишних нажатий клавиш. Это переключатель, то есть он принимает значение on или off;
  • class также обязательный параметр, но вводить его имя совершенно не нужно — при вызове функции достаточно просто указать его значение на первом месте. Обязательность этого параметра не запрещает ему принимать в качестве значения пустую строку.

Есть еще больше атрибутов и посвященных им примеров — их описание вы найдете в справке, для чего надо выполнить команду help about_Functions_Advanced_Parameters.

Доступ к общим параметрам

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

function Test-Something {
    [CmdletBinding()]
    param (
        [switch]$verbose
    )
    PROCESS {
    }
}

Дело в том, что нельзя переопределить такой общий параметр, как -verbose. Но как же тогда узнать, когда функцию запустили с параметром -verbose? А это просто не нужно — эту работу делает сама Windows PowerShell. Ваше дело вызвать Write-Verbose, а Windows PowerShell проигнорирует вызов, если функция вызвана без -verbose:

function Test-Something {
    PROCESS {
        Write-Verbose "Starting cmdlet"
    }
}

test-something –verbose

Подтверждение действий

Вот еще пара общих параметров:-whatif и -confirm. Любой командлет, вносящий изменения в систему компьютера, должен поддерживать эти параметры. Они позволяют пользователю увидеть, что происходит, если запустить команду (-whatif), или подтверждать каждое предпринимаемое командлетом действие (-confirm). В совокупности эти параметры называются ShouldProcess, а вот пример объявления функции, которая их поддерживает:

function Delete-Things {
    [CmdletBinding(
        SupportsShouldProcess=$true,
        ConfirmImpact="Medium"
    )]
    PROCESS {
    }
}

Эта функция поддерживает и -whatif, и -confirm. В объявлении также определено, что функция оказывает среднего уровня влияние на ОС. Нет никаких строгих инструкций относительно того, что означает «средний уровень влияния» — я бы сказал, что это чуть лучше, чем риск полного разрушения системы. А основной фокус в том, что по умолчанию оболочка присваивает переменной $ConfirmPreference значение High (высокий). Когда влияние командлета ниже, чем значение $ConfirmPreference, командлет работает без подтверждения, если только не задан параметр -whatif или -confirm.

Если влияние командлета равно или выше, чем значение $ConfirmPreference, то при каждом выполнении командлета он будет вести себя как если бы был задан параметр –confirm, — даже если тот не был задан. Поэтому если ваша функция может делать что-то действительно опасное, задайте ConfirmImpact="High", чтобы командлет всегда запрашивал подтверждение. Другие возможные значения этого параметра — None и Low.

Ни в одном из разделов справки оболочки вы найдете информации о том, как запрашивать подтверждение, ведь это не выполняется автоматически. Справка отсылает к библиотеке MSDN, предназначенной для разработчиков в среде Microsoft .NET Framework, и ничего не говорит о языках сценариев. Поэтому я покажу, как это делается, здесь:

function Delete-Things {
    [CmdletBinding(
        SupportsShouldProcess=$true,
        ConfirmImpact="High"
    )]
    Param ($param1)
    PROCESS {
        if ($pscmdlet.ShouldProcess($param1)) {
            Write "Deleting..."
        }
    }
}

Delete-Things "organizationalunit"

$pscmdlet — встроенная переменная, которую можно использовать в блоке PROCESS сценария для доступа к функциональности командлета, в том числе к методу ShouldProcess. Надо передать описание того, что вы собираетесь изменить, а оболочка сама позаботится об отображении подтверждения или сообщении «что, если».

Если ShouldProcess возвратит $True, можно продолжить операцию. Значение $False запрещает функции делать то, что она собиралась.Знание переменной $pscmdlet значительно облегчает понимание всех упомянутых документов в библиотеке MSDN. Они действительно точно описывают разные способы использования ShouldProcess и его аналога — ShouldContinue.

Помогите! Помогите! Помогите!

Как вы помните, функции, даже самые сложные, могут содержать собственную встроенную справочную информацию в особым образом отформатированных комментариях, о чем я рассказывал в выпуске рубрики за март 2010 г.. Как правило, сначала я размещаю основанную на комментариях справку, затем идет инструкция CmdletBinding, потом — параметры, и лишь затем блоки сценария: BEGIN{}, PROCESS{} и END{}. Всегда полезно включать справку в код функций — никогда, ведь, не знаешь, кому она может оказаться полезной.

Если вы уже создавали функции для конвейера (их еще называют «функции с фильтрами»), то уже знаете все необходимое для создания «сценарных командлетов». В блоке PROCESS{} сценария размещается код, и он будет выполнен по разу для каждого объекта, поступившего по конвейеру в командлет. Все остальное в этих расширенных функциях похоже на содержимое более простых функций.

Оболочка Windows PowerShell версии 2 стала общедоступной

Ранее Windows PowerShell v2 поставлялся только в составе Windows Server 2008 R2 и Windows 7, теперь эта оболочка и сопутствующие компоненты инфраструктуры управления доступны для Windows XP, Windows Server 2003, Windows Vista и Windows Server 2008. На странице support.microsoft.com/kb/968929 вы найдете ссылки для загрузки Windows PowerShell v2 для нужной вам ОС. В большинстве случаев новая оболочка будет поддерживать сценарии, созданные в версии 1; в своих последующих выпусках своей колонки, я буду предполагать, что вы используете 2.0.

Разнообразие целевой аудитории

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

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

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

Дон Джонс *(Don Jones) — основатель компании Concentrated Technology. Он отвечает на вопросы о Windows PowerShell и других технологиях по адресу ConcentratedTech.com. Он также пишет для  *Nexus.Realtimepublishers.com, поэтому многие из книг Дона доступны в бесплатной электронной форме.

Материалы по теме

·      Windows PowerShell: PowerShell и Active Directory

·      Windows PowerShell: фильтр налево, формат направо

·      Windows PowerShell: оставайтесь на местах