Есть вещь, которую я до сих пор считаю лучшим, что случалось с развёртыванием Windows: ты подходишь к машине, выбираешь в начале всё, что тебе нужно, — и больше её не касаешься. Идёшь пить чай. Через несколько минут возвращаешься к готовому компьютеру с именем, в домене, с драйверами и софтом.
Это MDT. И его больше нет.
Дальше — история о том, как я в него влюбился, как он у меня разваливался, как я упёрся в стену, и что из этого получилось.
Как всё начиналось
Я устроился на первую работу техником — совсем зелёным. В контору регулярно завозили новые моноблоки и компьютеры, и каждый требовал ручной установки Windows: флешка, мастер установки, драйверы, имя, ввод в домен, софт. В месяц приходило от 5 до 30 машин — предсказать поток или подготовиться к нему заранее было нельзя. Нас было трое техников, но даже этого объема сил не хватало.
Узким местом был сам установочный носитель. На части машин для загрузки с нашей флешки приходилось заходить в UEFI, отключать Secure Boot, а после установки — не забывать включить его обратно. Были и совсем бытовые мелочи: флешку надо найти, принести, не оставить в очередном кабинете и не забыть забрать после установки. Каждая такая забота кажется ерундой, пока не повторяется десятки раз.
Второе узкое место оказалось неожиданнее. Чтобы довести установку до конца, технику нужно было имя для машины — а выдавал его администратор. Сам шаг занимал секунды. Но он был синхронным: надо было найти админа, отвлечь его от своих дел, дождаться ответа.
То есть на установку одного компьютера фактически требовалось двое людей. Пусть второй и участвовал мгновение — без него процесс не двигался. Запомните этот момент. К нему я ещё вернусь. Довольно быстро стало понятно, что так жить нельзя.
Первое решение: WDS
Поднять WDS и раздавать установку по сети оказалось делом одного вечера. WDS убрал физический носитель из процесса. Машина загружалась по UEFI PXE с включённым Secure Boot, получала установочный образ и ставила Windows. Техник больше не таскал одну и ту же флешку между рабочими местами. Отлично. И тут выяснилось, что лёгкая часть кончилась.
Потому что «поставить Windows» — это 30% работы. Остальное: дать машине правильное имя из корпоративной последовательности, ввести её в домен, накатить драйверы под конкретную модель, поставить обязательный софт и понимать, что происходит с установкой прямо сейчас.
Здесь нужна честная поправка спустя годы: WDS умел больше, чем я тогда понимал.
Он мог генерировать имена по заданной политике, назначать им OU и параметры ввода в домен. Неизвестную машину можно было оставить в ожидании, а затем одобрить после PXE‑запроса, уже тогда задав ей имя и место в AD но это всё‑равно требовало будто доступа с двух сторон, а хотелось как оператор станка — где администратор лишь в исключительных случаях, а не на каждый Апрув. Тогда я этого не знал. Но это не отменяет следующего шага: мне нужен был не набор отдельных возможностей сервера, а один операторский процесс, похожий на тот, который позже дал MDT.
У конкретной машины оператор должен был в одном месте выбрать физический диск, образ, драйверпак, набор программ, имя и сам факт ввода в домен, а затем видеть весь путь установки до конца. В WDS эти решения были распределены между политиками сервера, answer‑файлами, Active Directory, предварительной подготовкой объектов и действиями администратора.
Поэтому WDS решил для меня транспорт и часть автоматизации, но не заменил целостный сценарий развёртывания под оператора.
Пятая попытка
WDS у меня заработал, и начальство выдало следующую задачу. Вместе с ней — MDT, с пояснением, что до меня за него уже брались другие техники. И у них не получилось.
Сервер, который выделили под меня, назывался: предприятие‑wds-05.
Пятый. Я был пятой попыткой заставить нашу схему нормально вводить машины в домен.
По‑хорошему, это должно было насторожить. Но признаться во словно заиграл азарт и вызов, хоть и некое чувство отвественности провала взложилась невольно на мои плечи.
Когда мне открыли доступ к наработкам предшественников, ощущение было буквально как в той сцене из «Аватара», где Аанг в видении оборачивается и видит уходящую вдаль вереницу прошлых Аватаров.
MDT: то, ради чего всё затевалось
Так я пришёл к Microsoft Deployment Toolkit.
И вот тут случилась любовь. Флоу MDT устроен ровно так, как я описал в начале: оператор задаёт параметры на старте, дальше машина всё делает сама. Никакого «подойди через десять минут и нажми Далее». Выбрал, а вернулся к готовому.
двумя словами:

Для автоматической генерации имён я взял известный скрипт с deploymentresearch — префикс плюс порядковый номер. Какое‑то время всё работало. А потом начало сыпаться.
Трещина первая: имена машин
Сам по себе скрипт работал. Повторная установка той же машины проблемой не была — имя тянулось из таблицы. Беда была в другом: счётчик жил отдельно от реальности.
Работы было много, а настроить пересылку PXE‑запросов до WDS во всех нужных сетевых сегментах времени не хватало. Поэтому часть машин ставилась мимо WDS и MDT, потому что надо было прямо сейчас. Такие машины появлялись в сети и в домене, но счётчик о них не знал.
С другой стороны, были компьютеры, которые ставились через WDS и MDT но в домен вообще не вводились. А счётчик всё равно считал, что имя израсходовано, и уходил на +1. В обе стороны расхождение. И каждый раз я лез править счётчик руками.
Оглядываясь, проблема была не в скрипте. Проблема была в том, что источником правды считался счётчик, а не домен. Счётчик знает только то, что прошло через MDT. Домен знает всё. Фрустрация копилась.
Трещина вторая: а на какой диск ставим?
Вот это, пожалуй, довело меня сильнее всего.
В штатном мастере MDT не было нативного выбора физического диска оператором. Номер диска можно было заранее задать через правила или последовательность задач, но решение принимал администратор до запуска, а не оператор, который стоит перед конкретной машиной. Даже UDI в связке с Configuration Manager штатно предлагал форматирование Disk 0, а не список физических накопителей для выбора.
Практический результат в моей тогдашней реализации: я держал два разных варианта развёртывания под разные случаи. Не потому что машины принципиально разные, а потому что диск в них нумеровался по‑разному. Я пробовал прикрутить кастомные скрипты с форумов. Не завелось.
Не верите, что это распространённая боль? Вбейте в поиск mdt choose disk. Там сотни людей, которые ищут ровно это. Вот, например, обсуждение на serverfault — посмотрите, как выглядит ответ. И вот здесь я сформулировал для себя мысль, которая позже стала архитектурной:
MDT просит администратора предугадать конфигурацию железа заранее. Я хотел спросить оператора, который стоит перед машиной.
Это не разница в интерфейсе. Это разница в том, кто принимает решение и в какой момент.
Трещина третья: интерфейс и мониторинг
Тут будет субъективно.
GUI MDT был мне отчасти враждебен. Я допускаю, что дело в неопытности — но факт остаётся: я тратил время на борьбу с интерфейсом вместо работы.
Отдельно раздражал мониторинг стадий установки. Мне хотелось видеть, что происходит с машиной прямо сейчас, и вроде как этапы показывались но это требовало доступа к оснастке MDT, т.е нельзя дать это операторам в удобном виде и хоть недавно я прочитал, что доступ то выдать можно на отдельные сегменты но даже реализация выдачи доступов в разные разделы мне показалась вреждебной. А если посмотреть устаревшие Деплои то... чаще пустота и главное, что я тогда не мог понять: где мои ошибки, а где баги MDT. Конструкция становилась нестабильнее по мере жизни, а я, будучи джуном, не мог отличить одно от другого. Это худшее положение, в котором можно оказаться: ты не знаешь, чинить себя или инструмент.

Стена
В какой‑то момент я решил пересобрать сервер с нуля. По‑хорошему, с чистого листа, с учётом всех набитых шишек и опыта. И обнаружил, что MDT закончился.

Его нельзя официально скачать. Нет, серьёзно — попробуйте. Остаются неофициальные сайты и надежда, что в архиве нет ничего лишнего.
Это, кстати, тот самый момент, ради которого я пишу эту статью. Если вы сегодня поддерживаете инфраструктуру развёртывания на MDT — вы в подвешенном состоянии. Оно работает, пока работает. А как только понадобится переставить сервер, вы окажетесь там же, где оказался я.
И не только я. Вот тред в r/MDT: человек обнаружил ровно это, а в комментариях подтягиваются остальные с тем же открытием. Почитайте, там всё узнаваемо.
Что было вокруг
Раз MDT кончился, надо было смотреть по сторонам:
SCCM. Платный, требует инфраструктуры. Для парка, который у меня был, это из пушки по воробьям, да и денег никто не даст.
Intune / Autopilot. Подписка и облако. Те же деньги, плюс зависимость, которая мне не подходила.
FOG. Бесплатный, живой, но у него принципиально другая модель — capture. И вот здесь стоит остановиться, потому что это водораздел.
Capture против deploy from stock
Модель capture (FOG, Clonezilla, в прошлом Ghost): собираешь эталонную машину, снимаешь с неё образ, раскатываешь этот образ дальше. Быстро при развёртывании.
Но: образ стареет. Его надо пересобирать при обновлении Windows, при новом поколении железа, при смене набора софта. Sysprep капризничает. Золотой образ превращается в отдельный объект, который сам требует обслуживания.
Модель deploy from stock (MDT, SCCM OSD): берётся чистый установочный образ Windows, а всё остальное — драйверы, софт, имя, домен — накладывается в момент развёртывания.
Медленнее на одну машину. Зато компоненты обслуживаются отдельно: установочный образ, драйверы и софт. Ради обновления одного из них не нужно пересобирать целую эталонную машину. Мне ближе вторая. Именно её я любил в MDT, и именно из‑за неё FOG мне не подошёл — не потому что он плохой, а потому что он про другое.
Решение
Итого: среди решений, которые я рассмотрел, я не нашёл живого бесплатного инструмента под тот локальный deploy‑from‑stock сценарий, который мне был нужен.
Я решил написать свой.

Но прежде чем перейти к технике
Есть ещё одна причина, по которой этот пост вообще существует, и будет нечестно её умолчать. Мне очень хочется выговориться. Проект я делал один (предчувствую взгляд чата гпт). Обсудить, почему решение принято так, а не иначе, было буквально не с кем — а когда варишься в своей голове месяцами, перестаёшь понимать, где у тебя разумный компромисс, а где просто привычка.
Поэтому я публикую это не только как «смотрите, что получилось». Я прошу посмотреть на это со стороны и сказать, где криво. Мне сейчас полезнее услышать «вот здесь у тебя странное решение, и вот почему», чем «молодец». Идеи, замечания по архитектуре, «а почему не вот так» — всё это я читаю с большим интересом, чем плюсы в карму.
Ну и, если совсем начистоту, это ещё и способ утолить социальный голод. Разработка в одиночку — очень тихое занятие. Проект называется IronDeploy. Дальше — как он устроен.

Архитектура
Четыре компонента, у каждого своя зона ответственности:
Компонент | За что отвечает |
|---|---|
SetupWeb | одноразовая локальная страница первичной настройки |
IronAPI | control plane: авторизация, план развёртывания, состояние, интеграция с AD |
WinPE | интерфейс оператора, стирание диска, применение образа |
Post‑install | доустановка софта в уже поставленной системе |
WDS/PXE или загрузочный носитель только доставляют WinPE. Тяжёлые payload’ы — образы, драйверы, установщики — едут по SMB. Во время развёртывания IronAPI не проксирует эти файлы: он выдаёт план и реквизиты доступа, а WinPE забирает их напрямую с SMB.
Разделение намеренное. Гонять двухгигабайтный пак драйверов через Python‑приложение — плохая идея, когда рядом есть SMB, который делает это лучше.
WinPE и интерфейс
Интерфейс оператора — WPF‑приложение, запускаемое внутри WinPE в STA‑режиме.
Сразу оговорка: WPF в WinPE официально не поддерживается Microsoft. Это не уязвимость само по себе, но совместимость не гарантируется. На используемых мной сборках ADK интерфейс работает, и для альфы я этот риск принял.
Из ограничений среды вытекает всё остальное: в WinPE нет.NET в привычном виде, нет большинства служб, а сама среда работает с системного RAM‑диска X:. Это накладывает жёсткие рамки на то, что можно себе позволить, и по‑своему дисциплинирует.
Отдельно я сделал так, что если WPF не стартовал — скрипт честно падает с ошибкой в консоль WinPE и не запускает никакого альтернативного сценария развёртывания. Мне не нужен инструмент, который в непонятной ситуации начинает что‑то делать с диском.
Там же живёт защита от запуска не в том месте:
if ( $env:SystemDrive -ine "X:" -or !(Test-Path -LiteralPath "HKLM:\SYSTEM\CurrentControlSet\Control\MiniNT") ) { throw "IronDeploy deploy.ps1 may only run inside Windows PE." }
Два условия: системный диск должен быть X: и должен присутствовать ключ реестра MiniNT. Обычный запуск этого скрипта на рабочей Windows будет остановлен до разрушительной фазы. Это дополнительный предохранитель, а не замена нормальной проверке выбранного диска.
Выбор диска
То, ради чего половина истории. Оператор видит список физических дисков с номером, моделью и размером. Выбирает, подтверждает.
Но выбрать мало. Между моментом выбора и моментом стирания есть зазор, и в этом зазоре может разъехаться что угодно — перечисление, нумерация, подключённая флешка. Поэтому перед разрушительной фазой WinPE заново опрашивает выбранный диск и останавливается, если его номер, модель или размер не совпали с тем, что подтвердил оператор. Логика простая: если экран показал одно, а в системе оказалось другое — значит, оператор согласовывал вслепую, и никакого согласия на самом деле не было. Снимок выбора (номер, модель, размер) при этом уходит в IronAPI и сохраняется вместе с развёртыванием. Потом видно, на что именно ставили.
Образ
Применение — обычный DISM:
dism.exe /Apply-Image /ImageFile:<путь> /Index:<индекс> /ApplyDir:C:\
Никакой магии. Разбивка диска под UEFI/GPT через diskpart, применение образа, запись unattend.xml.
Поддерживаются WIM и ESD. ESD можно развернуть напрямую, но для регулярной работы лучше сконвертировать в WIM — это делается на сервере через интерфейс IronAPI. Перед применением WinPE сверяет размер файла с тем, что заявил API. Дёшево и отсекает очевидно оборванную передачу образа.

Драйверы
Драйверы инжектятся в оффлайн‑образ до первой загрузки. Оператор выбирает один пакет под определённое железо или отказывается от драйверов вовсе.
Пакеты лежат на SMB, а не в образе. Это и есть главное преимущество модели deploy from stock: чтобы добавить поддержку новой модели, не нужно ничего пересобирать — положил папку с драйверами, и всё.
Загрузка драйверов через веб‑интерфейс обвешана ограничениями: количество файлов, глубина вложенности, длина полного пути, минимум свободного места. Пак драйверов от вендора умеет быть очень странным, и лучше отказать на загрузке, чем упасть посреди развёртывания.
Offline Domain Join
Самая недооценённая часть всей темы. Про неё мало кто знает, а вещь красивая.
Задача: ввести машину в домен, когда она ещё даже не загрузилась.
Решение существует в самой Windows — djoin.exe. На сервере, от имени учётной записи с делегированными правами, выполняется:
djoin.exe /provision /domain <домен> /machine <имя> /machineou <OU> /savefile <файл>
Windows создаёт или переиспользует в AD учётную запись компьютера и формирует блоб — файл, содержащий всё необходимое для вступления в домен. Дальше этот блоб применяется к оффлайн‑образу через DISM, и машина загружается уже членом домена. Без ручного ввода, без перезагрузки ради этого.
Важная деталь, которая определяет всё остальное: в блобе лежит секрет машинной учётной записи. Это не метаданные, это credential.
Отсюда обращение с ним:
блоб живёт в защищённом каталоге на сервере, не на SMB;
у него короткое время жизни — по умолчанию пять минут между созданием и выдачей;
если развёртывание не забрало блоб за это время, он не переиспользуется: IronAPI либо провижинит заново, либо вычищает сироту;
после подтверждения применения блоб удаляется;
при зафиксированной ошибке или истечении срока развёртывания он тоже удаляется и не остаётся лежать бессрочно.
Причина короткого TTL не в паранойе: djoin /provision сбрасывает пароль машинной учётки при каждом вызове. Старый блоб не просто небезопасен — он ещё и может быть уже невалиден.
И отдельно: IronDeploy не хранит отдельные доменные учётные данные в своей конфигурации или базе. Ни LDAP‑поиск, ни djoin.exe не используют отдельный пароль — они работают от имени той учётной записи Windows, под которой запущена служба IronAPI. Пароль самой службы хранит и обслуживает Windows Service Control Manager. Меньше секретов в приложении — меньше поводов для беспокойства.
Имена машин
Та самая боль, с которой всё началось. И решение здесь ровно одно: выкинуть счётчик.
IronAPI не хранит номер последней выданной машины. Вместо этого при каждом запросе он спрашивает у Active Directory: какие объекты компьютеров с этим префиксом сейчас существуют и какой у них максимальный номер? Дальше прибавляет единицу.
PC00001, PC00002, PC00003 — но не потому, что кто‑то считал, а потому что PC00002 в домене уже лежит.
Из этого само собой следует то, чего мне не хватало:
машину поставили руками мимо всякого развёртывания и ввели в домен — она видна в AD, и её номер учтён;
машину развернули без ввода в домен — в AD её нет, номер не израсходован, ничего не сдвинулось;
отдельному счётчику больше не с чем рассинхронизироваться, потому что его нет. Домен и есть источник.
Править руками больше нечего — нет того, что можно было бы испортить.
Оговорка: предложенное имя пока не резервируется атомарно. Если две машины одновременно запросят следующее имя до создания объекта в AD, они могут получить одинаковый ответ. В моём сценарии развёртывания почти всегда запускаются последовательно, поэтому гонка редкая, но для альфы это известное ограничение.
Отдельно оператору показываются имена, которые эта конкретная железка носила раньше: по серийному номеру и MAC из истории развёртываний. Это не влияет на предложение имени, просто полезно знать, что машина уже была PC00042, когда переставляешь её же.
Цена решения — без настроенного LDAP предложения имён не работает. По‑моему, честный размен: последовательность имён и существует только в контексте домена.
А теперь обещанное возвращение к началу.
Помните, что на установку одной машины требовалось двое людей — техник и администратор, который выдаёт имя?
Администратора в этой схеме больше нет. Оператор видит предложенное имя прямо на экране WinPE, вместе с историей этой железки, и подтверждает его сам. Никого не надо искать, отвлекать и ждать.

Для меня это, пожалуй, важнее девяти минут. Минуты — это про скорость. А тут исчезла целая зависимость от другого человека.
Безопасность
Инструмент, который стирает диски, ходит в AD и раздаёт учётные данные для SMB, обязан относиться к себе серьёзно.
Один вход — одно развёртывание. Оператор авторизуется в WinPE и получает bearer‑токен. Токен привязывается к конкретному развёртыванию атомарной операцией, и повторно использовать его нельзя. Есть жёсткий таймаут от начала до конца, не сдвигаемый.

Учётная запись для SMB должна иметь только чтение. Это отдельная identity, не совпадающая с учётной записью службы. Права на чтение необходимо задать и в SMB, и в NTFS. Она нужна WinPE, чтобы забрать образ и драйверы, и больше ни для чего.
Служба не работает от LocalSystem. Раньше такой вариант был как fallback с предупреждением. Я его выпилил полностью: теперь принимается только выделенная учётная запись — доменная или локальная, если AD не используется. Встроенные системные identity, домен BUILTIN и встроенная учётная запись Administrator с RID 500 отклоняются по SID. Проверка не анализирует членство обычной учётки в привилегированных группах, поэтому требование использовать действительно отдельную служебную учётку остаётся на администраторе.
Транспорт. В рабочей сети IronAPI должен использовать HTTPS с включённой проверкой сертификата. HTTP и отключённая проверка сертификата предназначены только для изолированного тестового стенда: через API передаются bearer‑токен и реквизиты read‑only SMB‑учётки.
Установщики проверяются по SHA-256. Хеш считается на сервере, сверяется после копирования на машину и ещё раз перед запуском. Несовпадение — отказ выполнять.
Active Directory опциональна. Если домена нет, LDAP‑поля и настройки ODJ оставляются пустыми, и обе функции отключаются. Развёртывание в рабочей группе работает штатно, без выдумывания фиктивных значений.
Результат
HP 27-cx, M.2 NVMe, гигабитная сеть. Windows 11 25H2, пакет драйверов на 2 ГБ и пять программ: PDF24, Битрикс24, 7-Zip, Zoom и Google Chrome.
Девять минут от подтверждения параметров в WinPE до момента, когда Windows, драйверы и выбранный софт уже установлены, а система переходит к применению групповых политик перед первым входом пользователя. Время применения самих политик в замер не входит.
Но дело даже не в минутах. Дело в том, что вернулось то самое ощущение, ради которого всё затевалось:
ты в начале выбрал, что хотел — и дальше не касаешься машины.
Она сама разметит диск, поставит систему, вкатит драйверы, возьмёт имя, войдёт в домен и доустановит софт. А ты в это время занимаешься чем‑нибудь другим.
Что не работает
Это альфа, и я не буду делать вид, что это не так.
Развёртывание рассчитано на x64 UEFI/GPT. BIOS/MBR нет.
Выбранный диск стирается полностью. Существующие разделы пока не показываются перед подтверждением — только номер, модель и размер.
Захвата эталонной машины нет и не планируется. Это осознанный отказ, а не пробел.
Управлением машинами после развёртывания проект не занимается. Обновления, политики, инвентаризация — это соседняя категория продуктов.
Проверено на моём парке. Ваше железо, прошивки, сеть и образы отличаются.
И самое главное: IronDeploy безвозвратно стирает выбранный диск. Тестируйте на виртуалке или на машине, которую не жалко. Не на своём рабочем компьютере.
Зачем я это выкладываю
Проект под Apache 2.0, лежит на GitHub: https://github.com/Syrinoxsis/IronDeploy
Мне нужно не «звёздочку поставьте». Мне нужны отчёты о железе. (хотя звёздочку хочу увидеть как молодой разраб)
Самое ценное, что можно прислать, — это рассказ о том, что сломалось на вашей модели: производитель, модель, SKU, на какой стадии упало, кусок лога, был ли включён ввод в домен, какой пакет драйверов выбирали. Такие вещи невозможно найти, сидя на одном парке техники.
Сообщения о том, что модель развернулась чисто, тоже полезны — из них складывается список проверенного железа.
На этапе альфы я не готов принимать изменения в разрушительном deployment‑пути без воспроизводимого стенда и сценария проверки. Код, который стирает диски или обрабатывает секреты машинных учёток, недостаточно проверить чтением — его надо прогнать на стенде с ADK и доменом. Зато документация, тест‑кейсы и точные отчёты об ошибках приветствуются: здесь хорошее описание проблемы часто ценнее диффа.
И если вы сейчас сидите на MDT и думаете, что делать дальше — напишите, чем закончилось. Мне правда интересно, кто как выкручивается.
Честно говоря в моменте осознал, что толком ничего не рассказал про интерфейс самого IronApi и то как это вообще управляется, а я смотрю на статью и её чудовищную огромность испытываю лишь:

Поэтому держите просто нарезков фрагов...ой т.е интерфейса:




Удачи всем!

