Как один символ ломает установку Windows
Амперсанд в файле ответов делает его невалидным. Установщик молчит, а человек не понимает, почему ничего не применилось.
У меня на сайте есть генератор autounattend.xml — файла, который Windows читает во время установки и настраивает систему сама, без вопросов. Человек отмечает нужные пункты, нажимает кнопку, получает готовый файл, кладёт его на флешку.
Работало это ровно до тех пор, пока кто-нибудь не отмечал тёмную тему. Или удаление OneDrive. Или русскую раскладку. После этого файл переставал работать — молча, без единого сообщения об ошибке.
Что происходило
Генератор собирал команды в такой блок:
<SynchronousCommand wcm:action="add">
<Order>1</Order>
<CommandLine>cmd.exe /c reg add ... /d 0 /f & reg add ... /d 0 /f</CommandLine>
</SynchronousCommand>
Обратите внимание на амперсанд посередине. В командной строке Windows он означает «выполни сначала одно, потом другое» — обычный способ склеить две команды в одну строку.
А в XML амперсанд — служебный символ. С него начинаются сущности вроде < или " . Встретив голый &, разборщик ждёт продолжения, не находит его и объявляет документ невалидным.
Проверка
Я взял ровно ту строку, что выдавал генератор при включённой тёмной теме, и скормил её обычному разборщику XML:
ОШИБКА РАЗБОРА XML: not well-formed (invalid token): line 8, column 163
Файл был битым. Не «неоптимальным», не «с замечаниями» — просто нечитаемым.
Почему это было незаметно
Самое неприятное здесь — не сама ошибка, а то, как она проявлялась.
Windows не показывает окна с текстом «ваш файл ответов сломан». Установщик просто не находит валидный файл и продолжает обычным путём: спрашивает язык, регион, учётную запись. Ровно так, как если бы файла на флешке вообще не было.
Человек делает вывод, что генератор не работает. Проверяет, правильно ли записал флешку. Пробует ещё раз. И никогда не догадается, что дело в одном символе внутри команды, которую он даже не видел.
Ошибка, которая ломает всё молча, хуже ошибки, которая падает с криком. Второе чинят за час. Первое живёт месяцами.
Масштаб
Я прошёл по всем настройкам и посмотрел, в каких командах есть амперсанд. Их оказалось четыре:
- тёмная тема — два обращения к реестру подряд
- удаление OneDrive — завершение процесса плюс запуск деинсталлятора
- русская раскладка — две записи в реестр
- обход проверки TPM — несколько ключей за раз
В генераторе тогда были готовые наборы настроек — три штуки, для игр, для приватности и базовый. Я проверил каждый:
Gamer -> ЛОМАЕТСЯ (тёмная тема)
Privacy -> ЛОМАЕТСЯ (удаление OneDrive)
Basic -> ЛОМАЕТСЯ (тёмная тема)
Все три. То есть человек, который заходил на страницу и нажимал любую из трёх больших кнопок, гарантированно получал нерабочий файл.
Как чинится
Всё, что попадает внутрь XML, нужно экранировать — заменять служебные символы на их безопасные обозначения. Функция занимает пять строк:
function esc(value) {
return String(value)
.replace(/&/g, '&')
.replace(/</g, '<')
.replace(/>/g, '>')
.replace(/"/g, '"');
}
Порядок замен важен. Амперсанд идёт первым: если поменять его местами с остальными, то уже подставленные < сами превратятся в &lt;, и результат снова окажется испорченным.
Дальше остаётся пропускать через неё вообще всё, что уходит в файл:
'<CommandLine>cmd.exe /c ' + esc(cmd) + '</CommandLine>'
И не только команды. Имя компьютера, которое вводит человек. Пароль. Любое поле. Достаточно одному пользователю назвать компьютер Вася & Петя — и файл снова битый.
Результат
После правки та же команда с тёмной темой выглядит так:
<CommandLine>cmd.exe /c reg add "HKCU\..." /d 0 /f & reg add ...</CommandLine>
Кавычки стали ", амперсанд — &. Windows при чтении превратит их обратно и выполнит ровно то, что задумано.
Я собрал файл со всеми настройками разом, вписал в поле имени компьютера PC & <script>, в пароль — p@ss"<&>, и прогнал через разборщик:
Твиков в словаре: 38
Команд с амперсандом: 3
РЕЗУЛЬТАТ: XML валиден
Что из этого следует
Правило простое и старое: никогда не вставляйте строку в разметку напрямую. Ни в XML, ни в HTML, ни в SQL-запрос. Всегда через функцию, которая приводит данные к безопасному виду.
Звучит очевидно. Но ошибка возникает не там, где вы помните о ней, а там, где не ожидаете подвоха. Мне казалось, что команды для реестра — это мои собственные строки, я их писал сам, что там может быть не так. Оказалось, амперсанд.
И второй вывод, менее очевидный. Я нашёл эту ошибку только потому, что дошёл до конца и прогнал установку в виртуальной машине. Код выглядел правильным. XML на глаз казался корректным. Проверка на живой системе показала обратное.
Если ваш инструмент делает что-то, чего вы не можете проверить глазами, — проверьте машиной. Разборщик XML занимает три строки кода и находит то, что человек пропустит.