Обновление установочного носителя 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

Заголовок может различать каждый динамический пакет. Накопительные обновления имеют встроенный стек обслуживания. Стек обслуживания публикуется только при необходимости для данного накопительного обновления.

Обновление пакетов Title
Безопасное динамическое обновление ОС YYYY-MM Безопасное динамическое обновление ОС для 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, "Обновление для удаления Adobe Flash Player" будет включено в последнее накопительное обновление для Windows 10 версии 1607 и 1507. Обновление также будет включено в ежемесячный накопительный пакет и обновление только для системы безопасности для Windows 8.1, Windows Server 2012 и Windows Embedded 8 Standard. Дополнительные сведения см. в разделе Обновление окончания поддержки Adobe Flash Player.

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

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

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

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

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

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
$LCU_PATH        = "C:\mediaRefresh\packages\LCU.msu"
$SSU_PATH        = "C:\mediaRefresh\packages\SSU_DU.msu"
$SETUP_DU_PATH   = "C:\mediaRefresh\packages\Setup_DU.cab"
$SAFE_OS_DU_PATH = "C:\mediaRefresh\packages\SafeOS_DU.cab"
$DOTNET_CU_PATH  = "C:\mediaRefresh\packages\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 и каждой main ос Windows

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

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

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

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

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

# Get the list of images contained within WinPE
$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.

        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"
        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"
                        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"
            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"
                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"
                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"
        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"
    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"
    # 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"
    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"
    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"
    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"
    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"
    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"
    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"
    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"
    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"
    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~~~~"
    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"
    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
    {
        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"
    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"
                    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"
        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"
            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"
            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"
    Add-WindowsPackage -Path $WINPE_MOUNT -PackagePath $LCU_PATH -ErrorAction stop | Out-Null  

    # Perform image cleanup
    Write-Output "$(Get-TS): Performing image cleanup on WinPE"
    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 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 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!"