Поделиться через


Обновление установочного носителя Windows с помощью динамического обновления

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

Корпоративный носитель доступен для каждого выпуска Windows в Центре обслуживания корпоративного лицензирования (VLSC) и других соответствующих каналах, таких как Центр обновления Windows для бизнеса, Windows Server Update Services (WSUS) и подписки Visual Studio. Вы можете использовать динамическое обновление, чтобы обеспечить наличие на устройствах Windows последних пакетов обновления компонентов в рамках обновления на месте при сохранении языковых пакетов и компонентов по запросу (FOD), которые могли быть установлены ранее. Динамическое обновление также устраняет необходимость установки отдельного обновления качества в рамках процесса обновления на месте.

Динамическое обновление

Каждый раз, когда начинается установка обновления компонентов (с носителя или среды, подключенной к Центру обновления Windows), динамическое обновление является одним из первых шагов. Программа установки Windows связывается с конечной точкой Майкрософт для получения пакетов динамического обновления, а затем применяет эти обновления к установочному носителю операционной системы. Пакеты обновлений включают следующие типы обновлений:

  • Обновления Setup.exe двоичных файлов или других файлов, которые программа установки использует для обновления компонентов
  • Обновления для "безопасной операционной системы" (SafeOS), используемой для среды восстановления Windows
  • Обновления стека обслуживания, необходимые для завершения обновления компонентов Дополнительные сведения см. в разделе Обновления стека обслуживания.
  • Последнее накопительное (качественное) обновление
  • Обновления применимых драйверов, уже опубликованные производителями, специально предназначенные для динамического обновления

Динамическое обновление сохраняет языковые пакеты и пакеты компонентов по запросу, повторно запрашивая их.

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

Получение пакетов динамического обновления

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

Пакеты динамического обновления Windows 11 версии 22H2 и более поздних версий

Заголовок может различать каждый динамический пакет. В последние накопительные обновления внедрен стек обслуживания. Стек обслуживания публикуется только при необходимости для данного накопительного обновления. Ниже приведены заголовки для Windows 11 версии 22H2. Windows 11 версии 23H2 и 24H2 имеют аналогичный формат.

Обновление пакетов Title
Безопасное динамическое обновление ОС ГГГ-ММ безопасное динамическое обновление ОС для Windows 11 версии 22H2
Настройка динамического обновления ГгГГ-ММ: динамическое обновление установки для Windows 11 версии 22H2
Последнее накопительное обновление ГгГГ-ММ накопительное обновление для Windows 11 версии 22H2
Динамическое обновление стека обслуживания Обновление стека обслуживания ггГГ-ММ для Windows 11 версии 22H2

Пакеты динамического обновления Windows 11 версии 21H2

Для различения каждого динамического пакета требуется название, продукт и описание . В последнее накопительное обновление внедрен стек обслуживания. Стек обслуживания публикуется отдельно, только если это необходимо в качестве необходимого условия для данного накопительного обновления.

Обновление пакетов Title Продукт Описание
Безопасное динамическое обновление ОС Динамическое обновление ГГГГ-ММ для Windows 11 Динамическое обновление безопасной ОС Windows ComponentUpdate
Настройка динамического обновления Динамическое обновление ГГГГ-ММ для Windows 11 Динамическое обновление Windows 10 и более поздних версий SetupUpdate
Последнее накопительное обновление ГГГГ-ММ накопительное обновление для Windows 11
Динамическое обновление стека обслуживания Обновление стека обслуживания ггГГ-ММ для Windows 11 версии 21H2

Пакеты динамического обновления Windows 10 версии 22H2

Для различения каждого динамического пакета требуется название, продукт и описание . В последнее накопительное обновление внедрен стек обслуживания. Стек обслуживания публикуется отдельно, только если это необходимо в качестве необходимого условия для данного накопительного обновления.

Обновление пакетов Title Продукт Описание
Безопасное динамическое обновление ОС Динамическое обновление ГГГГ-ММ для Windows 10 версии 22H2 Динамическое обновление безопасной ОС Windows ComponentUpdate
Настройка динамического обновления Динамическое обновление ГГГГ-ММ для Windows 10 версии 22H2 Динамическое обновление Windows 10 и более поздних версий SetupUpdate
Последнее накопительное обновление ГГГГ-ММ накопительное обновление для Windows 10 версии 22H2
Динамическое обновление стека обслуживания Обновление стека обслуживания ггГГ-ММ для Windows 10 версии 22H2

Если вы хотите настроить образ с помощью дополнительных языков или функций по запросу, скачайте дополнительные ISO-файлы мультимедиа из Центра обслуживания корпоративного лицензирования. Например, если динамическое обновление будет отключено для ваших устройств и пользователям требуются определенные функции по запросу, их можно предварительно включить в образ.

Обновление установочного носителя Windows

Правильное обновление установочного носителя включает в себя множество действий, выполняемых с несколькими разными целевыми объектами (файлами образов). Некоторые действия повторяются в разных целевых объектах. К целевым файлам образов относятся:

  • Среда предустановки Windows (WinPE): небольшая операционная система, используемая для установки, развертывания и восстановления операционных систем Windows.
  • Среда восстановления Windows (WinRE): исправит распространенные причины незагрузимых операционных систем. WinRE основан на WinPE и может быть настроен с помощью дополнительных драйверов, языков, необязательных пакетов и других средств для устранения неполадок или диагностики.
  • Операционная система Windows: один или несколько выпусков Windows, хранящихся в \sources\install.wim
  • Установочный носитель Windows: полная коллекция файлов и папок на установочном носителе Windows. Например, папка \sources, папка \boot, Setup.exe и т. д.

В этой таблице показана правильная последовательность для применения различных задач к файлам. Например, полная последовательность начинается с добавления обновления стека обслуживания в WinRE (1) и завершается добавлением диспетчера загрузки из WinPE на новый носитель (28).

Задача WinRE (winre.wim) Операционная система (install.wim) WinPE (boot.wim) Новый носитель
Добавление динамического обновления стека обслуживания 1 9 17
Добавление языкового пакета 2 10 18
Добавление локализованных необязательных пакетов 3 19
Добавление поддержки шрифтов 4 20
Добавление преобразования текста в речь 5 21
Обновление Lang.ini 22
Добавление функций по запросу 11
Добавление безопасного динамического обновления ОС 6
Добавление динамического обновления установки 26
Добавление setup.exe из WinPE 27
Добавление диспетчера загрузки из WinPE 28
Добавление последнего накопительного обновления 12 23
Очистка изображения 7 13 24
Добавление необязательных компонентов 14
Добавление накопительных обновлений .NET и .NET 15
Экспорт изображения 8 16 25

Примечание.

Начиная с февраля 2021 г. последнее накопительное обновление и обновление стека обслуживания будет объединено и распространено в каталоге Центра обновления Майкрософт в качестве нового объединенного накопительного обновления. Для шагов 1, 9 и 18, требующих обновления стека обслуживания для обновления установочного носителя, следует использовать объединенное накопительное обновление. Дополнительные сведения о объединенном накопительном обновлении см. в разделе Обновления стека обслуживания.

Примечание.

Корпорация Майкрософт удалит компонент Flash из Windows через KB4577586 "Обновление для удаления Adobe Flash Player". Вы также можете удалить Flash в любое время, развернув обновление в KB4577586 (доступно в каталоге) между шагами 20 и 21. С июля 2021 г. KB4577586 в последнее накопительное обновление для Windows 10 версий 1607 и 1507 будет включено "Обновление для удаления Adobe Flash Player". Обновление также будет включено в ежемесячный накопительный пакет и обновление только для системы безопасности для Windows 8.1, Windows Server 2012 и Windows Embedded 8 Standard. Дополнительные сведения см. в разделе Обновление окончания поддержки Adobe Flash Player.

Несколько выпусков Windows

Основной файл операционной системы (install.wim) может содержать несколько выпусков Windows. Возможно, для его развертывания на основе индекса требуется только обновление для определенного выпуска. Или может потребоваться обновление для всех выпусков. Кроме того, убедитесь, что языки установлены перед компонентом по запросу, а последнее накопительное обновление всегда применяется последним.

Дополнительные языки и функции

Вам не нужно добавлять в образ дополнительные языки и функции, чтобы выполнить обновления, но это возможность настроить образ с дополнительными языками, дополнительными компонентами и функциями по запросу, помимо того, что находится в начальном образе. При добавлении дополнительных языков и функций важно внести эти изменения в правильном порядке: сначала применить обновления стека обслуживания, а затем добавить язык, затем добавить компоненты и, наконец, последнее накопительное обновление. Предоставленный пример скрипта устанавливает второй язык (в данном случае японский (ja-JP)). Так как этот язык поддерживается lp.cab, добавлять языковой пакет не требуется. Японский язык добавляется как в основную операционную систему, так и в среду восстановления, чтобы позволить пользователю просматривать экраны восстановления на японском языке. Сюда входит добавление локализованных версий пакетов, установленных в данный момент в образе восстановления.

Необязательные компоненты вместе с функцией .NET можно установить в автономном режиме, однако при этом создаются ожидающие операции, требующие перезапуска устройства. В результате вызов для очистки образа завершится ошибкой. Существует два способа избежать сбоя очистки. Один из вариантов — пропустить шаг очистки образа, хотя это приводит к большему размеру install.wim. Другой вариант — установить .NET и необязательные компоненты на шаге после очистки, но перед экспортом. Это параметр в примере скрипта. Это позволит вам начать с исходного файла install.wim (без ожидающих действий) при следующем обслуживании или обновлении образа (например, в следующем месяце).

Накопительные обновления контрольных точек

Начиная с Windows 11 версии 24H2 последнее накопительное обновление может иметь накопительное обновление, необходимое для установки в первую очередь. Они называются накопительными обновлениями контрольных точек. В этих случаях различия на уровне файлов накопительного обновления основаны на предыдущем накопительном обновлении, а не на выпуске Windows RTM. Преимущество заключается в меньшем пакете обновления и более быстрой установке. При получении последнего накопительного обновления из каталога Центра обновления Майкрософт накопительные обновления контрольных точек будут доступны с кнопки скачивания. Кроме того, дополнительные сведения содержатся в статье базы знаний для накопительного обновления.

Чтобы установить контрольные точки при обслуживании ОС Windows (шаги 9 & 12) и WinPE (шаги 17 & 23), вызовите Add-WindowsPackage целевое накопительное обновление. Папка из -PackagePath будет использоваться для обнаружения и установки одной или нескольких контрольных точек при необходимости. В папке должны находиться только целевые накопительные обновления и накопительные обновления контрольных -PackagePath точек. Пакеты накопительного обновления с редакцией <= целевое накопительное обновление будет обработано. Если вы не настраиваете образ с дополнительными языками и (или) дополнительными функциями, то для шагов 9 & 17 выше можно использовать отдельные вызовы ( Add-WindowsPackage сначала накопительные обновления контрольных точек). Отдельные вызовы нельзя использовать для шагов 12 и 23.

Скрипты Windows PowerShell для применения динамических обновлений к существующему образу

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

Папка Описание
C:\mediaRefresh Родительская папка, содержащая скрипт PowerShell
C:\mediaRefresh\oldMedia Папка, содержащая исходный носитель, который будет обновлен. Например, содержит Setup.exe и папку \sources.
C:\mediaRefresh\newMedia Папка, которая будет содержать обновленный носитель. Он копируется из \oldMedia, а затем используется в качестве целевого объекта для всех операций обновления и очистки.

Get started

Скрипт начинается с объявления глобальных переменных и создания папок для подключения образов. Затем создайте копию исходного носителя из \oldMedia в \newMedia, сохраняя исходный носитель на случай ошибки скрипта и необходимо начать с известного состояния. Кроме того, он предоставляет сравнение старых и новых носителей для оценки изменений. Чтобы убедиться, что новые обновления мультимедиа не доступны только для чтения.

#Requires -RunAsAdministrator

function Get-TS { return "{0:HH:mm:ss}" -f [DateTime]::Now }

Write-Output "$(Get-TS): Starting media refresh"

# Declare language for showcasing adding optional localized components
$LANG  = "ja-jp"
$LANG_FONT_CAPABILITY = "jpan"

# Declare media for FOD and LPs
# Note: Starting with Windows 11, version 21H2, the language pack (LANGPACK) ISO has been superseded by the FOD ISO.
# Language packs and the \Windows Preinstallation Environment packages are part of the LOF ISO.
# If you are using this script for Windows 10, modify to mount and use the LANGPACK ISO.
$FOD_ISO_PATH    = "C:\mediaRefresh\packages\FOD-PACKAGES_OEM_PT1_amd64fre_MULTI.iso"

# Declare Dynamic Update packages. A dedicated folder is used for the latest cumulative update, and as needed
# checkpoint cumulative updates.
$LCU_PATH        = "C:\mediaRefresh\packages\CU\LCU.msu"
$SSU_PATH        = "C:\mediaRefresh\packages\Other\SSU_DU.msu"
$SETUP_DU_PATH   = "C:\mediaRefresh\packages\Other\Setup_DU.cab"
$SAFE_OS_DU_PATH = "C:\mediaRefresh\packages\Other\SafeOS_DU.cab"
$DOTNET_CU_PATH  = "C:\mediaRefresh\packages\Other\DotNet_CU.msu"

# Declare folders for mounted images and temp files
$MEDIA_OLD_PATH  = "C:\mediaRefresh\oldMedia"
$MEDIA_NEW_PATH  = "C:\mediaRefresh\newMedia"
$WORKING_PATH    = "C:\mediaRefresh\temp"
$MAIN_OS_MOUNT   = "C:\mediaRefresh\temp\MainOSMount"
$WINRE_MOUNT     = "C:\mediaRefresh\temp\WinREMount"
$WINPE_MOUNT     = "C:\mediaRefresh\temp\WinPEMount"

# Mount the Features on Demand ISO
Write-Output "$(Get-TS): Mounting FOD ISO"
$FOD_ISO_DRIVE_LETTER = (Mount-DiskImage -ImagePath $FOD_ISO_PATH -ErrorAction stop | Get-Volume).DriveLetter

# Note: Starting with Windows 11, version 21H2, the correct path for main OS language and optional features
# moved to \LanguagesAndOptionalFeatures instead of the root. For Windows 10, use $FOD_PATH = $FOD_ISO_DRIVE_LETTER + ":\"
$FOD_PATH = $FOD_ISO_DRIVE_LETTER + ":\LanguagesAndOptionalFeatures"

# Declare language related cabs
$WINPE_OC_PATH              = "$FOD_ISO_DRIVE_LETTER`:\Windows Preinstallation Environment\x64\WinPE_OCs"
$WINPE_OC_LANG_PATH         = "$WINPE_OC_PATH\$LANG"
$WINPE_OC_LANG_CABS         = Get-ChildItem $WINPE_OC_LANG_PATH -Name
$WINPE_OC_LP_PATH           = "$WINPE_OC_LANG_PATH\lp.cab"
$WINPE_FONT_SUPPORT_PATH    = "$WINPE_OC_PATH\WinPE-FontSupport-$LANG.cab"
$WINPE_SPEECH_TTS_PATH      = "$WINPE_OC_PATH\WinPE-Speech-TTS.cab"
$WINPE_SPEECH_TTS_LANG_PATH = "$WINPE_OC_PATH\WinPE-Speech-TTS-$LANG.cab"
$OS_LP_PATH                 = "$FOD_PATH\Microsoft-Windows-Client-Language-Pack_x64_$LANG.cab"

# Create folders for mounting images and storing temporary files
New-Item -ItemType directory -Path $WORKING_PATH -ErrorAction Stop | Out-Null
New-Item -ItemType directory -Path $MAIN_OS_MOUNT -ErrorAction stop | Out-Null
New-Item -ItemType directory -Path $WINRE_MOUNT -ErrorAction stop | Out-Null
New-Item -ItemType directory -Path $WINPE_MOUNT -ErrorAction stop | Out-Null

# Keep the original media, make a copy of it for the new, updated media.
Write-Output "$(Get-TS): Copying original media to new media path"
Copy-Item -Path $MEDIA_OLD_PATH"\*" -Destination $MEDIA_NEW_PATH -Force -Recurse -ErrorAction stop | Out-Null
Get-ChildItem -Path $MEDIA_NEW_PATH -Recurse | Where-Object { -not $_.PSIsContainer -and $_.IsReadOnly } | ForEach-Object { $_.IsReadOnly = $false }

Обновление WinRE и каждого основного выпуска ОС Windows

Скрипт обновит каждый выпуск Windows в главном файле операционной системы (install.wim). Для каждого выпуска подключается основной образ ОС.

Для первого образа Winre.wim копируется в рабочую папку и подключается. Затем применяется динамическое обновление стека обслуживания, так как его компоненты используются для обновления других компонентов. Так как скрипт при необходимости добавляет японский язык, он добавляет языковой пакет в образ и устанавливает японские версии всех дополнительных пакетов, уже установленных в Winre.wim. Затем применяется пакет динамического обновления безопасной ОС. Она завершается очисткой и экспортом образа, чтобы уменьшить размер изображения.

Затем для подключенного образа ОС скрипт запускается с применением динамического обновления стека обслуживания. Затем добавляется поддержка японского языка, а затем функции японского языка. В отличие от пакетов динамического обновления, он использует для Add-WindowsCapability добавления этих функций. Полный список таких функций и связанные с ними имена возможностей см. в разделе Доступные функции по запросу. Настало время включить другие необязательные компоненты или добавить другие функции по запросу. Если с такой функцией связано накопительное обновление (например, .NET), это время для его применения. Затем скрипт продолжает применять последнее накопительное обновление. Наконец, скрипт очищает и экспортирует образ. Необязательные компоненты вместе с функцией .NET можно установить в автономном режиме, но для этого требуется перезапустить устройство. Именно поэтому скрипт устанавливает .NET и необязательные компоненты после очистки и перед экспортом.

Этот процесс повторяется для каждого выпуска Windows в главном файле операционной системы. Чтобы уменьшить размер, файл Winre.wim с первого образа сохраняется и используется для обновления каждого последующего выпуска Windows. Это уменьшает окончательный размер install.wim.

#
# Update each main OS Windows image including the Windows Recovery Environment (WinRE)
#

# Get the list of images contained within the main OS
$WINOS_IMAGES = Get-WindowsImage -ImagePath $MEDIA_NEW_PATH"\sources\install.wim"

Foreach ($IMAGE in $WINOS_IMAGES) {

    # first mount the main OS image
    Write-Output "$(Get-TS): Mounting main OS, image index $($IMAGE.ImageIndex)"
    Mount-WindowsImage -ImagePath $MEDIA_NEW_PATH"\sources\install.wim" -Index $IMAGE.ImageIndex -Path $MAIN_OS_MOUNT -ErrorAction stop| Out-Null

    if ($IMAGE.ImageIndex -eq "1") {

        #
        # update Windows Recovery Environment (WinRE) within this OS image
        #
        Copy-Item -Path $MAIN_OS_MOUNT"\windows\system32\recovery\winre.wim" -Destination $WORKING_PATH"\winre.wim" -Force -ErrorAction stop | Out-Null
        Write-Output "$(Get-TS): Mounting WinRE"
        Mount-WindowsImage -ImagePath $WORKING_PATH"\winre.wim" -Index 1 -Path $WINRE_MOUNT -ErrorAction stop | Out-Null

        # Add servicing stack update (Step 1 from the table)

        # Depending on the Windows release that you are updating, there are 2 different approaches for updating the servicing stack
        # The first approach is to use the combined cumulative update. This is for Windows releases that are shipping a combined 
        # cumulative update that includes the servicing stack updates (i.e. SSU + LCU are combined). Windows 11, version 21H2 and 
        # Windows 11, version 22H2 are examples. In these cases, the servicing stack update is not published seperately; the combined 
        # cumulative update should be used for this step. However, in hopefully rare cases, there may breaking change in the combined 
        # cumulative update format, that requires a standalone servicing stack update to be published, and installed first before the 
        # combined cumulative update can be installed.

        # This is the code to handle the rare case that the SSU is published and required for the combined cumulative update
        # Write-Output "$(Get-TS): Adding package $SSU_PATH"
        # Add-WindowsPackage -Path $WINRE_MOUNT -PackagePath $SSU_PATH | Out-Null

        # Now, attempt the combined cumulative update.
        # There is a known issue where the servicing stack update is installed, but the cumulative update will fail. This error should 
        # be caught and ignored, as the last step will be to apply the Safe OS update and thus the image will be left with the correct 
        # packages installed.

        
        Write-Output "$(Get-TS): Adding package $LCU_PATH to WinRE"        
        try
        {
            
            Add-WindowsPackage -Path $WINRE_MOUNT -PackagePath $LCU_PATH | Out-Null  
        }
        Catch
        {
            $theError = $_
            Write-Output "$(Get-TS): $theError"
    
            if ($theError.Exception -like "*0x8007007e*") {
                Write-Output "$(Get-TS): This failure is a known issue with combined cumulative update, we can ignore."
            }
            else {
                throw
            }
        }

        # The second approach for Step 1 is for Windows releases that have not adopted the combined cumulative update
        # but instead continue to have a seperate servicing stack update published. In this case, we'll install the SSU
        # update. This second approach is commented out below.

        # Write-Output "$(Get-TS): Adding package $SSU_PATH"
        # Add-WindowsPackage -Path $WINRE_MOUNT -PackagePath $SSU_PATH | Out-Null

        #
        # Optional: Add the language to recovery environment
        #
        # Install lp.cab cab
        Write-Output "$(Get-TS): Adding package $WINPE_OC_LP_PATH to WinRE"
        Add-WindowsPackage -Path $WINRE_MOUNT -PackagePath $WINPE_OC_LP_PATH -ErrorAction stop | Out-Null

        # Install language cabs for each optional package installed
        $WINRE_INSTALLED_OC = Get-WindowsPackage -Path $WINRE_MOUNT
        Foreach ($PACKAGE in $WINRE_INSTALLED_OC) {

            if ( ($PACKAGE.PackageState -eq "Installed") -and ($PACKAGE.PackageName.startsWith("WinPE-")) -and ($PACKAGE.ReleaseType -eq "FeaturePack") ) {

                $INDEX = $PACKAGE.PackageName.IndexOf("-Package")
                if ($INDEX -ge 0) {
                    $OC_CAB = $PACKAGE.PackageName.Substring(0, $INDEX) + "_" + $LANG + ".cab"
                    if ($WINPE_OC_LANG_CABS.Contains($OC_CAB)) {
                        $OC_CAB_PATH = Join-Path $WINPE_OC_LANG_PATH $OC_CAB
                        Write-Output "$(Get-TS): Adding package $OC_CAB_PATH to WinRE"
                        Add-WindowsPackage -Path $WINRE_MOUNT -PackagePath $OC_CAB_PATH -ErrorAction stop | Out-Null  
                    }
                }
            }
        }

        # Add font support for the new language
        if ( (Test-Path -Path $WINPE_FONT_SUPPORT_PATH) ) {
            Write-Output "$(Get-TS): Adding package $WINPE_FONT_SUPPORT_PATH to WinRE"
            Add-WindowsPackage -Path $WINRE_MOUNT -PackagePath $WINPE_FONT_SUPPORT_PATH -ErrorAction stop | Out-Null
        }

        # Add TTS support for the new language
        if (Test-Path -Path $WINPE_SPEECH_TTS_PATH) {
            if ( (Test-Path -Path $WINPE_SPEECH_TTS_LANG_PATH) ) {

                Write-Output "$(Get-TS): Adding package $WINPE_SPEECH_TTS_PATH to WinRE"
                Add-WindowsPackage -Path $WINRE_MOUNT -PackagePath $WINPE_SPEECH_TTS_PATH -ErrorAction stop | Out-Null

                Write-Output "$(Get-TS): Adding package $WINPE_SPEECH_TTS_LANG_PATH to WinRE"
                Add-WindowsPackage -Path $WINRE_MOUNT -PackagePath $WINPE_SPEECH_TTS_LANG_PATH -ErrorAction stop | Out-Null
            }
        }

        # Add Safe OS
        Write-Output "$(Get-TS): Adding package $SAFE_OS_DU_PATH to WinRE"
        Add-WindowsPackage -Path $WINRE_MOUNT -PackagePath $SAFE_OS_DU_PATH -ErrorAction stop | Out-Null

        # Perform image cleanup
        Write-Output "$(Get-TS): Performing image cleanup on WinRE"
        DISM /image:$WINRE_MOUNT /cleanup-image /StartComponentCleanup /ResetBase /Defer | Out-Null

        # Dismount
        Dismount-WindowsImage -Path $WINRE_MOUNT  -Save -ErrorAction stop | Out-Null

        # Export
        Write-Output "$(Get-TS): Exporting image to $WORKING_PATH\winre.wim"
        Export-WindowsImage -SourceImagePath $WORKING_PATH"\winre.wim" -SourceIndex 1 -DestinationImagePath $WORKING_PATH"\winre2.wim" -ErrorAction stop | Out-Null

    }
    
    Copy-Item -Path $WORKING_PATH"\winre2.wim" -Destination $MAIN_OS_MOUNT"\windows\system32\recovery\winre.wim" -Force -ErrorAction stop | Out-Null
    
    #
    # update Main OS
    #

    # Add servicing stack update (Step 18 from the table)

    # Depending on the Windows release that you are updating, there are 2 different approaches for updating the servicing stack
    # The first approach is to use the combined cumulative update. This is for Windows releases that are shipping a combined cumulative update that
    # includes the servicing stack updates (i.e. SSU + LCU are combined). Windows 11, version 21H2 and Windows 11, version 22H2 are examples. In these
    # cases, the servicing stack update is not published seperately; the combined cumulative update should be used for this step. However, in hopefully
    # rare cases, there may breaking change in the combined cumulative update format, that requires a standalone servicing stack update to be published, 
    # and installed first before the combined cumulative update can be installed.

    # This is the code to handle the rare case that the SSU is published and required for the combined cumulative update
    # Write-Output "$(Get-TS): Adding package $SSU_PATH"
    # Add-WindowsPackage -Path $MAIN_OS_MOUNT -PackagePath $SSU_PATH | Out-Null

    # Now, attempt the combined cumulative update. Unlike WinRE and WinPE, we don't need to check for error 0x8007007e
    Write-Output "$(Get-TS): Adding package $LCU_PATH to main OS, index $($IMAGE.ImageIndex)"
    Add-WindowsPackage -Path $MAIN_OS_MOUNT -PackagePath $LCU_PATH | Out-Null

    # The second approach for Step 18 is for Windows releases that have not adopted the combined cumulative update
    # but instead continue to have a seperate servicing stack update published. In this case, we'll install the SSU
    # update. This second approach is commented out below.

    # Write-Output "$(Get-TS): Adding package $SSU_PATH to main OS, index $($IMAGE.ImageIndex)"
    # Add-WindowsPackage -Path $MAIN_OS_MOUNT -PackagePath $SSU_PATH | Out-Null

    # Optional: Add language to main OS
    Write-Output "$(Get-TS): Adding package $OS_LP_PATH to main OS, index $($IMAGE.ImageIndex)"
    Add-WindowsPackage -Path $MAIN_OS_MOUNT -PackagePath $OS_LP_PATH -ErrorAction stop | Out-Null

    # Optional: Add a Features on Demand to the image
    Write-Output "$(Get-TS): Adding language FOD: Language.Fonts.Jpan~~~und-JPAN~0.0.1.0 to main OS, index $($IMAGE.ImageIndex)"
    Add-WindowsCapability -Name "Language.Fonts.$LANG_FONT_CAPABILITY~~~und-$LANG_FONT_CAPABILITY~0.0.1.0" -Path $MAIN_OS_MOUNT -Source $FOD_PATH -ErrorAction stop | Out-Null

    Write-Output "$(Get-TS): Adding language FOD: Language.Basic~~~$LANG~0.0.1.0 to main OS, index $($IMAGE.ImageIndex)"
    Add-WindowsCapability -Name "Language.Basic~~~$LANG~0.0.1.0" -Path $MAIN_OS_MOUNT -Source $FOD_PATH -ErrorAction stop | Out-Null

    Write-Output "$(Get-TS): Adding language FOD: Language.OCR~~~$LANG~0.0.1.0 to main OS, index $($IMAGE.ImageIndex)"
    Add-WindowsCapability -Name "Language.OCR~~~$LANG~0.0.1.0" -Path $MAIN_OS_MOUNT -Source $FOD_PATH -ErrorAction stop | Out-Null

    Write-Output "$(Get-TS): Adding language FOD: Language.Handwriting~~~$LANG~0.0.1.0 to main OS, index $($IMAGE.ImageIndex)"
    Add-WindowsCapability -Name "Language.Handwriting~~~$LANG~0.0.1.0" -Path $MAIN_OS_MOUNT -Source $FOD_PATH -ErrorAction stop | Out-Null

    Write-Output "$(Get-TS): Adding language FOD: Language.TextToSpeech~~~$LANG~0.0.1.0 to main OS, index $($IMAGE.ImageIndex)"
    Add-WindowsCapability -Name "Language.TextToSpeech~~~$LANG~0.0.1.0" -Path $MAIN_OS_MOUNT -Source $FOD_PATH -ErrorAction stop | Out-Null

    Write-Output "$(Get-TS): Adding language FOD: Language.Speech~~~$LANG~0.0.1.0 to main OS, index $($IMAGE.ImageIndex)"
    Add-WindowsCapability -Name "Language.Speech~~~$LANG~0.0.1.0" -Path $MAIN_OS_MOUNT -Source $FOD_PATH -ErrorAction stop | Out-Null

    # Note: If I wanted to enable additional Features on Demand, I'd add these here.

    # Add latest cumulative update
    Write-Output "$(Get-TS): Adding package $LCU_PATH to main OS, index $($IMAGE.ImageIndex)"
    Add-WindowsPackage -Path $MAIN_OS_MOUNT -PackagePath $LCU_PATH -ErrorAction stop | Out-Null

    # Perform image cleanup
    Write-Output "$(Get-TS): Performing image cleanup on main OS, index $($IMAGE.ImageIndex)"
    DISM /image:$MAIN_OS_MOUNT /cleanup-image /StartComponentCleanup | Out-Null

    #
    # Note: If I wanted to enable additional Optional Components, I'd add these here.
    # In addition, we'll add .NET 3.5 here as well. Both .NET and Optional Components might require
    # the image to be booted, and thus if we tried to cleanup after installation, it would fail.
    #

    Write-Output "$(Get-TS): Adding NetFX3~~~~ to main OS, index $($IMAGE.ImageIndex)"
    Add-WindowsCapability -Name "NetFX3~~~~" -Path $MAIN_OS_MOUNT -Source $FOD_PATH -ErrorAction stop | Out-Null

    # Add .NET Cumulative Update
    Write-Output "$(Get-TS): Adding package $DOTNET_CU_PATH to main OS, index $($IMAGE.ImageIndex)"
    Add-WindowsPackage -Path $MAIN_OS_MOUNT -PackagePath $DOTNET_CU_PATH -ErrorAction stop | Out-Null

    # Dismount
    Dismount-WindowsImage -Path $MAIN_OS_MOUNT -Save -ErrorAction stop | Out-Null

    # Export
    Write-Output "$(Get-TS): Exporting image to $WORKING_PATH\install2.wim"
    Export-WindowsImage -SourceImagePath $MEDIA_NEW_PATH"\sources\install.wim" -SourceIndex $IMAGE.ImageIndex -DestinationImagePath $WORKING_PATH"\install2.wim" -ErrorAction stop | Out-Null

}

Move-Item -Path $WORKING_PATH"\install2.wim" -Destination $MEDIA_NEW_PATH"\sources\install.wim" -Force -ErrorAction stop | Out-Null

Обновление WinPE

Этот скрипт аналогичен тому, который обновляет WinRE, но вместо этого он подключает Boot.wim, применяет пакеты с последним накопительным обновлением и сохраняет. Он повторяет это для всех образов внутри Boot.wim, обычно двух образов. Он начинается с применения динамического обновления стека обслуживания. Так как скрипт настраивает этот носитель на японском языке, он устанавливает языковой пакет из папки WinPE в ISO-файле языкового пакета. Кроме того, он добавляет поддержку шрифтов и текста в речь (TTS). Так как скрипт добавляет новый язык, он перестраивает lang.ini, используемый для идентификации языков, установленных в образе. Для второго образа мы сохраним setup.exe для последующего использования, чтобы убедиться, что эта версия соответствует версии \sources\setup.exe с установочного носителя. Если эти двоичные файлы не идентичны, программа установки Windows завершится ошибкой во время установки. Мы также сохраним обслуживаемые файлы диспетчера загрузки для последующего использования в скрипте. Наконец, скрипт очищает и экспортирует Boot.wim и копирует его обратно на новый носитель.

#
# update Windows Preinstallation Environment (WinPE)
#

# Get the list of images contained within WinPE
$WINPE_IMAGES = Get-WindowsImage -ImagePath $MEDIA_NEW_PATH"\sources\boot.wim"

Foreach ($IMAGE in $WINPE_IMAGES) {

    # update WinPE
    Write-Output "$(Get-TS): Mounting WinPE, image index $($IMAGE.ImageIndex)"
    Mount-WindowsImage -ImagePath $MEDIA_NEW_PATH"\sources\boot.wim" -Index $IMAGE.ImageIndex -Path $WINPE_MOUNT -ErrorAction stop | Out-Null

    # Add servicing stack update (Step 9 from the table)

    # Depending on the Windows release that you are updating, there are 2 different approaches for updating the servicing stack
    # The first approach is to use the combined cumulative update. This is for Windows releases that are shipping a combined 
    # cumulative update that includes the servicing stack updates (i.e. SSU + LCU are combined). Windows 11, version 21H2 and 
    # Windows 11, version 22H2 are examples. In these cases, the servicing stack update is not published separately; the combined 
    # cumulative update should be used for this step. However, in hopefully rare cases, there may breaking change in the combined 
    # cumulative update format, that requires a standalone servicing stack update to be published, and installed first before the 
    # combined cumulative update can be installed.

    # This is the code to handle the rare case that the SSU is published and required for the combined cumulative update
    # Write-Output "$(Get-TS): Adding package $SSU_PATH"
    # Add-WindowsPackage -Path $WINPE_MOUNT -PackagePath $SSU_PATH | Out-Null

    # Now, attempt the combined cumulative update.
    # There is a known issue where the servicing stack update is installed, but the cumulative update will fail.
    # This error should be caught and ignored, as the last step will be to apply the cumulative update 
    # (or in this case the combined cumulative update) and thus the image will be left with the correct packages installed.

    try
    {
        Write-Output "$(Get-TS): Adding package $LCU_PATH to WinPE, image index $($IMAGE.ImageIndex)"
        Add-WindowsPackage -Path $WINPE_MOUNT -PackagePath $LCU_PATH | Out-Null  
    }
    Catch
    {
        $theError = $_
        Write-Output "$(Get-TS): $theError"

        if ($theError.Exception -like "*0x8007007e*") {
            Write-Output "$(Get-TS): This failure is a known issue with combined cumulative update, we can ignore."
        }
        else {
            throw
        }
    }

    # The second approach for Step 9 is for Windows releases that have not adopted the combined cumulative update
    # but instead continue to have a separate servicing stack update published. In this case, we'll install the SSU
    # update. This second approach is commented out below.

    # Write-Output "$(Get-TS): Adding package $SSU_PATH"
    # Add-WindowsPackage -Path $WINPE_MOUNT -PackagePath $SSU_PATH | Out-Null

    # Install lp.cab cab
    Write-Output "$(Get-TS): Adding package $WINPE_OC_LP_PATH to WinPE, image index $($IMAGE.ImageIndex)"
    Add-WindowsPackage -Path $WINPE_MOUNT -PackagePath $WINPE_OC_LP_PATH -ErrorAction stop | Out-Null

    # Install language cabs for each optional package installed
    $WINPE_INSTALLED_OC = Get-WindowsPackage -Path $WINPE_MOUNT
    Foreach ($PACKAGE in $WINPE_INSTALLED_OC) {

        if ( ($PACKAGE.PackageState -eq "Installed") -and ($PACKAGE.PackageName.startsWith("WinPE-")) -and ($PACKAGE.ReleaseType -eq "FeaturePack") ) {

            $INDEX = $PACKAGE.PackageName.IndexOf("-Package")
            if ($INDEX -ge 0) {

                $OC_CAB = $PACKAGE.PackageName.Substring(0, $INDEX) + "_" + $LANG + ".cab"
                if ($WINPE_OC_LANG_CABS.Contains($OC_CAB)) {
                    $OC_CAB_PATH = Join-Path $WINPE_OC_LANG_PATH $OC_CAB
                    Write-Output "$(Get-TS): Adding package $OC_CAB_PATH to WinPE, image index $($IMAGE.ImageIndex)"
                    Add-WindowsPackage -Path $WINPE_MOUNT -PackagePath $OC_CAB_PATH -ErrorAction stop | Out-Null  
                }
            }
        }
    }

    # Add font support for the new language
    if ( (Test-Path -Path $WINPE_FONT_SUPPORT_PATH) ) {
        Write-Output "$(Get-TS): Adding package $WINPE_FONT_SUPPORT_PATH to WinPE, image index $($IMAGE.ImageIndex)"
        Add-WindowsPackage -Path $WINPE_MOUNT -PackagePath $WINPE_FONT_SUPPORT_PATH -ErrorAction stop | Out-Null
    }

    # Add TTS support for the new language
    if (Test-Path -Path $WINPE_SPEECH_TTS_PATH) {
        if ( (Test-Path -Path $WINPE_SPEECH_TTS_LANG_PATH) ) {

            Write-Output "$(Get-TS): Adding package $WINPE_SPEECH_TTS_PATH to WinPE, image index $($IMAGE.ImageIndex)"
            Add-WindowsPackage -Path $WINPE_MOUNT -PackagePath $WINPE_SPEECH_TTS_PATH -ErrorAction stop | Out-Null

            Write-Output "$(Get-TS): Adding package $WINPE_SPEECH_TTS_LANG_PATH to WinPE, image index $($IMAGE.ImageIndex)"
            Add-WindowsPackage -Path $WINPE_MOUNT -PackagePath $WINPE_SPEECH_TTS_LANG_PATH -ErrorAction stop | Out-Null
        }
    }

    # Generates a new Lang.ini file which is used to define the language packs inside the image
    if ( (Test-Path -Path $WINPE_MOUNT"\sources\lang.ini") ) {
        Write-Output "$(Get-TS): Updating lang.ini"
        DISM /image:$WINPE_MOUNT /Gen-LangINI /distribution:$WINPE_MOUNT | Out-Null
    }

    # Add latest cumulative update
    Write-Output "$(Get-TS): Adding package $LCU_PATH to WinPE, image index $($IMAGE.ImageIndex)"
    Add-WindowsPackage -Path $WINPE_MOUNT -PackagePath $LCU_PATH -ErrorAction stop | Out-Null

    # Perform image cleanup
    Write-Output "$(Get-TS): Performing image cleanup on WinPE, image index $($IMAGE.ImageIndex)"
    DISM /image:$WINPE_MOUNT /cleanup-image /StartComponentCleanup /ResetBase /Defer | Out-Null

    if ($IMAGE.ImageIndex -eq "2") {

        # Save setup.exe for later use. This will address possible binary mismatch with the version in the main OS \sources folder
        Copy-Item -Path $WINPE_MOUNT"\sources\setup.exe" -Destination $WORKING_PATH"\setup.exe" -Force -ErrorAction stop | Out-Null
        
        # Save setuphost.exe for later use. This will address possible binary mismatch with the version in the main OS \sources folder
        # This is only required starting with Windows 11 version 24H2
        $TEMP = Get-WindowsImage -ImagePath $MEDIA_NEW_PATH"\sources\boot.wim" -Index $IMAGE.ImageIndex
        if ([System.Version]$TEMP.Version -ge [System.Version]"10.0.26100") {
            
            Copy-Item -Path $WINPE_MOUNT"\sources\setuphost.exe" -Destination $WORKING_PATH"\setuphost.exe" -Force -ErrorAction stop | Out-Null
        }
        else {

            Write-Output "$(Get-TS): Skipping copy of setuphost.exe; image version $($TEMP.Version)"
        }
        
        # Save serviced boot manager files later copy to the root media.
        Copy-Item -Path $WINPE_MOUNT"\Windows\boot\efi\bootmgfw.efi" -Destination $WORKING_PATH"\bootmgfw.efi" -Force -ErrorAction stop | Out-Null
        Copy-Item -Path $WINPE_MOUNT"\Windows\boot\efi\bootmgr.efi" -Destination $WORKING_PATH"\bootmgr.efi" -Force -ErrorAction stop | Out-Null
    
    }
        
    # Dismount
    Dismount-WindowsImage -Path $WINPE_MOUNT -Save -ErrorAction stop | Out-Null

    #Export WinPE
    Write-Output "$(Get-TS): Exporting image to $WORKING_PATH\boot2.wim"
    Export-WindowsImage -SourceImagePath $MEDIA_NEW_PATH"\sources\boot.wim" -SourceIndex $IMAGE.ImageIndex -DestinationImagePath $WORKING_PATH"\boot2.wim" -ErrorAction stop | Out-Null

}

Move-Item -Path $WORKING_PATH"\boot2.wim" -Destination $MEDIA_NEW_PATH"\sources\boot.wim" -Force -ErrorAction stop | Out-Null

Обновление оставшихся файлов мультимедиа

Эта часть скрипта обновляет файлы установки. Он просто копирует отдельные файлы из пакета динамического обновления установки на новый носитель. На этом шаге по мере необходимости будут добавлены обновленные файлы установки, а также последняя база данных совместимости и манифесты компонентов замены. Этот скрипт также выполняет окончательную замену файлов setup.exe и диспетчера загрузки с использованием ранее сохраненных версий из WinPE.

#
# update remaining files on media
#

# Add Setup DU by copy the files from the package into the newMedia
Write-Output "$(Get-TS): Adding package $SETUP_DU_PATH"
cmd.exe /c $env:SystemRoot\System32\expand.exe $SETUP_DU_PATH -F:* $MEDIA_NEW_PATH"\sources" | Out-Null

# Copy setup.exe from boot.wim, saved earlier.
Write-Output "$(Get-TS): Copying $WORKING_PATH\setup.exe to $MEDIA_NEW_PATH\sources\setup.exe"
Copy-Item -Path $WORKING_PATH"\setup.exe" -Destination $MEDIA_NEW_PATH"\sources\setup.exe" -Force -ErrorAction stop | Out-Null

# Copy setuphost.exe from boot.wim, saved earlier.
if (Test-Path -Path $WORKING_PATH"\setuphost.exe") {

    Write-Output "$(Get-TS): Copying $WORKING_PATH\setuphost.exe to $MEDIA_NEW_PATH\sources\setuphost.exe"
    Copy-Item -Path $WORKING_PATH"\setuphost.exe" -Destination $MEDIA_NEW_PATH"\sources\setuphost.exe" -Force -ErrorAction stop | Out-Null
}

# Copy bootmgr files from boot.wim, saved earlier.
$MEDIA_NEW_FILES = Get-ChildItem $MEDIA_NEW_PATH -Force -Recurse -Filter b*.efi

Foreach ($File in $MEDIA_NEW_FILES){
    if (($File.Name -ieq "bootmgfw.efi") -or ($File.Name -ieq "bootx64.efi") -or ($File.Name -ieq "bootia32.efi") -or ($File.Name -ieq "bootaa64.efi")) 
    {

        Write-Output "$(Get-TS): Copying $WORKING_PATH\bootmgfw.efi to $($File.FullName)"
        Copy-Item -Path $WORKING_PATH"\bootmgfw.efi" -Destination $File.FullName -Force -ErrorAction stop | Out-Null
    }
    elseif ($File.Name -ieq "bootmgr.efi") 
    {

        Write-Output "$(Get-TS): Copying $WORKING_PATH\bootmgr.efi to $($File.FullName)"
        Copy-Item -Path $WORKING_PATH"\bootmgr.efi" -Destination $File.FullName -Force -ErrorAction stop | Out-Null
    }
}

Завершить

В качестве последнего шага скрипт удаляет рабочую папку временных файлов и отключает наш языковой пакет и компоненты по запросу ISOS.

#
# Perform final cleanup
#

# Remove our working folder
Remove-Item -Path $WORKING_PATH -Recurse -Force -ErrorAction stop | Out-Null

# Dismount ISO images
Write-Output "$(Get-TS): Dismounting ISO images"
Dismount-DiskImage -ImagePath $FOD_ISO_PATH -ErrorAction stop | Out-Null

Write-Output "$(Get-TS): Media refresh completed!"