Actualización de los medios de instalación de Windows con Dynamic Update

En este artículo se explica cómo adquirir y aplicar paquetes de actualización dinámica a imágenes de Windows existentes antes de la implementación e incluye Windows PowerShell scripts que puede usar para automatizar este proceso.

Los medios con licencia por volumen están disponibles para cada versión de Windows en el Centro de servicios de licencias por volumen (VLSC) y otros canales relevantes, como Windows Update para empresas, Windows Server Update Services (WSUS) y Suscripciones de Visual Studio. Puede usar la actualización dinámica para asegurarse de que los dispositivos Windows tengan los paquetes de actualización de características más recientes como parte de una actualización local, al tiempo que conserva el paquete de idioma y las características a petición (FOD) que podrían haberse instalado anteriormente. La actualización dinámica también elimina la necesidad de instalar una actualización de calidad independiente como parte del proceso de actualización local.

Actualización dinámica

Cada vez que se inicia la instalación de una actualización de características (ya sea desde medios o desde un entorno conectado a Windows Update), actualización dinámica es uno de los primeros pasos. El programa de instalación de Windows se pone en contacto con un punto de conexión de Microsoft para capturar paquetes de actualización dinámica y, a continuación, aplica esas actualizaciones a los medios de instalación del sistema operativo. Los paquetes de actualización incluyen los siguientes tipos de actualizaciones:

  • Novedades para Setup.exe archivos binarios u otros archivos que el programa de instalación usa para las actualizaciones de características
  • Novedades para el "sistema operativo seguro" (SafeOS) que se usa para el entorno de recuperación de Windows
  • Novedades a la pila de mantenimiento necesaria para completar la actualización de características Para obtener más información, consulte Actualizaciones de la pila de mantenimiento.
  • La última actualización acumulativa (de calidad)
  • Novedades a los controladores aplicables ya publicados por fabricantes destinados específicamente a la actualización dinámica

La actualización dinámica conserva el paquete de idioma y los paquetes de características a petición al volver a recuperarlos.

Los dispositivos deben poder conectarse a Internet para obtener Novedades dinámicos. En algunos entornos, no es una opción para obtener Novedades dinámicos. Puede seguir realizando una actualización de características basada en medios adquiriendo paquetes de actualización dinámica y aplicándola a la imagen antes de iniciar el programa de instalación en el dispositivo.

Adquisición de paquetes de actualización dinámica

Puede obtener paquetes de actualización dinámica del catálogo de Microsoft Update. En ese sitio, use la barra de búsqueda de la esquina superior derecha para buscar los paquetes de actualización dinámica de una versión determinada. Es posible que los distintos paquetes de actualización dinámica no estén presentes en los resultados de una sola búsqueda, por lo que es posible que tenga que buscar con diferentes palabras clave para buscar todas las actualizaciones. Compruebe varias partes de los resultados para asegurarse de que ha identificado los archivos necesarios. En las tablas siguientes se muestran los valores de clave que se van a buscar o buscar en los resultados.

Windows 11, paquetes de actualización dinámica de la versión 22H2

Title puede distinguir cada paquete dinámico. Las actualizaciones acumulativas tienen la pila de mantenimiento incrustada. La pila de mantenimiento solo se publica si es necesario para una actualización acumulativa determinada.

Actualizar paquetes Title
Actualización dinámica del sistema operativo seguro Actualización dinámica del sistema operativo seguro AAAA-MM para Windows 11 versión 22H2
Instalación de la actualización dinámica Actualización dinámica de configuración de AAAA-MM para Windows 11 versión 22H2
Actualización acumulativa más reciente Actualización acumulativa de AAAA-MM para Windows 11 versión 22H2
Actualización dinámica de la pila de mantenimiento Actualización de pila de mantenimiento de AAAA-MM para Windows 11 versión 22H2

paquetes de actualización dinámica Windows 11, versión 21H2

El título, el producto y la descripción son necesarios para distinguir cada paquete dinámico. La última actualización acumulativa tiene la pila de mantenimiento incrustada. Pila de mantenimiento publicada por separado solo si es necesario como requisito previo para una actualización acumulativa determinada.

Actualizar paquetes Title Producto Descripción
Actualización dinámica del sistema operativo seguro Actualización dinámica de AAAA-MM para Windows 11 Actualización dinámica del sistema operativo Seguro para Windows ComponentUpdate
Instalación de la actualización dinámica Actualización dinámica de AAAA-MM para Windows 11 Windows 10 y versiones posteriores de actualización dinámica SetupUpdate
Actualización acumulativa más reciente Actualización acumulativa de AAAA-MM para Windows 11
Actualización dinámica de la pila de mantenimiento Actualización de pila de mantenimiento de AAAA-MM para Windows 11 versión 21H2

Para Windows 10, paquetes de actualización dinámica de la versión 22H2

El título, el producto y la descripción son necesarios para distinguir cada paquete dinámico. La última actualización acumulativa tiene la pila de mantenimiento incrustada. Pila de mantenimiento publicada por separado solo si es necesario como requisito previo para una actualización acumulativa determinada.

Actualizar paquetes Title Producto Descripción
Actualización dinámica del sistema operativo seguro Actualización dinámica de AAAA-MM para Windows 10 versión 22H2 Actualización dinámica del sistema operativo Seguro para Windows ComponentUpdate
Instalación de la actualización dinámica Actualización dinámica de AAAA-MM para Windows 10 versión 22H2 Windows 10 y versiones posteriores de actualización dinámica SetupUpdate
Actualización acumulativa más reciente Actualización acumulativa de AAAA-MM para Windows 10 versión 22H2
Actualización dinámica de la pila de mantenimiento Actualización de pila de mantenimiento de AAAA-MM para Windows 10 versión 22H2

Si desea personalizar la imagen con idiomas adicionales o Características a petición, descargue archivos ISO de medios complementarios desde el Centro de servicios de licencias por volumen. Por ejemplo, si la actualización dinámica se deshabilitará para los dispositivos y los usuarios requieren características específicas a petición, puede preinstalarlas en la imagen.

Actualizar los medios de instalación de Windows

Actualizar correctamente los medios de instalación implica un gran número de acciones que funcionan en varios destinos diferentes (archivos de imagen). Algunas acciones se repiten en distintos destinos. Los archivos de imágenes de destino incluyen:

  • Entorno de preinstalación de Windows (WinPE): un pequeño sistema operativo que se usa para instalar, implementar y reparar sistemas operativos Windows
  • Entorno de recuperación de Windows (WinRE): repara las causas comunes de los sistemas operativos que no se pueden iniciar. WinRE se basa en WinPE y se puede personalizar con controladores adicionales, idiomas, paquetes opcionales y otras herramientas de solución de problemas o diagnóstico.
  • Sistema operativo Windows: una o varias ediciones de Windows almacenadas en \sources\install.wim
  • Medios de instalación de Windows: la colección completa de archivos y carpetas en los medios de instalación de Windows. Por ejemplo, carpeta \sources, carpeta \boot, Setup.exe, etc.

En esta tabla se muestra la secuencia correcta para aplicar las distintas tareas a los archivos. Por ejemplo, la secuencia completa comienza con la adición de la actualización de la pila de mantenimiento a WinRE (1) y concluye con la adición del administrador de arranque de WinPE a los nuevos medios (28).

Tarea WinRE (winre.wim) Sistema operativo (install.wim) WinPE (boot.wim) Nuevos medios
Adición de actualización dinámica de pila de mantenimiento 1 9 17
Agregar paquete de idioma 2 10 18
Adición de paquetes opcionales localizados 3 19
Adición de compatibilidad con fuentes 4 20
Adición de texto a voz 5 21
Actualizar Lang.ini 22
Agregar características a petición 11
Agregar actualización dinámica del sistema operativo seguro 6
Agregar actualización dinámica de instalación 26
Adición de setup.exe desde WinPE 27
Adición del administrador de arranque desde WinPE 28
Adición de la actualización acumulativa más reciente 12 23
Limpieza de la imagen 7 13 24
Agregar componentes opcionales 14
Adición de actualizaciones acumulativas de .NET y .NET 15
Exportar imagen 8 16 25

Nota

A partir de febrero de 2021, la actualización acumulativa más reciente y la actualización de la pila de mantenimiento se combinarán y distribuirán en el catálogo de Microsoft Update como una nueva actualización acumulativa combinada. Para los pasos 1, 9 y 18 que requieren la actualización de la pila de mantenimiento para actualizar los medios de instalación, debe usar la actualización acumulativa combinada. Para obtener más información sobre la actualización acumulativa combinada, consulte Mantenimiento de actualizaciones de pila.

Nota

Microsoft quitará el componente Flash de Windows a través de KB4577586, "Actualización para la eliminación de Adobe Flash Player". También puede quitar Flash en cualquier momento implementando la actualización en KB4577586 (disponible en el catálogo) entre los pasos 20 y 21. A partir de julio de 2021, KB4577586, "Actualización para la eliminación de Adobe Flash Player" se incluirá en la última actualización acumulativa para Windows 10, las versiones 1607 y 1507. La actualización también se incluirá en el paquete acumulativo mensual y la actualización de solo seguridad para Windows 8.1, Windows Server 2012 y Windows Embedded 8 Standard. Para obtener más información, consulte Actualización del fin de soporte técnico de Adobe Flash Player.

Varias ediciones de Windows

El archivo del sistema operativo principal (install.wim) puede contener varias ediciones de Windows. Es posible que solo se necesite una actualización para una edición determinada para implementarla, en función del índice. O bien, puede ser que todas las ediciones necesiten una actualización. Además, asegúrese de que los idiomas se instalan antes de las características a petición y que la última actualización acumulativa siempre se aplica por última vez.

Idiomas y características adicionales

No es necesario agregar más idiomas y características a la imagen para realizar las actualizaciones, pero es una oportunidad para personalizar la imagen con más idiomas, componentes opcionales y características a petición más allá de lo que hay en la imagen inicial. Al agregar más idiomas y características, es importante realizar estos cambios en el orden correcto: aplique primero las actualizaciones de la pila de mantenimiento, seguidas de las adiciones de idioma, después las adiciones de características y, por último, la última actualización acumulativa. El script de ejemplo proporcionado instala un segundo idioma (en este caso japonés (ja-JP)). Dado que este idioma está respaldado por un lp.cab, no es necesario agregar un paquete de experiencia de idioma. El japonés se agrega tanto al sistema operativo principal como al entorno de recuperación para permitir al usuario ver las pantallas de recuperación en japonés. Esto incluye la adición de versiones localizadas de los paquetes instalados actualmente en la imagen de recuperación.

Los componentes opcionales, junto con la característica .NET, se pueden instalar sin conexión, pero al hacerlo se crean operaciones pendientes que requieren el reinicio del dispositivo. Como resultado, se producirá un error en la llamada para realizar la limpieza de imágenes. Hay dos opciones para evitar el error de limpieza. Una opción es omitir el paso de limpieza de imágenes, aunque esto da como resultado un install.wim más grande. Otra opción es instalar .NET y los componentes opcionales en un paso después de la limpieza, pero antes de la exportación. Esta es la opción del script de ejemplo. Al hacerlo, tendrá que empezar con el archivo install.wim original (sin acciones pendientes) al mantener o actualizar la imagen la próxima vez (por ejemplo, el mes siguiente).

Windows PowerShell scripts para aplicar Novedades dinámica a una imagen existente

Estos ejemplos son solo para ilustración y, por lo tanto, carecen de control de errores. El script supone que los siguientes paquetes se almacenan localmente en esta estructura de carpetas:

Carpeta Descripción
C:\mediaRefresh Carpeta principal que contiene el script de PowerShell
C:\mediaRefresh\oldMedia Carpeta que contiene el medio original que se actualizará. Por ejemplo, contiene Setup.exe y la carpeta \sources.
C:\mediaRefresh\newMedia Carpeta que contendrá los medios actualizados. Se copia de \oldMedia y, a continuación, se usa como destino para todas las operaciones de actualización y limpieza.

Comenzar

El script comienza declarando variables globales y creando carpetas para usarlas para el montaje de imágenes. A continuación, realice una copia del medio original, desde \oldMedia a \newMedia, manteniendo el medio original en caso de que haya un error de script y sea necesario empezar de nuevo desde un estado conocido. Además, proporciona una comparación de elementos multimedia antiguos frente a nuevos para evaluar los cambios. Para asegurarse de que se actualizan los nuevos medios, asegúrese de que no son de solo lectura.

#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 }

Actualizar WinRE y cada edición principal de Windows del sistema operativo

El script actualizará cada edición de Windows dentro del archivo del sistema operativo principal (install.wim). Para cada edición, se monta la imagen principal del sistema operativo.

Para la primera imagen, Winre.wim se copia en la carpeta de trabajo y se monta. A continuación, aplica la actualización dinámica de la pila de mantenimiento, ya que sus componentes se usan para actualizar otros componentes. Dado que el script agrega opcionalmente japonés, agrega el paquete de idioma a la imagen e instala las versiones en japonés de todos los paquetes opcionales ya instalados en Winre.wim. A continuación, aplica el paquete actualización dinámica del sistema operativo seguro. Finaliza limpiando y exportando la imagen para reducir el tamaño de la imagen.

A continuación, para la imagen del sistema operativo montada, el script comienza aplicando la actualización dinámica de la pila de mantenimiento. A continuación, agrega compatibilidad con el idioma japonés y, a continuación, las características del idioma japonés. A diferencia de los paquetes de actualización dinámica, usa Add-WindowsCapability para agregar estas características. Para obtener una lista completa de estas características y su nombre de funcionalidad asociado, consulte Características disponibles a petición. Ahora es el momento de habilitar otros componentes opcionales o agregar otras características a petición. Si una característica de este tipo tiene una actualización acumulativa asociada (por ejemplo, .NET), este es el momento de aplicarlas. A continuación, el script continúa con la aplicación de la actualización acumulativa más reciente. Por último, el script limpia y exporta la imagen. Puede instalar componentes opcionales, junto con la característica .NET, sin conexión, pero eso requiere que se reinicie el dispositivo. Esta es la razón por la que el script instala .NET y componentes opcionales después de la limpieza y antes de la exportación.

Este proceso se repite para cada edición de Windows dentro del archivo del sistema operativo principal. Para reducir el tamaño, se guarda el archivo Winre.wim con servicio de la primera imagen y se usa para actualizar cada edición de Windows posterior. Esto reduce el tamaño final de 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

Actualización de WinPE

Este script es similar al que actualiza WinRE, pero en su lugar monta Boot.wim, aplica los paquetes con la última actualización acumulativa y guarda. Se repite esto para todas las imágenes dentro de Boot.wim, normalmente dos imágenes. Comienza aplicando la actualización dinámica de la pila de mantenimiento. Dado que el script está personalizando este medio con japonés, instala el paquete de idioma desde la carpeta WinPE en el paquete de idioma ISO. Además, agrega compatibilidad con fuentes y texto a la compatibilidad con voz (TTS). Dado que el script agrega un nuevo idioma, vuelve a generar lang.ini, que se usan para identificar los idiomas instalados en la imagen. En la segunda imagen, guardaremos setup.exe para su uso posterior, a fin de garantizar que esta versión coincida con la versión \sources\setup.exe del medio de instalación. Si estos archivos binarios no son idénticos, se producirá un error en el programa de instalación de Windows durante la instalación. También guardaremos los archivos del administrador de arranque con servicio para usarlos más adelante en el script. Por último, el script limpia y exporta Boot.wim y lo copia de nuevo en los nuevos medios.

#
# 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

Actualizar los archivos multimedia restantes

Esta parte del script actualiza los archivos de instalación. Simplemente copia los archivos individuales del paquete de actualización dinámica de instalación en los nuevos medios. Este paso incluye archivos de instalación actualizados según sea necesario, junto con la base de datos de compatibilidad más reciente y manifiestos de componentes de reemplazo. Este script también realiza un reemplazo final de setup.exe y archivos del administrador de arranque mediante las versiones guardadas anteriormente de 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
    }
}

Finalizar

Como último paso, el script quita la carpeta de trabajo de los archivos temporales y desmonta nuestro paquete de idioma y los ISO de características a petición.

#
# 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!"