動的更新プログラムを使用して Windows インストール メディアを更新する

この記事では、展開前に動的更新プログラム パッケージを取得して既存の Windows イメージに適用する方法について説明し、このプロセスを自動化するために使用できるWindows PowerShellスクリプトが含まれています。

ボリューム ライセンス メディアは、ボリューム ライセンス サービス センター (VLSC) 内の Windows の各リリースと、Windows Update for Business、Windows Server Update Services (WSUS)、Visual Studio サブスクリプションなどのその他の関連チャネルで使用できます。 動的更新プログラムを使用すると、以前にインストールされている可能性がある言語パックとオンデマンド機能 (FOD) を保持しながら、インプレース アップグレードの一環として Windows デバイスに最新の機能更新プログラム パッケージが含まれるようにすることができます。 動的更新では、インプレース アップグレード プロセスの一部として別の品質更新プログラムをインストールする必要もなくなります。

動的更新

機能更新プログラムのインストールが開始されるたびに (メディアからでも、Windows Updateに接続されている環境からでも)、動的更新は最初の手順の 1 つです。 Windows セットアップは、Microsoft エンドポイントに接続して動的更新プログラム パッケージをフェッチし、それらの更新プログラムをオペレーティング システムのインストール メディアに適用します。 更新プログラム パッケージには、次の種類の更新プログラムが含まれています。

  • 機能更新プログラムにセットアップで使用するバイナリまたはその他のファイルを Setup.exe する更新
  • Windows 回復環境に使用される "安全なオペレーティング システム" (SafeOS) の更新
  • 機能更新プログラムを完了するために必要なサービス スタックへの更新詳細については、「サービス スタックの更新プログラム」を参照してください。
  • 最新の累積的な (品質) 更新プログラム
  • 動的更新プログラム専用の製造元によって既に公開されている該当するドライバーへの更新

Dynamic Update では、言語パックとオンデマンド機能パッケージを再取得することで保持されます。

動的な更新を取得するには、デバイスがインターネットに接続できる必要があります。 一部の環境では、動的更新を取得するオプションではありません。 デバイスでセットアップを開始する前に、動的更新パッケージを取得してイメージに適用することで、メディアベースの機能更新を引き続き実行できます。

動的更新プログラム パッケージを取得する

動的更新プログラム パッケージは 、Microsoft Update カタログから入手できます。 そのサイトで、右上の検索バーを使用して、特定のリリースの動的更新プログラム パッケージを見つけます。 1 回の検索の結果には、さまざまな動的更新プログラム パッケージがすべて存在しない場合があるため、すべての更新プログラムを検索するには、さまざまなキーワードで検索する必要がある場合があります。 結果のさまざまな部分を確認して、必要なファイルが特定されていることを確認します。 次の表は、検索または検索する結果のキー値を示しています。

Windows 11バージョン 22H2 動的更新プログラム パッケージ

タイトル は、各動的パッケージを区別できます。 累積的な更新プログラムには、サービス スタックが埋め込まれています。 サービス スタックは、特定の累積的な更新プログラムに必要な場合にのみ発行されます。

パッケージの更新 タイトル
安全な OS 動的更新プログラム Windows 11 バージョン 22H2 の YYYY-MM セーフ OS 動的更新プログラム
動的更新の設定 Windows 11 バージョン 22H2 の YYYY-MM セットアップ動的更新
最新の累積的な更新プログラム Windows 11 バージョン 22H2 の YYYY-MM 累積的な更新プログラム
サービス スタックの動的更新 Windows 11 バージョン 22H2 の YYYY-MM サービス スタック更新プログラム

Windows 11バージョン 21H2 動的更新プログラム パッケージ

動的パッケージを区別するには、タイトル、 製品説明 が必要です。 最新の累積的な更新プログラムには、サービス スタックが埋め込まれています。 サービス スタックは、特定の累積的な更新プログラムの前提条件として必要な場合にのみ個別に発行されます。

パッケージの更新 タイトル 製品 説明
安全な OS 動的更新プログラム Windows 11の YYYY-MM 動的更新 Windows セーフ OS の動的更新プログラム ComponentUpdate
動的更新の設定 Windows 11の YYYY-MM 動的更新 Windows 10以降の動的更新 SetupUpdate
最新の累積的な更新プログラム Windows 11の YYYY-MM 累積的な更新プログラム
サービス スタックの動的更新 Windows 11 バージョン 21H2 の YYYY-MM サービス スタック更新プログラム

Windows 10の場合、バージョン 22H2 動的更新プログラム パッケージ

動的パッケージを区別するには、タイトル、 製品説明 が必要です。 最新の累積的な更新プログラムには、サービス スタックが埋め込まれています。 サービス スタックは、特定の累積的な更新プログラムの前提条件として必要な場合にのみ個別に発行されます。

パッケージの更新 タイトル 製品 説明
安全な OS 動的更新プログラム Windows 10 バージョン 22H2 の YYYY-MM 動的更新プログラム Windows セーフ OS の動的更新プログラム ComponentUpdate
動的更新の設定 Windows 10 バージョン 22H2 の YYYY-MM 動的更新プログラム Windows 10以降の動的更新 SetupUpdate
最新の累積的な更新プログラム Windows 10 バージョン 22H2 の YYYY-MM 累積的な更新プログラム
サービス スタックの動的更新 Windows 10 バージョン 22H2 の YYYY-MM サービス スタック更新プログラム

追加の言語またはオンデマンド機能を使用してイメージをカスタマイズする場合は、 ボリューム ライセンス サービス センターから補足メディア ISO ファイルをダウンロードします。 たとえば、デバイスの動的更新が無効になり、ユーザーが特定のオンデマンド機能を必要とする場合は、これらをイメージにプレインストールできます。

Windows インストール メディアを更新する

インストール メディアを適切に更新するには、複数の異なるターゲット (イメージ ファイル) で動作する多数のアクションが必要です。 一部のアクションは、さまざまなターゲットで繰り返されます。 ターゲット イメージ ファイルには、次のものが含まれます。

  • Windows プレインストール環境 (WinPE): Windows オペレーティング システムのインストール、展開、修復に使用される小規模なオペレーティング システム
  • Windows Recovery Environment (WinRE): 起動できないオペレーティング システムの一般的な原因を修復します。 WinRE は WinPE に基づいており、追加のドライバー、言語、オプション パッケージ、およびその他のトラブルシューティングまたは診断ツールを使用してカスタマイズできます。
  • Windows オペレーティング システム: \sources\install.wim に格納されている Windows の 1 つ以上のエディション
  • 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
安全な OS 動的更新プログラムを追加する 6
セットアップの動的更新の追加 26
WinPE から setup.exe を追加する 27
WinPE からブート マネージャーを追加する 28
最新の累積的な更新プログラムを追加する 12 23
イメージをクリーンアップする 7 13 24
省略可能なコンポーネントを追加する 14
.NET および .NET の累積的な更新プログラムを追加する 15
イメージのエクスポート 8 16 25

2021 年 2 月以降、最新の累積的な更新プログラムとサービス スタック更新プログラムが組み合わされ、新しい累積更新プログラムとして Microsoft Update Catalog に配布されます。 インストール メディアを更新するためにサービス スタック更新プログラムが必要な手順 1、9、18 では、組み合わされた累積的な更新プログラムを使用する必要があります。 組み合わされた累積的な更新プログラムの詳細については、「 サービス スタックの更新プログラム」を参照してください。

Microsoft は、"Adobe Flash Player の削除用の更新プログラム" KB4577586を通じて、Windows から Flash コンポーネントを削除します。 手順 20 から 21 の間の KB4577586 (カタログで利用可能) に更新プログラムをデプロイすることで、いつでも Flash を削除することもできます。 2021 年 7 月の時点で、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 が含まれている場合があります。 インデックスに基づいて、特定のエディションの更新プログラムのみをデプロイする必要がある可能性があります。 または、すべてのエディションに更新プログラムが必要な場合があります。 さらに、オンデマンド機能の前に言語がインストールされ、最新の累積的な更新プログラムが常に最後に適用されるようにします。

その他の言語と機能

更新を行うためにイメージに言語と機能を追加する必要はありませんが、開始イメージ以外の言語、オプションコンポーネント、およびオンデマンド機能を使用してイメージをカスタマイズする機会です。 より多くの言語と機能を追加する場合は、次の変更を正しい順序で行う必要があります。最初にサービス スタック更新プログラムを適用し、次に言語の追加、次に機能の追加、最後に最新の累積的な更新プログラムを適用します。 提供されたサンプル スクリプトは、2 番目の言語 (この場合は日本語 (ja-JP)) をインストールします。 この言語は lp.cab によってサポートされているため、Language Experience Pack を追加する必要はありません。 ユーザーが回復画面を日本語で表示できるように、メインオペレーティング システムと復旧環境の両方に日本語が追加されます。 これには、現在回復イメージにインストールされているパッケージのローカライズされたバージョンの追加が含まれます。

オプションのコンポーネントと .NET 機能はオフラインでインストールできますが、これを行うと、デバイスの再起動を必要とする保留中の操作が作成されます。 その結果、イメージクリーンアップを実行する呼び出しは失敗します。 クリーンアップ エラーを回避するには、2 つのオプションがあります。 1 つのオプションは、イメージのクリーンアップ手順をスキップすることですが、その結果、install.wim が大きくなります。 もう 1 つのオプションは、クリーンアップ後、エクスポート前の手順で .NET と省略可能なコンポーネントをインストールすることです。 これはサンプル スクリプトのオプションです。 これを行うには、次回 (次の月など) にイメージを維持または更新するときに、元の install.wim (保留中のアクションなし) から開始する必要があります。

既存のイメージに動的更新を適用するスクリプトをWindows PowerShellする

これらの例は図専用であるため、エラー処理がありません。 このスクリプトでは、次のパッケージがこのフォルダー構造にローカルに格納されていることを前提としています。

フォルダー 説明
C:\mediaRefresh PowerShell スクリプトを含む親フォルダー
C:\mediaRefresh\oldMedia 更新される元のメディアを含むフォルダー。 たとえば、Setup.exe フォルダーと \sources フォルダーが含まれます。
C:\mediaRefresh\newMedia 更新されたメディアを含むフォルダー。 \oldMedia からコピーされ、すべての更新およびクリーンアップ操作のターゲットとして使用されます。

使ってみる

スクリプトはまず、グローバル変数を宣言し、イメージのマウントに使用するフォルダーを作成します。 次に、スクリプト エラーが発生し、既知の状態からやり直す必要がある場合に備えて、元のメディアを \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 と各メイン OS Windows エディションを更新する

スクリプトは、メイン オペレーティング システム ファイル (install.wim) 内の Windows の各エディションを更新します。 エディションごとに、メイン OS イメージがマウントされます。

最初のイメージでは、Winre.wim が作業フォルダーにコピーされ、マウントされます。 その後、そのコンポーネントは他のコンポーネントの更新に使用されるため、サービス スタックの動的更新が適用されます。 スクリプトはオプションで日本語を追加するため、イメージに言語パックが追加され、Winre.wim に既にインストールされているすべてのオプション パッケージの日本語バージョンがインストールされます。 次に、安全な OS 動的更新プログラム パッケージが適用されます。 イメージのサイズを小さくするために、イメージのクリーニングとエクスポートによって終了します。

次に、マウントされた OS イメージの場合、スクリプトはサービス スタックの動的更新を適用することから始まります。 次に、日本語のサポートと日本語機能が追加されます。 動的更新パッケージとは異なり、これらの機能を追加するために を使用 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 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 内のすべてのイメージ (通常は 2 つのイメージ) に対してこれを繰り返します。 まず、サービス スタックの動的更新プログラムを適用します。 スクリプトは日本語でこのメディアをカスタマイズしているため、言語パック ISO の WinPE フォルダーから言語パックをインストールします。 さらに、フォントサポートとテキスト読み上げ (TTS) サポートが追加されます。 スクリプトは新しい言語を追加しているため、イメージにインストールされている言語を識別するために使用される lang.ini を再構築します。 2 番目のイメージでは、後で使用するために 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

残りのメディア ファイルを更新する

スクリプトのこの部分では、セットアップ ファイルが更新されます。 セットアップ動的更新パッケージ内の個々のファイルを新しいメディアにコピーするだけです。 この手順では、必要に応じて更新されたセットアップ ファイルと、最新の互換性データベース、および置換コンポーネント マニフェストを取り込みます。 このスクリプトでは、WinPE から以前に保存したバージョンを使用して、setup.exe ファイルとブート マネージャー ファイルを最終的に置き換えることもできます。

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

完了

最後の手順として、スクリプトは一時ファイルの作業フォルダーを削除し、言語パックとオンデマンドの機能の ISO のマウントを解除します。

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