sergey vasin

The IT blog

PowerShell Workflows: Основы – Hey, Scripting Guy! Blog

leave a comment »

Резюме: Windows PowerShell MVP Richard Siddaway рассказывает об основах рабочих процессов (workflows) в Windows PowerShell 3.0.

Microsoft Scripting Guy, Ed Wilson на связи. Сегодня у нас приглашенный блогер Windows PowerShell MVP Richard Siddaway. Он написал несколько гостевых постов, кроме этого он является автором двух книг по Windows PowerShell. Последняя его книга, PowerShell in Depth написана в соавторстве двумя другими MVP – Don Jones и Jeffrey Hicks. Итак, Ричард.

PowerShell Workflows: Основы

Если вы читали что-нибудь из того, что я написал за последние 6 лет, то вы знаете, что я считаю, что Windows PowerShell это лучшее из всего, что когда-либо появлялось в экосистеме Windows. С появлением 3 версии все стало еще лучше. Одной из основных сфер моих интересов в последние несколько лет был WMI, но одна вещь в Windows PowerShell 3.0 меня действительно восхищает – это рабочие процессы.

Когда я начинаю разбираться с новой технологией, я хочу знать три вещи:

1. Что это и как оно работает?

2. Почему это важно?

3. Что мне это даст?

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

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

Это определение вполне может подойти к функции или скрипту Windows PowerShell, и нельзя сказать, что вы будете полностью неправы, если так решите, но – и это весьма значительное «но» — рабочие процессы Windows PowerShell созданы для использования в сценариях, где требуются следующие атрибуты:

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

Хорошо, я уже вроде объяснил вам, что рабочие процессы – это хорошая вещь – но как же они выглядят? Существует традиция, что знакомство с новым языком программирования начинается с программы «hello world». Итак, самый простой рабочий процесс будет выглядеть так.

workflow helloworld {

«Hello World»

}

Запуск этого кода создает рабочий процесс, но не выполняет его – в точности как и функция Windows PowerShell. Для эго выполнения просто наберите его имя в командной строке и нажмите «Enter». При первом запуске рабочего процесса будьте готовы к небольшой задержке перед тем как он выполнится.

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

Вы заметили, что Windows PowerShell 3.0 привнес новое ключевое слово – workflow. Существует еще несколько ключевых слов, имеющих отношение к рабочим процессам, о которых вам следует знать:

  • Workflow
  • Parallel
  • Foreach –parallel
  • Sequence
  • InlineScript
  • Checkpoint-workflow
  • Suspend-workflow

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

Get-CimInstance –ClassName Win32_OperatingSystem

Get-Process –Name PowerShell*

Get-CimInstance –ClassName Win32_ComputerSystem

Get-Service –Name s*

В каком порядке будут возвращены результаты, если вы запустите эти команды в скрипте или функции Windows PowerShell?

Если не возникнет никаких проблем, я полагаю что я увижу:

1. Данные, возвращенные классом Win32_OperatingSystem

2. Информацию о процессе Windows PowerShell

3. Данные, возвращенные классом Win32_ComputerSystem

4. Информацию о службах, начинающихся с буквы «s»

Теперь давайте превратим это в рабочий процесс с параллельным выполнением.

workflow paralleltest {

   parallel {

      Get-CimInstance –ClassName Win32_OperatingSystem

      Get-Process –Name PowerShell*

      Get-CimInstance –ClassName Win32_ComputerSystem

      Get-Service –Name s*

   }

}

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

Как вы думаете, в каком порядке будут возвращаться данные?

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

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

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

Функциональность рабочих процессов Windows PowerShell строится на .NET Framework Windows Workflow Foundation (WWF). Большинство (однако, не все) командлетов сопоставлено активностям рабочих процессов (я коснусь несопоставленных командлетов позже). И это именно то, что вы запускали – активности рабочих процессов. Для запуска активностей, код Windows PowerShell транслируется в XAML. Если потребуется, вы даже можете импортировать XAML в Visual Studio.

Для просмотра XAML-кода наберите следующую команду:

Get-command paralletest | format-list *

Синтаксис активностей рабочих процессов большей частью похож на тот, что мы используем при работе с командлетами, но есть и отличия — наиболее заметное из них – это параметр ‑ComputerName. В активностях рабочих процессов он заменен на ‑PSComputerName. Я проиллюстрирую это в следующем рабочем процессе.

workflow foreachptest {

   param([string[]]$computers)

   foreach –parallel ($computer in $computers){

      Get-WmiObject –Class Win32_OperatingSystem –PSComputerName $computer

   }

}

Вы можете запустить этот рабочий процесс следующим образом:

foreachptest -Computers «server01», «server02», «server03»

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

А что же насчет ситуаций, когда команды должны быть выполнены в определенном порядке? Этот функционал предоставляется посредством ключевого слова «sequence». Все, что входит в блок sequence{} выполняется в том порядке, в каком вы это указали. Вы можете видоизменить последний рабочий процесс следующим образом:

workflow foreachpstest {

   param([string[]]$computers)

   foreach –parallel ($computer in $computers){

      sequence {

         Get-WmiObject -Class Win32_ComputerSystem -PSComputerName $computer

         Get-WmiObject –Class Win32_OperatingSystem –PSComputerName $computer

      }

   }

}

foreachpstest -Computers «server01», «server02», «server03»

В этом рабочем процессе вы параллельно обращаетесь к трем компьютерам, но команды

Get-WmiObject -Class Win32_ComputerSystem -PSComputerName $computer

Get-WmiObject –Class Win32_OperatingSystem –PSComputerName $computer

выполняются на каждом компьютере именно в этом порядке.

Еще не запутались? Отлично! Теперь давайте попробуем вот так.

workflow foreachpsptest {

   param([string[]]$computers)

   foreach –parallel ($computer in $computers){

      sequence {

         Get-WmiObject -Class Win32_ComputerSystem -PSComputerName $computer

         Get-WmiObject –Class Win32_OperatingSystem –PSComputerName $computer

         $disks = Get-WmiObject -Class Win32_LogicalDisk `

         -Filter «DriveType = 3» –PSComputerName $computer

         foreach -parallel ($disk in $disks){

            sequence {

               $vol = Get-WmiObject -Class Win32_Volume `

              -Filter «DriveLetter = ‘$($disk.DeviceID)'» `

              –PSComputerName $computer

              Invoke-WmiMethod -Path $($vol.__PATH) -Name DefragAnalysis

           }

         }

      }

   }

}

foreachpstest -Computers «server01», «server02», «server03»

Рабочий процесс принимает список имен компьютеров и параллельно выполняет набор действий. Эти действия выполняются в указанном порядке, поскольку мы использовали ключевое слово sequence. С получением экземпляров Win32_ComputerSystem и Win32_OperatingSystem все понятно, поскольку вы получаете по одному экземпляру каждого класса. Затем рабочий процесс получает список логических дисков, но поскольку их несколько, мы хотим, чтобы они обрабатывались параллельно. Поэтому мы используем:

foreach -parallel ($disk in $disks)

Для каждого диска существует экземпляр класса Win32_Volume. Мы используем свойство __PATH этих экземпляров для вызова метода DefragAnalysis.

Обычно, вы могли бы сделать следующее:

Get-WmiObject -Class Win32_Volume -Filter «DriveLetter = ‘C:'» |

Invoke-WmiMethod -Name DefragAnalysis

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

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

Одна из проблем, с которой сталкиваются люди при использовании WMI, это то, что форматирование по умолчанию выводит не все данные. Один из подходов к этой проблеме – это использование командлета Format-List *. Так что вы, возможно, захотите сделать следующее:

workflow foreachptest {

   param([string[]]$computers)

   foreach –parallel ($computer in $computers){

      Get-WmiObject –Class Win32_OperatingSystem –PSComputerName $computer | Format-List

   }

}

К сожалению, это не сработает и вы увидите сообщение об ошибке, подобное следующему:

At line:5 char:5

+ Format-List

+ ~~~~~~~~~~~

Cannot call the ‘Format-List’ command. Other commands from this module have been packaged as workflow activities, but this command was specifically excluded. This is likely because the command requires an interactive Windows PowerShell session, or has behavior not suited for workflows. To run this command anyway, place it within an inline-script (InlineScript {Format-List }) where it will be invoked in isolation.

   + CategoryInfo : ParserError: (:) [], ParseException

   + FullyQualifiedErrorId : CommandActivityExcluded

Как нам объясняет сообщение об ошибке — Format-List – это один из командлетов, который не был реализован в качестве активности рабочих процессов. Также это сообщение рекомендует нам использовать InlineScript, что по сути является скриптблоком Windows PowerShell внутри рабочего процесса. Вы можете использовать его следующим образом:

workflow foreachpitest {

   param([string[]]$computers)

   foreach –parallel ($computer in $computers){

      InlineScript {

         Get-WmiObject –Class Win32_OperatingSystem –ComputerName $using:computer | Format-List

      }

   }

}

В этом рабочем процессе следует отметить две вещи. Первое, он снова использует параметр –ComputerName. Это потому, что внутри InlineScript находится командлет, а не активность рабочего процесса. Второе – это то, каким образом передается переменная $computer$using:computer. Это вследствие того, как организованы области (scopes) рабочих процессов. Более полно я объясню это позже, но сейчас запомните – если вы собираетесь использовать в блоке InlineScript переменную, определенную выше в структуре рабочего процесса, вам нужно использовать модификатор $using.

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

  • Parallel
  • Foreach –parallel
  • Sequence
  • InlineScript

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

~Richard.

Автор:

Ed Wilson, Microsoft Scripting Guy

Оригинал:

http://blogs.technet.com/b/heyscriptingguy/archive/2012/12/26/powershell-workflows-the-basics.aspx


Страницы в социальных сетях:

Twitter: https://twitter.com/vsseth
Facebook: https://fb.com/inpowershell
VKontakte: https://vk.com/inpowershell


Реклама

Written by Сергей Васин

Январь 3, 2013 в 12:49

Опубликовано в HeyScriptingGuyBlog, PowerShell

Tagged with ,

Добавить комментарий

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

Логотип WordPress.com

Для комментария используется ваша учётная запись WordPress.com. Выход / Изменить )

Фотография Twitter

Для комментария используется ваша учётная запись Twitter. Выход / Изменить )

Фотография Facebook

Для комментария используется ваша учётная запись Facebook. Выход / Изменить )

Google+ photo

Для комментария используется ваша учётная запись Google+. Выход / Изменить )

Connecting to %s