Использование PowerShell для создания диалоговых окон при развертывании ОС с помощью System Center Configuration Manager

Я думаю, что каждый администратор ConfigMgr, работавший с функционалом Operating System Deployment, использовал свои скрипты для придания гибкости процессу. Если нужно показать пользователю какой-то интерфейс, то чаще всего задействуют HTML Application (HTA). В этой статье я хочу показать, как решить аналогичную задачу с помощью PowerShell. Да, используя PowerShell, можно нарисовать пользовательский интерфейс. Лично мне легче читать код на PowerShell, нежели html-теги. Сегодня мы нарисуем диалог для OSD с двумя вкладками:

1 2

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

Из каких элементов состоит пользовательский интерфейс? Из объектов, которые еще называют Windows Controls. Они бывают разными – всевозможные списки, кнопки, вкладки, меню, поля для ввода текста, надписи и так далее. Основным элементом каждого интерфейса является форма. Собственно, это и есть окно в привычном для нас понимании. Оно может иметь заголовок и кнопки свертывания, маскимизации/минимизации, закрытия в правом верхнем углу. На форме мы располагаем остальные элементы интерфейса. Вот что мы будем использовать в нашем примере:

  • Form – это форма, основа для других элементов интерфейса
  • TabControl – для пользователя этот элемент выглядит как вкладки. Мы создадим в нашем диалоге 2 вкладки, чтобы эффективней расположить остальные элементы
  • Label – в основном этот тип объектов используется для показа всевозможных надписей. Но мы его используем еще и с целью группировки RadioButton
  • RadioButton – переключатель состоящий из нескольких элементов, мы будем использовать его для того чтобы пользователь выбрал одну опцию из нескольких предложенных
  • TextBox – поле для ввода текста
  • ComboBox – выпадающий список, в котором обычно пользователь может выбрать какой-либо элемент
  • CheckBox – не могу подобрать заумное описание. Это просто квадратик, в котором можно поставить галочку :)
  • Button - кнопка

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

Мы можем отслеживать и обрабатывать различные события, генерируемые при взаимодействии с элементами интерфейса. В данном случае, мы хотим, чтобы при нажатии кнопки Apply считались все выбранные пользователем опции и записались в переменные Task Sequence. Для этого мы воспользуемся событием Click. А точнее, мы впишем свой код в процедуру, вызываемую при возникновении события Click у кнопки Apply. Событий также создано немало и с ними можно делать много интересного: например, отслеживать изменение текста в текстовом поле, отслеживать изменение размера объекта, отслеживать момент, когда пользователь помещает указатель мыши на объект и пр. Хотите знать больше – вам опять прямая дорога в один из разделов msdn.

Логику скрипта не сложно понять, я дам только общее описание. Сначала прячем окно интерфейса Task Sequence:

$objTSProgressUI = New-Object -COMObject Microsoft.SMS.TSProgressUI

$objTSProgressUI.CloseProgressDialog()

Далее создаем объект для доступа к переменным Task Sequence

$objTSEnv = New-Object -COMObject Microsoft.SMS.TSEnvironment

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

$OUList = Get-Content "OUList.txt"

#delete empty lines

$OUList = $OUList | ? {$_.trim() -ne "" }

Вот пример текстового файла со списком OU:

3

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

Get-ADOrganizationalUnit -Filter * -Properties DistinguishedName | Select-Object -ExpandProperty DistinguishedName | Out-File "C:\Windows\Temp\OUlist.txt"

Вернемся к скрипту, который рисует форму с опциями. Создадим форму и определим некоторые ее свойства:

Add-Type -AssemblyName System.Windows.Forms

$objForm = New-Object System.Windows.Forms.Form

$objForm.Text = "Don't hesitate to use deployment options"

$objForm.Size = New-Object System.Drawing.Size(670,430)

$objForm.StartPosition = "CenterScreen"

$objForm.Topmost = $True

$objForm.MaximizeBox = $false

$objForm.MinimizeBox = $false

Потом создадим элементы управления, например, TabControl:

$objTab = New-Object System.Windows.Forms.TabControl

$objTab.Size = New-Object System.Drawing.Size(653,333)

Но просто создать элемент недостаточно, нужно добавить его на форму:

$objForm.Controls.Add($objTab)

 Затем создадим страницы для TabControl и разместим их на форме:

$objTab = New-Object System.Windows.Forms.TabControl

$objTab.Size = New-Object System.Drawing.Size(653,333)

$objForm.Controls.Add($objTab)

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

Далее код, который обрабатывает нажатие кнопки Apply, в нем мы считываем значения с элементов формы и сохраняем их в переменные Task Sequence

$ApplyButton.Add_Click({

$objTSEnv.Value("OSDComputerName")=$objTextBox_PCName.Text

If($objComboBox_PCOU.SelectedIndex -ne 0) { $objTSEnv.Value("OSDDomainOUName")="LDAP://" + $objComboBox_PCOU.SelectedItem }

If($objCheckBox_SW1.Checked -eq $True) { $objTSEnv.Value("InstallApp01")=$True }

If($objCheckBox_SW2.Checked -eq $True) { $objTSEnv.Value("InstallApp02")=$True }

If($objCheckBox_SW3.Checked -eq $True) { $objTSEnv.Value("InstallApp03")=$True }

If($objCheckBox_SW4.Checked -eq $True) { $objTSEnv.Value("InstallApp04")=$True }

If($objCheckBox_SW5.Checked -eq $True) { $objTSEnv.Value("InstallApp05")=$True }

If($objCheckBox_SW6.Checked -eq $True) { $objTSEnv.Value("InstallApp06")=$True }

if($objRadioButtonYes_DisableAdmin.Checked -eq $True) { $objTSEnv.Value("OSDRandomAdminPassword")=$True}

if($objRadioButtonNo_DisableAdmin.Checked -eq $True) { $objTSEnv.Value("OSDRandomAdminPassword")=$False}

if($objRadioButtonYes_Updates.Checked -eq $True) { $objTSEnv.Value("InstallUpdates")=$True}

$objForm.Close()

})

 Ну и последним штрихом вызываем нашу форму на экран:

$objForm.Add_Shown({$objForm.Activate()})

[void] $objForm.ShowDialog()

Теперь нужно написать пару слов о том, как запустить этот скрипт в Task Sequence. Во-первых, нужно добавить опциональные компоненты в используемый загрузочный образ:

4

Во-вторых, если просто использовать шаг Run PowerShell Script, то скрипт запустится, но пользователь не увидит ничего на экране. Чтобы сделать окно видимым, я использую шаг Run Command Line

5

ServiceUI.exe -process:TSProgressUI.exe %SYSTEMROOT%\System32\WindowsPowerShell\v1.0\powershell.exe -NoProfile -WindowStyle Hidden -ExecutionPolicy Bypass -File OSD_options.ps1

ServiceUI.exe входит в состав Microsoft Deployment Tools (MDT). В зависимости от архитектуры загрузочного образа используем x86 или x64 версию ServiceUI.exe. Ну и не забываем, что этот файл нужно положить в тот же пакет, рядом с нашим PowerShell-скриптом. Ссылку на полную версию скрипта можно найти в самом конце статьи.

Также, нельзя умолчать о том, что существует более продвинутый способ рисования пользовательского интерфейса для скриптов на PowerShell. Он не требует расчета координат элементов. Особенно это удобно, когда элементов много. Можно буквально взять и перевернуть кнопку вверх ногами. Если коротко, то все сводится к тому чтобы в Visual Studio (можно использовать Visual Studio Express) с помощью мыши создать форму с необходимыми элементами. В итоге получаем XML-код (XAML), который мы копируем и вставляем в наш PowerShell-скрипт. Подробное описание процесса есть в статье Integrating XAML into PowerShell Концепция сильно напоминает HTML-приложение – можно сказать виток эволюции завершился, и мы вернулись к тому, с чего начали. Удачного скриптинга!

OSD_options.ps1