При написании рабочего процесса в Windows PowerShell необходимо помнить о том, что каждая команда должна преобразовываться в операцию Windows Workflow Foundation (WF) или операцию InlineScript.
Прежде всего, что такое операция? Рабочие процессы Windows PowerShell, в конечном счете, транслируются в нечто, понятное WF. А WF работает с операциями. Операция в WF — это одно действие, выполняемое в рамках рабочего процесса.
Для многих базовых команд Windows PowerShell имеются эквивалентные операции. Эти операции полностью отделены от команд. Другими словами, сотрудникам группы Microsoft пришлось сесть за компьютеры и написать и команды Windows PowerShell, например, Where-Object, и соответствующие им операции WF, делающие то же самое.
Так что, на самом деле, у нас две параллельные структуры. Когда мы выполняем команду рабочего процесса, Windows PowerShell смотрит, имеется ли эквивалентная операция, кем-то написанная и установленная на компьютер. Если имеется, то рабочий процесс ей воспользуется.
Это важный момент. Вполне возможно, что в будущем разработкой операций займутся другие группы Microsoft и даже сторонние компании. Однако перед тем, как использовать операции, вы будете должны установить и зарегистрировать их на каждом компьютере, на котором будут выполняться написанные вами рабочие процессы. И то, как вы это сделаете, будет зависеть от продукта.
Если операции нет
Если вы выполните команду, для которой нет эквивалентной операции WF, то Windows PowerShell обернет эту команду неявным блоком InlineScript. InlineScript — операция, встроенная в WF. По сути, она указывает WF, что надо запустить копию Windows PowerShell, выполнить команду, а затем закрыть эту копию Windows PowerShell.
Поскольку обертывание блоком InlineScript может происходить неявно, вы можете не узнать, что оно произошло, и оно может оказаться совершенно неожиданным для вас. В сущности, в Windows PowerShell 3.0, непросто узнать, какие команды имеют WF-эквиваленты, а какие — нет. Вы не всегда сможете сказать, когда команда выполняется как встроенная операция, а когда она обернута InlineScript. В большинстве случаев это и не нужно знать. Однако это может кое на что влиять.
Например, если вы попробуете выполнить следующий код, то он потерпите неудачу:
Workflow My-Workflow {
Import-Module DHCPServer
Get-DHCPServerv4Scope
}
Рабочий процесс терпит неудачу, поскольку для Import-Module нет WF-операции. Каждая операция должна выполняться в своем собственном процессе (почти всегда). Вспомните, что вы можете прервать, а затем возобновить рабочий процесс, значит, каждая команда должна самостоятельно создавать и завершать сеанс. Ни одна команда не может рассчитывать на код, выполняющийся в той же области памяти или том же процессе. Windows PowerShell не будет обертывать Import-Module in блоком InlineScript, поскольку при этом открылась бы Windows PowerShell, выполнилась бы операция Import-Module, а затем Windows PowerShell закрылась бы. В результате произошла бы выгрузка модуля, так что весь этот все эти действия не имели бы смысла.
Однако следующий код будет работать:
Workflow My-Workflow {
InlineScript {
Import-Module DHCPServer
Get-DHCPServerv4Scope
}
}
В нем добавлен явный блок InlineScript. Значит, две команды будут выполняться в одном сеансе Windows PowerShell.
Блоки InlineScript
Наверно, вы можете себе представить, сколько рабочих процессов можно было бы разбить на один или несколько блоков InlineScript. Ведь если в процессе нужно выполнить более одной команды, причем эти команды должны обмениваться результатами и выходными данными, то InlineScript — один из возможных вариантов.
Имейте в виду, что каждый блок InlineScript представляет собой самостоятельный процесс Windows PowerShell. Например, следующий код не будет работать:
Workflow My-Workflow {
InlineScript {
Import-Module DHCPServer
$scopes = Get-DHCPServerv4Scope
}
InlineScript {
ForEach ($scope in $scopes) {
Write $scope.IPAddress
}
}
}
Переменная $scopes, созданная в первом InlineScript, не будет существовать во втором. Код завершится с ошибкой, или просто ничего не сделает. Возможно, вы сейчас подумали: «Почему бы просто не поместить все в один блок InlineScript?». Так можно поступить:
Workflow My-Workflow {
InlineScript {
Import-Module DHCPServer
$scopes = Get-DHCPServerv4Scope
ForEach ($scope in $scopes) {
Write $scope.IPAddress
}
}
}
Но проблема в том, что теперь ваш рабочий процесс состоит из единственной операции. WF поддерживает только контрольные точки, располагающиеся между операциями, и возобновление работы на уровне операций. Ваш рабочий процесс, состоящий из одной операции, невозможно приостановить, возобновить или прервать.
Раз уж на то пошло, вы теряете многие преимущества, предоставляемые рабочими процессами. Вам по-прежнему доступно удаленное выполнение. Однако если бы это был длительный многоэтапный процесс, то вы не смогли бы «пережить» его сбой (например, отказ сети или отключение питания) и возобновить работу с места, где произошел сбой.
Таким образом, рабочий процесс становится интересной архитектурной головоломкой. Нужно стремиться к тому, чтобы каждая операции была, по возможности, обособленной и самостоятельной. Тогда вы обеспечите максимальную поддержку прерывания и возобновления. Однако возникает ограничение: команды могут совместно использовать информацию только в рамках процесса.
В самом деле, от Windows PowerShell Workflow было бы гораздо больше пользы, если операции могли бы сохранять информацию во внешнем хранилище (таком как SQL Server). Тогда другие операции могли бы извлекать и использовать эту информацию. Такое хранилище стало бы постоянным внешним хранилищем переменных.
К сожалению, в Windows PowerShell нет встроенной поддержки таких хранилищ. Однако ничто не мешает вам реализовать их своими силами.