動的更新プログラムを使用して Windows インストール メディアを更新する
この記事では、 展開前 に動的更新プログラム パッケージを取得して既存の Windows イメージに適用する方法について説明し、このプロセスを自動化するために使用できる Windows PowerShell スクリプトが含まれています。
ボリューム ライセンス メディアは、ボリューム ライセンス サービス センター (VLSC) 内の Windows の各リリースと、ビジネス向け Windows Update、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 以降の動的更新プログラム パッケージ
タイトル は、各動的パッケージを区別できます。 最新の累積的な更新プログラムには、サービス スタックが埋め込まれています。 サービス スタックは、特定の累積的な更新プログラムに必要な場合にのみ発行されます。以下のタイトルは、Windows 11 バージョン 22H2 用です。 Windows 11 バージョン 23H2 と 24H2 の形式も同様です。
パッケージの更新 | タイトル |
---|---|
安全な 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 11 バージョン 24H2 以降では、最新の累積的な更新プログラムには、最初にインストールする必要がある前提条件の累積的な更新プログラムがある場合があります。 これらはチェックポイント累積更新プログラムと呼ばれます。 このような場合、累積的な更新プログラム ファイル レベルの差分は、Windows RTM リリースではなく、以前の累積的な更新プログラムに基づいています。 利点は、より小さな更新プログラム パッケージと高速インストールです。 Microsoft Update カタログから最新の累積的な更新プログラムを取得すると、チェックポイントの累積的な更新プログラムがダウンロード ボタンから使用できるようになります。 さらに、累積的な更新プログラムのサポート技術情報の記事では、追加情報が提供されます。
Windows OS (手順 9 & 12) と WinPE (手順 17 & 23) を提供するときにチェックポイントをインストールするには、ターゲットの累積的な更新プログラムを使用して Add-WindowsPackage
を呼び出します。
-PackagePath
のフォルダーは、必要に応じて 1 つ以上のチェックポイントを検出してインストールするために使用されます。 ターゲットの累積的な更新プログラムとチェックポイントの累積的な更新プログラムのみが、 -PackagePath
フォルダーに存在する必要があります。 リビジョン <= ターゲットの累積的な更新プログラムを含む累積的な更新プログラム パッケージが処理されます。 追加の言語や省略可能な機能を使用してイメージをカスタマイズしない場合は、上記の手順 9 & 17 の Add-WindowsPackage
(チェックポイント累積更新プログラム) を個別に呼び出すことができます。 手順 12 と 23 では、個別の呼び出しを使用できません。
既存のイメージに動的更新プログラムを適用するための 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. A dedicated folder is used for the latest cumulative update, and as needed
# checkpoint cumulative updates.
$LCU_PATH = "C:\mediaRefresh\packages\CU\LCU.msu"
$SSU_PATH = "C:\mediaRefresh\packages\Other\SSU_DU.msu"
$SETUP_DU_PATH = "C:\mediaRefresh\packages\Other\Setup_DU.cab"
$SAFE_OS_DU_PATH = "C:\mediaRefresh\packages\Other\SafeOS_DU.cab"
$DOTNET_CU_PATH = "C:\mediaRefresh\packages\Other\DotNet_CU.msu"
# Declare folders for mounted images and temp files
$MEDIA_OLD_PATH = "C:\mediaRefresh\oldMedia"
$MEDIA_NEW_PATH = "C:\mediaRefresh\newMedia"
$WORKING_PATH = "C:\mediaRefresh\temp"
$MAIN_OS_MOUNT = "C:\mediaRefresh\temp\MainOSMount"
$WINRE_MOUNT = "C:\mediaRefresh\temp\WinREMount"
$WINPE_MOUNT = "C:\mediaRefresh\temp\WinPEMount"
# Mount the Features on Demand ISO
Write-Output "$(Get-TS): Mounting FOD ISO"
$FOD_ISO_DRIVE_LETTER = (Mount-DiskImage -ImagePath $FOD_ISO_PATH -ErrorAction stop | Get-Volume).DriveLetter
# Note: Starting with Windows 11, version 21H2, the correct path for main OS language and optional features
# moved to \LanguagesAndOptionalFeatures instead of the root. For Windows 10, use $FOD_PATH = $FOD_ISO_DRIVE_LETTER + ":\"
$FOD_PATH = $FOD_ISO_DRIVE_LETTER + ":\LanguagesAndOptionalFeatures"
# Declare language related cabs
$WINPE_OC_PATH = "$FOD_ISO_DRIVE_LETTER`:\Windows Preinstallation Environment\x64\WinPE_OCs"
$WINPE_OC_LANG_PATH = "$WINPE_OC_PATH\$LANG"
$WINPE_OC_LANG_CABS = Get-ChildItem $WINPE_OC_LANG_PATH -Name
$WINPE_OC_LP_PATH = "$WINPE_OC_LANG_PATH\lp.cab"
$WINPE_FONT_SUPPORT_PATH = "$WINPE_OC_PATH\WinPE-FontSupport-$LANG.cab"
$WINPE_SPEECH_TTS_PATH = "$WINPE_OC_PATH\WinPE-Speech-TTS.cab"
$WINPE_SPEECH_TTS_LANG_PATH = "$WINPE_OC_PATH\WinPE-Speech-TTS-$LANG.cab"
$OS_LP_PATH = "$FOD_PATH\Microsoft-Windows-Client-Language-Pack_x64_$LANG.cab"
# Create folders for mounting images and storing temporary files
New-Item -ItemType directory -Path $WORKING_PATH -ErrorAction Stop | Out-Null
New-Item -ItemType directory -Path $MAIN_OS_MOUNT -ErrorAction stop | Out-Null
New-Item -ItemType directory -Path $WINRE_MOUNT -ErrorAction stop | Out-Null
New-Item -ItemType directory -Path $WINPE_MOUNT -ErrorAction stop | Out-Null
# Keep the original media, make a copy of it for the new, updated media.
Write-Output "$(Get-TS): Copying original media to new media path"
Copy-Item -Path $MEDIA_OLD_PATH"\*" -Destination $MEDIA_NEW_PATH -Force -Recurse -ErrorAction stop | Out-Null
Get-ChildItem -Path $MEDIA_NEW_PATH -Recurse | Where-Object { -not $_.PSIsContainer -and $_.IsReadOnly } | ForEach-Object { $_.IsReadOnly = $false }
WinRE と各メイン 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 the main OS
$WINOS_IMAGES = Get-WindowsImage -ImagePath $MEDIA_NEW_PATH"\sources\install.wim"
Foreach ($IMAGE in $WINOS_IMAGES) {
# first mount the main OS image
Write-Output "$(Get-TS): Mounting main OS, image index $($IMAGE.ImageIndex)"
Mount-WindowsImage -ImagePath $MEDIA_NEW_PATH"\sources\install.wim" -Index $IMAGE.ImageIndex -Path $MAIN_OS_MOUNT -ErrorAction stop| Out-Null
if ($IMAGE.ImageIndex -eq "1") {
#
# update Windows Recovery Environment (WinRE) within this OS image
#
Copy-Item -Path $MAIN_OS_MOUNT"\windows\system32\recovery\winre.wim" -Destination $WORKING_PATH"\winre.wim" -Force -ErrorAction stop | Out-Null
Write-Output "$(Get-TS): Mounting WinRE"
Mount-WindowsImage -ImagePath $WORKING_PATH"\winre.wim" -Index 1 -Path $WINRE_MOUNT -ErrorAction stop | Out-Null
# Add servicing stack update (Step 1 from the table)
# Depending on the Windows release that you are updating, there are 2 different approaches for updating the servicing stack
# The first approach is to use the combined cumulative update. This is for Windows releases that are shipping a combined
# cumulative update that includes the servicing stack updates (i.e. SSU + LCU are combined). Windows 11, version 21H2 and
# Windows 11, version 22H2 are examples. In these cases, the servicing stack update is not published seperately; the combined
# cumulative update should be used for this step. However, in hopefully rare cases, there may breaking change in the combined
# cumulative update format, that requires a standalone servicing stack update to be published, and installed first before the
# combined cumulative update can be installed.
# This is the code to handle the rare case that the SSU is published and required for the combined cumulative update
# Write-Output "$(Get-TS): Adding package $SSU_PATH"
# Add-WindowsPackage -Path $WINRE_MOUNT -PackagePath $SSU_PATH | Out-Null
# Now, attempt the combined cumulative update.
# There is a known issue where the servicing stack update is installed, but the cumulative update will fail. This error should
# be caught and ignored, as the last step will be to apply the Safe OS update and thus the image will be left with the correct
# packages installed.
Write-Output "$(Get-TS): Adding package $LCU_PATH to WinRE"
try
{
Add-WindowsPackage -Path $WINRE_MOUNT -PackagePath $LCU_PATH | Out-Null
}
Catch
{
$theError = $_
Write-Output "$(Get-TS): $theError"
if ($theError.Exception -like "*0x8007007e*") {
Write-Output "$(Get-TS): This failure is a known issue with combined cumulative update, we can ignore."
}
else {
throw
}
}
# The second approach for Step 1 is for Windows releases that have not adopted the combined cumulative update
# but instead continue to have a seperate servicing stack update published. In this case, we'll install the SSU
# update. This second approach is commented out below.
# Write-Output "$(Get-TS): Adding package $SSU_PATH"
# Add-WindowsPackage -Path $WINRE_MOUNT -PackagePath $SSU_PATH | Out-Null
#
# Optional: Add the language to recovery environment
#
# Install lp.cab cab
Write-Output "$(Get-TS): Adding package $WINPE_OC_LP_PATH to WinRE"
Add-WindowsPackage -Path $WINRE_MOUNT -PackagePath $WINPE_OC_LP_PATH -ErrorAction stop | Out-Null
# Install language cabs for each optional package installed
$WINRE_INSTALLED_OC = Get-WindowsPackage -Path $WINRE_MOUNT
Foreach ($PACKAGE in $WINRE_INSTALLED_OC) {
if ( ($PACKAGE.PackageState -eq "Installed") -and ($PACKAGE.PackageName.startsWith("WinPE-")) -and ($PACKAGE.ReleaseType -eq "FeaturePack") ) {
$INDEX = $PACKAGE.PackageName.IndexOf("-Package")
if ($INDEX -ge 0) {
$OC_CAB = $PACKAGE.PackageName.Substring(0, $INDEX) + "_" + $LANG + ".cab"
if ($WINPE_OC_LANG_CABS.Contains($OC_CAB)) {
$OC_CAB_PATH = Join-Path $WINPE_OC_LANG_PATH $OC_CAB
Write-Output "$(Get-TS): Adding package $OC_CAB_PATH to WinRE"
Add-WindowsPackage -Path $WINRE_MOUNT -PackagePath $OC_CAB_PATH -ErrorAction stop | Out-Null
}
}
}
}
# Add font support for the new language
if ( (Test-Path -Path $WINPE_FONT_SUPPORT_PATH) ) {
Write-Output "$(Get-TS): Adding package $WINPE_FONT_SUPPORT_PATH to WinRE"
Add-WindowsPackage -Path $WINRE_MOUNT -PackagePath $WINPE_FONT_SUPPORT_PATH -ErrorAction stop | Out-Null
}
# Add TTS support for the new language
if (Test-Path -Path $WINPE_SPEECH_TTS_PATH) {
if ( (Test-Path -Path $WINPE_SPEECH_TTS_LANG_PATH) ) {
Write-Output "$(Get-TS): Adding package $WINPE_SPEECH_TTS_PATH to WinRE"
Add-WindowsPackage -Path $WINRE_MOUNT -PackagePath $WINPE_SPEECH_TTS_PATH -ErrorAction stop | Out-Null
Write-Output "$(Get-TS): Adding package $WINPE_SPEECH_TTS_LANG_PATH to WinRE"
Add-WindowsPackage -Path $WINRE_MOUNT -PackagePath $WINPE_SPEECH_TTS_LANG_PATH -ErrorAction stop | Out-Null
}
}
# Add Safe OS
Write-Output "$(Get-TS): Adding package $SAFE_OS_DU_PATH to WinRE"
Add-WindowsPackage -Path $WINRE_MOUNT -PackagePath $SAFE_OS_DU_PATH -ErrorAction stop | Out-Null
# Perform image cleanup
Write-Output "$(Get-TS): Performing image cleanup on WinRE"
DISM /image:$WINRE_MOUNT /cleanup-image /StartComponentCleanup /ResetBase /Defer | Out-Null
# Dismount
Dismount-WindowsImage -Path $WINRE_MOUNT -Save -ErrorAction stop | Out-Null
# Export
Write-Output "$(Get-TS): Exporting image to $WORKING_PATH\winre.wim"
Export-WindowsImage -SourceImagePath $WORKING_PATH"\winre.wim" -SourceIndex 1 -DestinationImagePath $WORKING_PATH"\winre2.wim" -ErrorAction stop | Out-Null
}
Copy-Item -Path $WORKING_PATH"\winre2.wim" -Destination $MAIN_OS_MOUNT"\windows\system32\recovery\winre.wim" -Force -ErrorAction stop | Out-Null
#
# update Main OS
#
# Add servicing stack update (Step 18 from the table)
# Depending on the Windows release that you are updating, there are 2 different approaches for updating the servicing stack
# The first approach is to use the combined cumulative update. This is for Windows releases that are shipping a combined cumulative update that
# includes the servicing stack updates (i.e. SSU + LCU are combined). Windows 11, version 21H2 and Windows 11, version 22H2 are examples. In these
# cases, the servicing stack update is not published seperately; the combined cumulative update should be used for this step. However, in hopefully
# rare cases, there may breaking change in the combined cumulative update format, that requires a standalone servicing stack update to be published,
# and installed first before the combined cumulative update can be installed.
# This is the code to handle the rare case that the SSU is published and required for the combined cumulative update
# Write-Output "$(Get-TS): Adding package $SSU_PATH"
# Add-WindowsPackage -Path $MAIN_OS_MOUNT -PackagePath $SSU_PATH | Out-Null
# Now, attempt the combined cumulative update. Unlike WinRE and WinPE, we don't need to check for error 0x8007007e
Write-Output "$(Get-TS): Adding package $LCU_PATH to main OS, index $($IMAGE.ImageIndex)"
Add-WindowsPackage -Path $MAIN_OS_MOUNT -PackagePath $LCU_PATH | Out-Null
# The second approach for Step 18 is for Windows releases that have not adopted the combined cumulative update
# but instead continue to have a seperate servicing stack update published. In this case, we'll install the SSU
# update. This second approach is commented out below.
# Write-Output "$(Get-TS): Adding package $SSU_PATH to main OS, index $($IMAGE.ImageIndex)"
# Add-WindowsPackage -Path $MAIN_OS_MOUNT -PackagePath $SSU_PATH | Out-Null
# Optional: Add language to main OS
Write-Output "$(Get-TS): Adding package $OS_LP_PATH to main OS, index $($IMAGE.ImageIndex)"
Add-WindowsPackage -Path $MAIN_OS_MOUNT -PackagePath $OS_LP_PATH -ErrorAction stop | Out-Null
# Optional: Add a Features on Demand to the image
Write-Output "$(Get-TS): Adding language FOD: Language.Fonts.Jpan~~~und-JPAN~0.0.1.0 to main OS, index $($IMAGE.ImageIndex)"
Add-WindowsCapability -Name "Language.Fonts.$LANG_FONT_CAPABILITY~~~und-$LANG_FONT_CAPABILITY~0.0.1.0" -Path $MAIN_OS_MOUNT -Source $FOD_PATH -ErrorAction stop | Out-Null
Write-Output "$(Get-TS): Adding language FOD: Language.Basic~~~$LANG~0.0.1.0 to main OS, index $($IMAGE.ImageIndex)"
Add-WindowsCapability -Name "Language.Basic~~~$LANG~0.0.1.0" -Path $MAIN_OS_MOUNT -Source $FOD_PATH -ErrorAction stop | Out-Null
Write-Output "$(Get-TS): Adding language FOD: Language.OCR~~~$LANG~0.0.1.0 to main OS, index $($IMAGE.ImageIndex)"
Add-WindowsCapability -Name "Language.OCR~~~$LANG~0.0.1.0" -Path $MAIN_OS_MOUNT -Source $FOD_PATH -ErrorAction stop | Out-Null
Write-Output "$(Get-TS): Adding language FOD: Language.Handwriting~~~$LANG~0.0.1.0 to main OS, index $($IMAGE.ImageIndex)"
Add-WindowsCapability -Name "Language.Handwriting~~~$LANG~0.0.1.0" -Path $MAIN_OS_MOUNT -Source $FOD_PATH -ErrorAction stop | Out-Null
Write-Output "$(Get-TS): Adding language FOD: Language.TextToSpeech~~~$LANG~0.0.1.0 to main OS, index $($IMAGE.ImageIndex)"
Add-WindowsCapability -Name "Language.TextToSpeech~~~$LANG~0.0.1.0" -Path $MAIN_OS_MOUNT -Source $FOD_PATH -ErrorAction stop | Out-Null
Write-Output "$(Get-TS): Adding language FOD: Language.Speech~~~$LANG~0.0.1.0 to main OS, index $($IMAGE.ImageIndex)"
Add-WindowsCapability -Name "Language.Speech~~~$LANG~0.0.1.0" -Path $MAIN_OS_MOUNT -Source $FOD_PATH -ErrorAction stop | Out-Null
# Note: If I wanted to enable additional Features on Demand, I'd add these here.
# Add latest cumulative update
Write-Output "$(Get-TS): Adding package $LCU_PATH to main OS, index $($IMAGE.ImageIndex)"
Add-WindowsPackage -Path $MAIN_OS_MOUNT -PackagePath $LCU_PATH -ErrorAction stop | Out-Null
# Perform image cleanup
Write-Output "$(Get-TS): Performing image cleanup on main OS, index $($IMAGE.ImageIndex)"
DISM /image:$MAIN_OS_MOUNT /cleanup-image /StartComponentCleanup | Out-Null
#
# Note: If I wanted to enable additional Optional Components, I'd add these here.
# In addition, we'll add .NET 3.5 here as well. Both .NET and Optional Components might require
# the image to be booted, and thus if we tried to cleanup after installation, it would fail.
#
Write-Output "$(Get-TS): Adding NetFX3~~~~ to main OS, index $($IMAGE.ImageIndex)"
Add-WindowsCapability -Name "NetFX3~~~~" -Path $MAIN_OS_MOUNT -Source $FOD_PATH -ErrorAction stop | Out-Null
# Add .NET Cumulative Update
Write-Output "$(Get-TS): Adding package $DOTNET_CU_PATH to main OS, index $($IMAGE.ImageIndex)"
Add-WindowsPackage -Path $MAIN_OS_MOUNT -PackagePath $DOTNET_CU_PATH -ErrorAction stop | Out-Null
# Dismount
Dismount-WindowsImage -Path $MAIN_OS_MOUNT -Save -ErrorAction stop | Out-Null
# Export
Write-Output "$(Get-TS): Exporting image to $WORKING_PATH\install2.wim"
Export-WindowsImage -SourceImagePath $MEDIA_NEW_PATH"\sources\install.wim" -SourceIndex $IMAGE.ImageIndex -DestinationImagePath $WORKING_PATH"\install2.wim" -ErrorAction stop | Out-Null
}
Move-Item -Path $WORKING_PATH"\install2.wim" -Destination $MEDIA_NEW_PATH"\sources\install.wim" -Force -ErrorAction stop | Out-Null
WinPE の更新
このスクリプトは WinRE を更新するスクリプトと似ていますが、代わりに Boot.wim をマウントし、最後に最新の累積的な更新プログラムを含むパッケージを適用して保存します。 Boot.wim 内のすべてのイメージ (通常は 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
{
Write-Output "$(Get-TS): Adding package $LCU_PATH to WinPE, image index $($IMAGE.ImageIndex)"
Add-WindowsPackage -Path $WINPE_MOUNT -PackagePath $LCU_PATH | Out-Null
}
Catch
{
$theError = $_
Write-Output "$(Get-TS): $theError"
if ($theError.Exception -like "*0x8007007e*") {
Write-Output "$(Get-TS): This failure is a known issue with combined cumulative update, we can ignore."
}
else {
throw
}
}
# The second approach for Step 9 is for Windows releases that have not adopted the combined cumulative update
# but instead continue to have a separate servicing stack update published. In this case, we'll install the SSU
# update. This second approach is commented out below.
# Write-Output "$(Get-TS): Adding package $SSU_PATH"
# Add-WindowsPackage -Path $WINPE_MOUNT -PackagePath $SSU_PATH | Out-Null
# Install lp.cab cab
Write-Output "$(Get-TS): Adding package $WINPE_OC_LP_PATH to WinPE, image index $($IMAGE.ImageIndex)"
Add-WindowsPackage -Path $WINPE_MOUNT -PackagePath $WINPE_OC_LP_PATH -ErrorAction stop | Out-Null
# Install language cabs for each optional package installed
$WINPE_INSTALLED_OC = Get-WindowsPackage -Path $WINPE_MOUNT
Foreach ($PACKAGE in $WINPE_INSTALLED_OC) {
if ( ($PACKAGE.PackageState -eq "Installed") -and ($PACKAGE.PackageName.startsWith("WinPE-")) -and ($PACKAGE.ReleaseType -eq "FeaturePack") ) {
$INDEX = $PACKAGE.PackageName.IndexOf("-Package")
if ($INDEX -ge 0) {
$OC_CAB = $PACKAGE.PackageName.Substring(0, $INDEX) + "_" + $LANG + ".cab"
if ($WINPE_OC_LANG_CABS.Contains($OC_CAB)) {
$OC_CAB_PATH = Join-Path $WINPE_OC_LANG_PATH $OC_CAB
Write-Output "$(Get-TS): Adding package $OC_CAB_PATH to WinPE, image index $($IMAGE.ImageIndex)"
Add-WindowsPackage -Path $WINPE_MOUNT -PackagePath $OC_CAB_PATH -ErrorAction stop | Out-Null
}
}
}
}
# Add font support for the new language
if ( (Test-Path -Path $WINPE_FONT_SUPPORT_PATH) ) {
Write-Output "$(Get-TS): Adding package $WINPE_FONT_SUPPORT_PATH to WinPE, image index $($IMAGE.ImageIndex)"
Add-WindowsPackage -Path $WINPE_MOUNT -PackagePath $WINPE_FONT_SUPPORT_PATH -ErrorAction stop | Out-Null
}
# Add TTS support for the new language
if (Test-Path -Path $WINPE_SPEECH_TTS_PATH) {
if ( (Test-Path -Path $WINPE_SPEECH_TTS_LANG_PATH) ) {
Write-Output "$(Get-TS): Adding package $WINPE_SPEECH_TTS_PATH to WinPE, image index $($IMAGE.ImageIndex)"
Add-WindowsPackage -Path $WINPE_MOUNT -PackagePath $WINPE_SPEECH_TTS_PATH -ErrorAction stop | Out-Null
Write-Output "$(Get-TS): Adding package $WINPE_SPEECH_TTS_LANG_PATH to WinPE, image index $($IMAGE.ImageIndex)"
Add-WindowsPackage -Path $WINPE_MOUNT -PackagePath $WINPE_SPEECH_TTS_LANG_PATH -ErrorAction stop | Out-Null
}
}
# Generates a new Lang.ini file which is used to define the language packs inside the image
if ( (Test-Path -Path $WINPE_MOUNT"\sources\lang.ini") ) {
Write-Output "$(Get-TS): Updating lang.ini"
DISM /image:$WINPE_MOUNT /Gen-LangINI /distribution:$WINPE_MOUNT | Out-Null
}
# Add latest cumulative update
Write-Output "$(Get-TS): Adding package $LCU_PATH to WinPE, image index $($IMAGE.ImageIndex)"
Add-WindowsPackage -Path $WINPE_MOUNT -PackagePath $LCU_PATH -ErrorAction stop | Out-Null
# Perform image cleanup
Write-Output "$(Get-TS): Performing image cleanup on WinPE, image index $($IMAGE.ImageIndex)"
DISM /image:$WINPE_MOUNT /cleanup-image /StartComponentCleanup /ResetBase /Defer | Out-Null
if ($IMAGE.ImageIndex -eq "2") {
# Save setup.exe for later use. This will address possible binary mismatch with the version in the main OS \sources folder
Copy-Item -Path $WINPE_MOUNT"\sources\setup.exe" -Destination $WORKING_PATH"\setup.exe" -Force -ErrorAction stop | Out-Null
# Save setuphost.exe for later use. This will address possible binary mismatch with the version in the main OS \sources folder
# This is only required starting with Windows 11 version 24H2
$TEMP = Get-WindowsImage -ImagePath $MEDIA_NEW_PATH"\sources\boot.wim" -Index $IMAGE.ImageIndex
if ([System.Version]$TEMP.Version -ge [System.Version]"10.0.26100") {
Copy-Item -Path $WINPE_MOUNT"\sources\setuphost.exe" -Destination $WORKING_PATH"\setuphost.exe" -Force -ErrorAction stop | Out-Null
}
else {
Write-Output "$(Get-TS): Skipping copy of setuphost.exe; image version $($TEMP.Version)"
}
# Save serviced boot manager files later copy to the root media.
Copy-Item -Path $WINPE_MOUNT"\Windows\boot\efi\bootmgfw.efi" -Destination $WORKING_PATH"\bootmgfw.efi" -Force -ErrorAction stop | Out-Null
Copy-Item -Path $WINPE_MOUNT"\Windows\boot\efi\bootmgr.efi" -Destination $WORKING_PATH"\bootmgr.efi" -Force -ErrorAction stop | Out-Null
}
# Dismount
Dismount-WindowsImage -Path $WINPE_MOUNT -Save -ErrorAction stop | Out-Null
#Export WinPE
Write-Output "$(Get-TS): Exporting image to $WORKING_PATH\boot2.wim"
Export-WindowsImage -SourceImagePath $MEDIA_NEW_PATH"\sources\boot.wim" -SourceIndex $IMAGE.ImageIndex -DestinationImagePath $WORKING_PATH"\boot2.wim" -ErrorAction stop | Out-Null
}
Move-Item -Path $WORKING_PATH"\boot2.wim" -Destination $MEDIA_NEW_PATH"\sources\boot.wim" -Force -ErrorAction stop | Out-Null
残りのメディア ファイルを更新する
スクリプトのこの部分では、セットアップ ファイルが更新されます。 セットアップ動的更新パッケージ内の個々のファイルを新しいメディアにコピーするだけです。 この手順では、必要に応じて更新されたセットアップ ファイルと、最新の互換性データベース、および置換コンポーネント マニフェストを取り込みます。 このスクリプトでは、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 setuphost.exe from boot.wim, saved earlier.
if (Test-Path -Path $WORKING_PATH"\setuphost.exe") {
Write-Output "$(Get-TS): Copying $WORKING_PATH\setuphost.exe to $MEDIA_NEW_PATH\sources\setuphost.exe"
Copy-Item -Path $WORKING_PATH"\setuphost.exe" -Destination $MEDIA_NEW_PATH"\sources\setuphost.exe" -Force -ErrorAction stop | Out-Null
}
# Copy bootmgr files from boot.wim, saved earlier.
$MEDIA_NEW_FILES = Get-ChildItem $MEDIA_NEW_PATH -Force -Recurse -Filter b*.efi
Foreach ($File in $MEDIA_NEW_FILES){
if (($File.Name -ieq "bootmgfw.efi") -or ($File.Name -ieq "bootx64.efi") -or ($File.Name -ieq "bootia32.efi") -or ($File.Name -ieq "bootaa64.efi"))
{
Write-Output "$(Get-TS): Copying $WORKING_PATH\bootmgfw.efi to $($File.FullName)"
Copy-Item -Path $WORKING_PATH"\bootmgfw.efi" -Destination $File.FullName -Force -ErrorAction stop | Out-Null
}
elseif ($File.Name -ieq "bootmgr.efi")
{
Write-Output "$(Get-TS): Copying $WORKING_PATH\bootmgr.efi to $($File.FullName)"
Copy-Item -Path $WORKING_PATH"\bootmgr.efi" -Destination $File.FullName -Force -ErrorAction stop | Out-Null
}
}
完了
最後の手順として、スクリプトは一時ファイルの作業フォルダーを削除し、言語パックとオンデマンドの機能の 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!"