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

Для работы MDT необходимо:

  • WDS
  • Windows ADK
  • PowerShell
  • .net Framework
  • DHCP

План



Добавление роли Windows Deployment Services (WDS) на сервер


На сервере включаем роль WDS.







Загрузка и установка на сервер необходимых компонентов


С официального сайта скачиваем и устанавливаем Windows Assessment and Deployment Kit (ADK):
1) Download the Windows ADK for Windows 10, version 1809 (возможно, новее)
2) Download the Windows PE add-on for the ADK

Отмечаем для установки:

  • Deployment Tools
  • Imaging And Configuration Designer
  • Configuration Designer
  • User State Migration Tools



Также скачиваем и устанавливаем Microsoft Deployment Toolkit (MDT)

Запуск и настройка WDS


Открываем консоль WDS



Запускаем конфигурирование.



В мастере настройки выбираем интеграцию с доменом.



Задаем служебную папку WDS.



На следующем шаге можно выбрать каким компьютерам будет отвечать сервер WDS:

  • Никому не отвечать — можно отключить работу сервера на время настройки или тестирования, например, чтобы пользователи не получали возможные конфликты при установке.
  • Отвечать только известным компьютерам — список составляется в консоли и если записи адреса компьютера нет, то он не получит возможность работать с сервером.
  • Отвечать всем клиентам — ответ получат все компьютеры. Если установить галку ниже, то при обращении неизвестных устройств (не записанных ранее) в консоли появится запись, что некий компьютер с определенным адресом запрашивает подключение. Можно отклонить или принять и процесс продолжится. Позже эти настройки можно изменить в консоли WDS.



Завершаем процесс первоначальной настройки. Имеем следующую структуру папок:



WDS нам понадобится только для подключения и передачи образов, поэтому без подробного объяснения:

Install Images — установочные образы (не используем);
Boot Images — загрузочные образы (добавим созданные в MDT);
Pending Devices — появляются устройства запрашивающие соединение если включена опция «требуется подтверждение администратора».

Запуск и настройка MDT


Для настройки MDT запускаем его консоль. Microsoft Deployment Toolkit -> Deployment Workbench.



Добавляем новую DeploymentShare. В ней будут храниться все файлы для установки.





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



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



Общая папка E:\DeploymentShare$ может переноситься на другие сервера простым копированием. Отключение и подключение осуществляется в консоли MDT.

Applications — приложения которые устанавливаются на операционную систему;
Operating Systems — операционные системы доступные для загрузочного образа;
Out-of-Box Drivers — драйвера (.inf);
Packages — пакеты обновлений безопасности, сервисные, языковые и т.д. (.cab и .msu);
Task Sequences — последовательность задач установки;
Selection Profiles — логические группы объединения контента;
Linked Deployment Shares — другие подключенные DeploymentShare с других серверов;
Monitoring — при включенной опции отображается ход выполнения установки на клиентах.



Открываем свойства нашей шары MDT Deployment Share. На вкладке General можно выбрать для каких платформ создавать .wim файлы с которых позже можно будет загружаться.



На вкладке Rules настраиваются конфигурационные файлы автоматизации MDT. В самом окне отображается текст файла .\Control\CustomSettings.ini, а под кнопкой Edit Bootstrap.ini файл .\Control\Bootstrap.ini.
CustomSettings.ini — находится на сервере и скрывает шаги меню установки, а также определяет некоторые параметры установки.
Bootstrap.ini — находится в загрузочном образе и определяет параметры для подключения к DeploymentShare.



.\Control\CustomSettings.ini

OSInstall=Y //установить операционную систему
JoinDomain=alx*.com //ввести в этот домен
DomainAdmin=alx - имя пользователя используемого для присоединения
DomainAdminDomain=alx*.com //домен пользователя
DomainAdminPassword= //пароль пользователя
AdminPassword= //пароль локального администратора на новой машине
HideShell=YES //скрыть Shell
SkipUserData=NO //пропустить шаг о решении сохранности пользовательских данных (если установка производится поверх существующей системы)
TimeZoneName=N. Central Asia Standard Time //временная зона
SkipTimeZone=YES //пропустить выбор временной зоны
UILanguage=ru-RU //выбор языка интерфейса
UserLocale=ru-RU //выбор местоположения
SkipLocaleSelection=YES //пропустить выбор месторасположения
SystemLocale=ru-RU //выбор языка для non-Unicode программ
SkipCapture=YES //пропустить захват установленной операционной системы
SkipComputerName=NO //пропустить ввод имени компьютера
SkipDomainMembership=YES //пропустить членство в домене
SkipAdminPassword=YES //пропустить пароль администратора
SkipProductKey=YES //пропустить ввод лицензионного ключа
SkipComputerBackup=YES //пропустить выполнение резервного копирования
SkipBitLocker=YES //пропустить настройку шифрования BitLocker
SkipSummary=YES //пропустить страницу с выводом результирующих настроек
EventService=http://SRV04:9800 //установить сервер назначения для логов

Список временных зон



.\Control\Bootstrap.ini

[Settings]
Priority=Default
[Default]
DeployRoot=\\SRV04\DeploymentShare$
UserID=alx //имя пользователя для доступа к папкам Deployment Share
UserDomain=alx*.com //домен пользователя
UserPassword= //пароль пользователя
KeyboardLocale=en-US //выбор языка
SkipBDDWelcome=YES //пропустить начальную страницу установщика

На вкладке Windows PE настраивается создание загрузочных образов. Можно отключить на первой вкладке создание .wim файла, но выбрать на третьей .iso файл, если он нам нужен. Сейчас оставил только платформу x64. Второй пункт Generate a Lite Touch bootable ISO image понадобится, если нам необходим загрузочный ISO файл который мы могли бы записать на флешку или диск и загрузиться с него. Scratch space size — размер памяти в мегабайтах выделяемой для скриптов и команд установщика.



На вкладке Features можем добавить какие-либо компоненты в загрузочный образ. На вкладке Drivers and Patches лучше выбрать созданный специально для загрузочного образа Selection profile с сетевыми драйверами.
На следующей вкладке Monitoring включаем опцию чтобы он начал принимать логи от клиентов во время установки и отображать статус в папке Monitoring.

В соответствии со своей политикой безопасности добавляем разрешения на чтение каталога DeploymentShare$ и на этом простая настройка MDT закончена.



Импорт приложений


В контекстном меню папки Applications выбираем пункт New Application.



Добавим Google Chrome.



Скачиваем Standalone Enterprise на 64 бита и сохраняем в отдельную временную папку, например, E:\Soft. Указываем, где программа находится и выбираем опцию чтобы всё содержимое было перемещено в новую папку.



Далее составляем команду для тихой установки этого приложения и заполняем соответствующее поле.





По аналогии добавляем весь нужный нам софт.

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



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



На последней вкладке Dependencies указываются зависимости. Если для приложения нужны какие-то дополнительные установки, то тут указывается их порядок. Только после установки зависимостей установится основное приложение. Софт, указанный в списке, должен быть импортирован заранее.



Импорт установочных образов


В папку Operating Systems добавляем операционную систему. У меня имеется .wim файл с Windows 10 Pro x64.

Почему .wim?
Лицензий на LTSC нет, только Pro. Поэтому приходится с выходом новой версии скачивать актуальную Windows 10 и с помощью MSMG ToolKit вычищать предустановленное… программы. На выходе получается .iso с вложенным .wim.









Переименовываем в более удобный вид.



Импорт драйверов


Для примера импортируем драйвера для сетевых карт Intel. Стоит сразу заметить, что любые архивы должны быть распакованы т.к. MDT автоматически по указанной директории ищет именно .inf файлы.













Целесообразно создавать подпапки для разделения производителей и моделей компьютерного оборудования. Отдельно стоит выделить драйвера для сетевых карт и дисков для загрузочного образа с помощью Selection Profiles.

Импорт пакетов


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







Создание задач


Task Sequences — это последовательность задач для установки. Можно добавлять, удалять или изменять шаги установки. На первой странице при добавлении задается ID и название.



Выбирается шаблон.



Выбор операционной системы из добавленных ранее.



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



Вводим имя пользователя и название организации.



Пароль будущего локального администратора.



После создания можно аналогично просматривать её свойства и вносить изменения.



На вкладке Task Sequence описан весь процесс выполнения установки. Последовательность необходимо изменять под свои нужды.



Для примера я добавлю скрипт включающий возможность подключиться по RDP т.к. по умолчанию после установки она отключена.

В папке .\Scripts\Custom создан скрипт на PowerShell Enable_RDP.ps1:

(Get-WmiObject Win32_TerminalServiceSetting -Namespace root\cimv2\TerminalServices).SetAllowTsConnections(1,1)
(Get-WmiObject -Class "Win32_TSGeneralSetting" -Namespace root\cimv2\TerminalServices -Filter "TerminalName='RDP-tcp'").SetUserAuthenticationRequired(1)
Enable-NetFirewallRule -DisplayGroup "Remote Desktop"

Далее выбираем желаемое место в этом порядке и добавляем новый пункт.





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

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



Для создания образов выбираем второй пункт.



Обновление DeploymentShare необходимо выполнять после:

  • обновления загрузочных драйверов (сетевых карт и дисковых накопителей);
  • добавления компонентов в загрузочный образ;
  • изменения параметров загрузочного образа;
  • обновления версии Windows ADK;
  • изменения Bootrstrap.ini;
  • изменения файлов «экстра»-директорий.

Переходим в консоль WDS и в папку Boot Images добавляем созданный загрузочный образ. WDS скопирует этот образ в свой рабочий каталог.



Тестирование


Настраиваем на тестовом компьютере загрузку по сети. Сервер WDS определяется автоматически. По умолчанию, компьютер ожидает нажатия F12 для продолжения загрузки. Эта настройка меняется в свойствах сервера WDS на вкладке Boot.





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



Задаем имя компьютера.



Данная настройка позволяет сохранить профили пользователей. У нас чистая установка, поэтому оставим как есть.



Можно и восстановить откуда-либо.



Выбираем необходимый софт.



Дальнейшая установка производится в автоматическом режиме.



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



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



Явные плюсы автоматизации:

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

Полная официальная документация MDT

Комментарии (8)


  1. Fitrager
    09.03.2019 22:30

    По функционалу не уступает аналогичным возможностям из SCCM.


    1. Xeonkeeper
      10.03.2019 14:11

      Есть одно важное различие между деплоем через SCCM и MDT. В MDT это происходит от локальной УЗ администратора, а в SCCM от SYSTEM. Но последние версии SCCM так же можно интегрировать с MDT и использовать в нём MDT task sequence.


  1. HEPB68
    09.03.2019 22:45

    Знающие люди, подскажите
    Есть ли возможность автоматизировать ввод имени будущего ПК?
    В голом WDS это делает достаточно просто, имя берётся из определённого OU в AD и по маске увеличивается.
    А как реализовать данную функцию в MDT?
    Находил ссылку на зарубежный ресурс, там предлагали поднять web сервис, который парсил бы AD и отдавал имя. Сервис я поднял, но вот что-то MDT не захотел брать имя ПК таким образом.
    Заранее благодарю за подсказку


    1. Alx1 Автор
      09.03.2019 23:26

      На мой взгляд, в wds это выглядит как костыль, хоть и вполне рабочий. Имея счетчик, нужно записывать значения хоть в какую-то таблицу. В mdt есть возможность подключить базу данных и оперировать действительно уникальными адресами компьютеров, а им уже назначать имена. Если сделать автоматическое добавление компьютеров в mdt db и добавить переменные в OSDComputerName, то получится эдакий DHCP для UUID/MAC/Serial, только выдает не ip, а имя)


    1. alaxala
      10.03.2019 11:10

      Веб-сервис необязателен. Достаточно vbs-скрипта. Если добавить в CustomSettings.ini

      UserExit=GetCompName.vbs
      OSDComputerName=#GetComputerName()#

      MDT вызовет из скрипта GetCompName.vbs функцию GetComputerName() и присвоит переменной OSDComputerName, которая и определяет будущее имя компьютера, результат этой функции (символы "#" вокруг имени функции обязательны).
      В самом скрипте нам доступны все уже определённые переменные. Например, название домена, указанное в CustomSettings.ini из статьи, доступно как

      oEnvironment.Item(«JoinDomain»)

      Почитайте в документации про параметры Priority, Properties раздела [Settings] файла CustomSettings.ini, параметр Subsection. Там достаточно сложную логику можно реализовать. Можно добавить несколько секций в этот файл с разными значениями одних и тех же параметров и выбирать нужную секцию в зависимости от значений других параметров или результатов вызова скриптов. Можно добавить свои окна в Deploymen Wizard, не говоря уже о своих Task Sequences и их шаблонов.
      И это не костыли. MDT просто так устроен. Он весь состоит из скриптов xml- и ini-файлов.


    1. Xeonkeeper
      10.03.2019 14:33
      +1

      Мы использовали единую базу данных (CMDB) с именами и MAC адресами всех компьютеров организации. С помощью этого модуля был создан скрипт, который по REST api подключается к базе CMDB, берёт список компьютеров с их MAC адресами и заливает их в базу MDT. Скрипт приложу, вдруг кому пригодится (он уродливый и сырой, выкладываю как есть). Он работает через truncate mdt базы — кривое решение и если у вас 1000000 компьютеров, то не сгодится, но с 2000 справляется отлично и быстро.

      Скрипт
      $out =@()

      [Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12

      $Url = "https://otrs.domain.ru/otrs/nph-genericinterface.pl/Webservice/CMDBData/Session"
      $Body = @{"UserLogin"="otrs";"Password"="Password"}
      $SessionID = ((Invoke-WebRequest -Method Post -Uri $url -Body ($Body|ConvertTo-Json) -ContentType "application/json").content | ConvertFrom-Json).SessionID

      $UrlOTRS = "https://otrs.domain.ru/otrs/nph-genericinterface.pl/Webservice/CMDBData/"

      $truncate = "truncate table settings
      truncate table computeridentity
      GO"

      Invoke-SQLcmd -ServerInstance 'windeploy\SQLEXPRESS' -query $truncate -Database MDT

      Connect-MDTDatabase -sqlServer windeploy.domain.ru -instance SQLEXPRESS -database MDT

      $hash = [ordered]@{
      ConfigItem = [ordered]@{
      Class="ПК";
      Number="*"

      }
      }
      $BodySearch = $hash | ConvertTo-Json -Depth 99

      $Response = Invoke-WebRequest -Method POST -Uri "https://otrs.domain.ru/otrs/nph-genericinterface.pl/Webservice/CMDBData/CISearch?SessionID=$SessionID" -Body $BodySearch -ContentType "application/json; charset=UTF-8" | ConvertFrom-Json

      $ConfigItemIDs = $Response.ConfigItemIDs

      #==================Computers

      foreach ($item in $ConfigItemIDs)
      {
      $uri = $UrlOTRS+"CI/"+$item+"?SessionID="+$sessionid;
      $jsonresp = Invoke-WebRequest -Method GET $uri -ContentType "application/json; charset=UTF-8" | ConvertFrom-Json
      if (($jsonresp.ConfigItem.CIXMLData.MAC -match "[a-zA-Z_0-9]") -and (($jsonresp.ConfigItem.deplstate -like "Operation") -or ($jsonresp.ConfigItem.deplstate -like "Prep") -or ($jsonresp.ConfigItem.deplstate -like "Reserve") -or ($jsonresp.ConfigItem.deplstate -like "Relocation")) )
      {
      #write-host $jsonresp.ConfigItem.name -ForegroundColor Green
      #Write-Host $jsonresp.ConfigItem.CIXMLData.MAC
      #Write-Host $jsonresp.ConfigItem.deplstate

      $out += $jsonresp
      }

      }

      $machines = $out

      For ($i=1; $i -le $machines.count; $i++)
      {
      $machines[$i-1].ConfigItem.CIXMLData.MAC=$machines[$i-1].ConfigItem.CIXMLData.MAC.ToUpper() -replace '..(?!$)', '$&:'
      $macvalid=$TRUE
      $temp = $machines[$i-1].ConfigItem.CIXMLData.MAC.Split(":")
      if (($temp.count -ne 6) -or ($machines[$i-1].ConfigItem.CIXMLData.MAC.length -ne 17))
      { $macvalid = $FALSE
      }

      $namevalid=$TRUE
      if ($machines[$i-1].ConfigItem.name.length -gt 15)
      { $namevalid=$FALSE
      }

      if ($namevalid -and $macvalid)
      {
      $validrecords=$validrecords+1
      $machineid=Get-MDTComputer -macAddress $machines[$i-1].ConfigItem.CIXMLData.MAC
      if ($machineid.id -gt 0)
      {
      Remove-MDTComputer $machineid.id
      }
      $OSDPcName = "PC-" + $machines[$i-1].ConfigItem.number
      New-MDTComputer -macAddress $machines[$i-1].ConfigItem.CIXMLData.MAC -description $OSDPcName -settings @{
      OSInstall='YES';
      OSDComputerName=$OSDPcName;
      }
      $machineid=Get-MDTComputer -macAddress $machines[$i-1].ConfigItem.CIXMLData.MAC
      Set-MDTComputerRole $machineid.id "StandardPC"
      }
      else
      { #log the invalid record
      $invalidrecords=$invalidrecords+1
      $text = "Invalid Record : "+$i+" "+$machines[$i-1].mac+" "+$machines[$i-1].name
      $text >> $logfile
      }
      }

      #====================Notebooks

      Clear-Variable out
      $out =@()

      $hash = [ordered]@{
      ConfigItem = [ordered]@{
      Class="Ноутбук";
      Number="*"

      }
      }
      $BodySearch = $hash | ConvertTo-Json -Depth 99

      $Response = Invoke-WebRequest -Method POST -Uri "https://espp.domain.ru/otrs/nph-genericinterface.pl/Webservice/CMDBData/CISearch?SessionID=$SessionID" -Body $BodySearch -ContentType "application/json; charset=UTF-8" | ConvertFrom-Json

      $ConfigItemIDs = $Response.ConfigItemIDs

      foreach ($item in $ConfigItemIDs)
      {
      $uri = $UrlOTRS+"CI/"+$item+"?SessionID="+$sessionid;
      $jsonresp = Invoke-WebRequest -Method GET $uri -ContentType "application/json; charset=UTF-8" | ConvertFrom-Json
      if ($jsonresp.ConfigItem.CIXMLData.EthMAC -match "[a-zA-Z_0-9]" -and (($jsonresp.ConfigItem.deplstate -like "Operation") -or ($jsonresp.ConfigItem.deplstate -like "Prep") -or ($jsonresp.ConfigItem.deplstate -like "Reserve") -or ($jsonresp.ConfigItem.deplstate -like "Relocation")) )
      {
      #write-host $jsonresp.ConfigItem.name -ForegroundColor Green
      #Write-Host $jsonresp.ConfigItem.CIXMLData.EthMAC
      $out += $jsonresp
      }

      }

      #$out | fl

      $machines = $out

      For ($i=1; $i -le $machines.count; $i++)
      {
      $machines[$i-1].ConfigItem.CIXMLData.EthMAC=$machines[$i-1].ConfigItem.CIXMLData.EthMAC.ToUpper() -replace '..(?!$)', '$&:'
      $macvalid=$TRUE
      $temp = $machines[$i-1].ConfigItem.CIXMLData.EthMAC.Split(":")
      if (($temp.count -ne 6) -or ($machines[$i-1].ConfigItem.CIXMLData.EthMAC.length -ne 17))
      { $macvalid = $FALSE
      }

      $namevalid=$TRUE
      if ($machines[$i-1].ConfigItem.name.length -gt 15)
      { $namevalid=$FALSE
      }

      if ($namevalid -and $macvalid)
      {
      $validrecords=$validrecords+1
      $machineid=Get-MDTComputer -macAddress $machines[$i-1].ConfigItem.CIXMLData.EthMAC
      if ($machineid.id -gt 0)
      {
      Remove-MDTComputer $machineid.id
      }
      $OSDNbName = "NB-" + $machines[$i-1].ConfigItem.number
      New-MDTComputer -macAddress $machines[$i-1].ConfigItem.CIXMLData.EthMAC -description $OSDNbName -settings @{
      OSInstall='YES';
      OSDComputerName=$OSDNbName;
      }
      $machineid=Get-MDTComputer -macAddress $machines[$i-1].ConfigItem.CIXMLData.EthMAC
      Set-MDTComputerRole $machineid.id "StandardPC"
      }
      else
      { #log the invalid record
      #$invalidrecords=$invalidrecords+1
      #$text = "Invalid Record : "+$i+" "+$machines[$i-1].mac+" "+$machines[$i-1].name
      #$text >> $logfile
      }
      }



  1. YMax
    12.03.2019 11:51

    Как-то излишне сложно на мой взгляд — достаточно периодически обновлять на виртуальной машине мастер-образ со всем софтом, закрывать его sysprep, полученный образ заливать на WDS и устанавливать при необходимости, получая при этом 100% рабочую систему. В сохранении данных пользователя смысла вообще нет, потому что применяются перемещаемые профили и перенаправление папок пользователя — при первом входе происходит синхронизация данных. Имя компьютера мне всё же удобнее задавать руками, хотя это можно и автоматизировать, но не было такой необходимости.


    1. Alx1 Автор
      12.03.2019 12:03

      Начнём с того, что всё зависит от задач. Не все используют перемещаемые профили, например. В некоторых случаях имеет смысл автоматизировать процесс от А до Я.
      Иметь машину с мастер-образом позволит иметь одну конфигурацию. Но если мне понадобится точно такой же, но с перламутровыми пуговицами, то придется устанавливать всё вручную. В предложенном же варианте есть возможность устанавливать различные конфигурации не держа при этом похожие друг на друга образы с повторяющимся софтом. И обновить тот же Adobe Reader во всех конфигурациях не составит проблем, чем снимать образы с мастер-машин.