WinPEからWindows 11セットアップを自動化すると、毎回ドライブレターの並びが変わってしまい、スクリプトが失敗する――そんな経験はないでしょうか。本記事では、WinPE経由のセットアップで「CATUD → CGDEF」のようにレターが勝手に入れ替わる理由と、その根本対策を、winpeshl.ini と AutoUnattend.xml(応答ファイル)を軸に詳しく解説します。
WinPEでWindows 11セットアップ時にドライブレターが変わる理由
まず、今回の事象を整理します。
- boot.wim に必要なファイル一式を入れ、WinPE から Windows 11 セットアップを実行した
- パーティションのドライブレターが、想定していた CATUD ではなく、実際には CGDEF のように変わってしまう
- その結果、スクリプト内で指定しているドライブレターと実際のドライブレターが合わず、処理に失敗する
この現象の本質は、Windows セットアップ/WinPE 環境における「ドライブレターは固定ではなく動的に割り当てられる」という仕様にあります。
WinPEのドライブレター割り当ての特徴
WinPE と通常のインストール済み Windows では、同じディスク構成でもドライブレターの付き方が変わることがあります。主な理由は次の通りです。
- デバイスの検出順序(HDD/SSD、USBメモリ、光学ドライブなど)
- パーティション種別(EFI/MSR/基本/回復/リムーバブルなど)
- ブート属性やシステムパーティションであるかどうか
- マウントのタイミング(wpeinit 前後など)
さらに、WinPE では通常 X: が RAM ディスクとして予約されるため、C: から順番に割り振られるとは限りません。結果として、
- WinPE 中:D: が OS 用パーティション、E: がデータ用、F: が別ディスク…
- インストール後:C: が OS、D: がデータ…
のように、セットアップ中とインストール後でドライブレターが一致しない状況が普通に発生します。
| 環境 | 典型的なシステムドライブ | ドライブレターの安定性 |
|---|---|---|
| WinPE(boot.wim 起動) | X:(RAMディスク) | 低い(毎回変わり得る) |
| インストール後のWindows 11 | C:(OSパーティション) | 比較的高い(C: はほぼ固定) |
このため、「WinPE上で C ドライブだったから、本番 Windows でも C になるはずだ」といった期待は、基本的に成り立ちません。
なぜ「CATUD → CGDEF」のような変化が起きるのか
今回のように、CATUD という順番でレターを決めたつもりが、実際には CGDEF になってしまうケースでは、次のような要素が影響していることが多いです。
- USB メモリや別ディスクが先にマウントされ、想定より早いレターを奪う
- 光学ドライブ(物理/仮想)が D: を取りに来る
- 以前のアサインが残っていて、DiskPartの
assign letter=が失敗している - wpeinit 前にスクリプトを走らせてしまい、まだボリュームが出揃っていない
つまり、OS任せにしている限りレターは「勝手に変わる」ものであり、スクリプトで確実に扱いたければ、こちらから明示的にルールを押し付ける必要があるということです。
対策の全体像:3つのアプローチ
WinPE 経由の Windows 11 セットアップでドライブレター問題を回避するための代表的なアプローチは次の3つです。
- winpeshl.ini または startnet.cmd からスクリプトを起動し、セットアップ前にレターを強制割り当て
- AutoUnattend.xml(応答ファイル)の DiskConfiguration / ModifyPartition でレターを指定
- そもそもスクリプトを「ドライブレターに依存しない構造」にする
| 方法 | 実装場所 | メリット | 向いているケース |
|---|---|---|---|
| WinPEスクリプト | winpeshl.ini / startnet.cmd | 手軽、メディア単体で完結 | カスタムWinPEメディアを配布している場合 |
| 応答ファイル | AutoUnattend.xml(windowsPE パス) | 構成の一元管理がしやすい | 既に応答ファイル運用をしている環境 |
| レター非依存設計 | スクリプト本体 | 環境差に強く、長期運用向き | 多数拠点・長期運用を前提とする企業環境 |
実務的には、
- パーティションの作成とラベル付けは AutoUnattend.xml で行う
- WinPE 起動直後に winpeshl.ini からラベルに基づいてレターを再割り当てする
という二段構えが、管理しやすく再現性も高い構成です。
winpeshl.iniでセットアップ前にドライブレターを固定する
もっとも分かりやすい対策は、boot.wim 内にスクリプトと winpeshl.ini を配置し、setup.exe を起動する前にレターを決め打ちする方法です。
boot.wim をマウントしてスクリプトを配置する
作業用PC(管理端末)で、以下のように boot.wim をマウントします。
REM 作業用フォルダは環境に合わせて変更
dism /Mount-Wim /WimFile:C:\WinPE\media\sources\boot.wim /Index:1 /MountDir:C:\Mount
mkdir C:\Mount\Windows\System32\Scripts
copy C:\Work\SetDriveLetters.cmd C:\Mount\Windows\System32\Scripts\
notepad C:\Mount\Windows\System32\winpeshl.ini
ここでは例として、DiskPart ベースの SetDriveLetters.cmd を配置するものとします。
winpeshl.ini の例:wpeinit → スクリプト → setup.exe の順で起動
WinPEでは通常、X: がシステムドライブとしてマウントされます。winpeshl.ini には次のように記述します。
[LaunchApps]
wpeinit
X:\Windows\System32\Scripts\SetDriveLetters.cmd
X:\setup.exe
- 1 行につき 1 コマンド
- wpeinit でデバイス初期化 → スクリプト実行 → Windows セットアップの流れ
- スクリプト内でドライブレターを CATUD など目的の配列に整えてから、
setup.exeを起動
DiskPart版スクリプト:パーティション番号ベースでレターを付ける
もっともシンプルなのが DiskPart スクリプトです。
SetDriveLetters.cmd(例)
@echo off
diskpart /s X:\Windows\System32\Scripts\letters.txt
letters.txt(例:Disk 0 の Part.1〜5 を C A T U D に割り当て)
select disk 0
select partition 1
assign letter=C
select partition 2
assign letter=A
select partition 3
assign letter=T
select partition 4
assign letter=U
select partition 5
assign letter=D
注意点:
- 実際の構成に合わせて「どのパーティションにどのレターを振るか」を調整する
- UEFI構成では、EFI/MSR/回復用パーティションには通常レターを付けないほうが良い
- 既に他デバイスが同じレターを使用している場合、
assignが失敗するため、先に別レターに退避させる等の工夫が必要
PowerShell版スクリプト:ボリュームラベル基準で割り当てる
より堅牢な方法は、ボリュームラベルで対象を特定してレターを振り直すやり方です。これにより、パーティション番号やディスク順序が多少変わっても耐えられます。
前提:
- WinPE イメージに WinPE-PowerShell コンポーネントを追加していること(ADK で追加)
X:\Windows\System32\Scripts\SetDriveLetters.ps1(例)
$map = @{
'OS' = 'C' # ラベル "OS" のボリューム → C:
'APPS' = 'A'
'TEMP' = 'T'
'USER' = 'U'
'DATA' = 'D'
}
foreach ($kv in $map.GetEnumerator()) {
$label = $kv.Key
$letter = $kv.Value
$vol = Get-Volume -FileSystemLabel $label -ErrorAction SilentlyContinue
if ($null -eq $vol) {
Write-Host "Volume with label $label not found."
continue
}
$part = $vol | Get-Partition
Set-Partition -DiskNumber $part.DiskNumber -PartitionNumber $part.PartitionNumber -NewDriveLetter $letter -ErrorAction Stop
Write-Host "Assigned $letter: to volume $label"
}
このスクリプトを winpeshl.ini から呼び出す例は次の通りです。
[LaunchApps]
wpeinit
powershell.exe -ExecutionPolicy Bypass -File X:\Windows\System32\Scripts\SetDriveLetters.ps1
X:\setup.exe
ポイント:
- 応答ファイルや別スクリプトで、事前に各パーティションにラベル(OS/APPS/USER/DATA など)を付けておく
- スクリプトは「ラベル → レター」のマッピングだけを担当するので、構成変更に強い
- ログを
X:\logs\drive-letter.logのように出力しておくと検証が楽
boot.wim を閉じて変更を確定する
編集が終わったら、boot.wim をアンマウントします。
dism /Unmount-Wim /MountDir:C:\Mount /Commit
これで、作成した WinPE メディアから起動すると、setup.exe が動き出す前にドライブレターが期待通りにそろうようになります。
AutoUnattend.xml(応答ファイル)でドライブレターを制御する
既に応答ファイル(AutoUnattend.xml)でディスク構成を管理している環境では、windowsPE パスの DiskConfiguration / ModifyPartition でレターを指定する方法も有効です。
以下は構造イメージです(実際の XML では名前空間や wcm 属性などが必要です)。
<unattend>
<settings pass="windowsPE">
<component name="Microsoft-Windows-Setup">
<DiskConfiguration>
<Disk wcm:action="add">
<DiskID>0</DiskID>
<WillWipeDisk>true</WillWipeDisk>
<ModifyPartitions>
<ModifyPartition wcm:action="add">
<Order>1</Order>
<PartitionID>3</PartitionID> <!-- 例:OS パーティション -->
<Label>OS</Label>
<Letter>C</Letter>
<Format>NTFS</Format>
</ModifyPartition>
<ModifyPartition wcm:action="add">
<Order>2</Order>
<PartitionID>4</PartitionID> <!-- データ用パーティション -->
<Label>DATA</Label>
<Letter>D</Letter>
<Format>NTFS</Format>
</ModifyPartition>
</ModifyPartitions>
</Disk>
</DiskConfiguration>
<RunSynchronous>
<RunSynchronousCommand wcm:action="add">
<Order>1</Order>
<Path>cmd /c X:\Windows\System32\Scripts\SetDriveLetters.cmd</Path>
</RunSynchronousCommand>
</RunSynchronous>
</component>
</settings>
</unattend>
ポイント:
- windowsPE パスで DiskConfiguration を設定すると、インストール開始前にディスク構成が確定する
- OSパーティション(C:)、データパーティション(D:)など、基本レターをここで決めておくと分かりやすい
- それでも WinPE 中の一時的なレターが気になる場合は、RunSynchronous からスクリプト(SetDriveLetters.cmd)を呼び出して再調整する
応答ファイルでレターを制御する際の注意点
- WillWipeDisk=true の指定は、既存データが削除されるため本番環境に適用する前に必ず検証環境でテストする
- PartitionID は CreatePartitions の定義と対応している必要がある
- EFI/MSR/回復パーティションには通常レターを割り当てない(トラブルの元になる)
- OSパーティションは基本的に C: にしておくことで後工程の運用が楽になる
winpeshl.ini と AutoUnattend.xml、どちらに書くべきか
「どこに書くのが正解か?」という問いに対しては、用途によって使い分けるというのが実務的な答えになります。
| 観点 | winpeshl.ini | AutoUnattend.xml |
|---|---|---|
| 適用タイミング | WinPE起動直後 | セットアップ処理(windowsPEパス) |
| 構成管理 | メディア単位(boot.wimごと) | XMLファイルで一元管理しやすい |
| 変更のしやすさ | boot.wim の再マウントが必要 | XML を差し替えるだけでよい場合が多い |
| おすすめ用途 | 簡易ツール、単独メディア運用 | 企業内標準イメージ、長期運用 |
まとめると、
- メディア単体で完結させたい・構成がシンプル → winpeshl.ini で [LaunchApps] に記述
- 既に応答ファイルでディスク設計を管理している → AutoUnattend.xml の windowsPE/RunSynchronous からスクリプトを呼ぶ
いずれの場合も、ゴールは同じで、「setup.exe を動かす前にドライブレターを確定させる」ことです。
スクリプト設計のベストプラクティス
ドライブレター問題を根本から安定させるには、スクリプト側の設計も重要です。以下のポイントを押さえておくと、環境差に強い構成になります。
ドライブレターに過度に依存しない
- 対象ボリュームの指定は、パーティション番号やレターではなく、ラベルや GPT タイプ、Volume GUID で行う
- 最終的にユーザーが使うドライブレターだけを、最後に
Set-Partition -NewDriveLetterで付与する
例えば、PowerShell から GPT タイプで OS パーティションを見つけて C: にする、というようなアプローチも可能です(例は簡略版)。
$osPart = Get-Partition | Where-Object {
$_.GptType -eq "{EBD0A0A2-B9E5-4433-87C0-68B6B72699C7}" -and
$_.IsBoot -eq $true
}
if ($null -ne $osPart) {
Set-Partition -DiskNumber $osPart.DiskNumber -PartitionNumber $osPart.PartitionNumber -NewDriveLetter "C"
}
A/B ドライブは特別扱いに注意
- 最新の Windows では A: / B: にもレターを割り当て可能ですが、古いツールやスクリプトがフロッピーディスクを想定していることがあります
- 業務利用では、C/D/E… の一般的な並びを使う方がトラブルが少ない
光学ドライブとの競合を考慮する
- 物理/仮想の光学ドライブは、よく D: を取りに来ます
- データ用パーティションを D: にしたい場合は、光学ドライブのレターを先に Z: などに退避させると安定します
select volume <光学ドライブのボリューム番号>
assign letter=Z
EFI/MSR/回復パーティションにはレターを付けない
- これらのパーティションにドライブレターを付けると、誤操作で中身を消してしまうリスクが高まります
- 通常は「レターなし」が正解です。どうしても必要なときだけ、一時的に付与して作業後に削除するようにします。
ログ出力とエラー処理を入れておく
- スクリプトのログを X:\Logs\ やインストール先ディスク上に出力すると、原因調査が圧倒的に楽になります
- PowerShell では
-ErrorAction Stopとtry / catchを組み合わせ、失敗時にメッセージを残すようにしておきましょう
トラブルシューティング:思った通りにレターが付かない場合
「CATUD のはずが CGDEF になってしまう」といった場合、次の手順で原因を切り分けます。
WinPE 上で DiskPart の状況を確認する
WinPE のコマンドプロンプトから、以下を順番に実行します。
diskpart
list disk
list volume
list partition
- どのディスク/ボリュームにどのレターが付いているか
- EFI/回復パーティションにレターが付いてしまっていないか
- 光学ドライブや USB が想定外のレターを確保していないか
を確認します。
スクリプトが実際に実行されているか確認する
winpeshl.iniのパスやファイル名の typo がないか- PowerShell スクリプトの場合、ExecutionPolicy でブロックされていないか
- ログファイルが出力されているか(出ていなければそもそも呼ばれていない可能性)
テストとして、WinPE 上で手動で以下を実行し、同じ結果になるかを確認するのも有効です。
X:\Windows\System32\Scripts\SetDriveLetters.cmd
REM もしくは
powershell.exe -ExecutionPolicy Bypass -File X:\Windows\System32\Scripts\SetDriveLetters.ps1
AutoUnattend.xml の DiskConfiguration を見直す
- PartitionID と実際のパーティション番号の対応が崩れていないか
- 複数ディスク環境で DiskID の指定が期待通りか
- ModifyPartitions の Order が重複していないか
構成変更のたびに PartitionID がずれてしまうようであれば、構成をシンプルに整理するか、ラベルベースのスクリプトへ寄せることを検討してください。
実運用でのおすすめ構成例
中〜大規模環境での運用を想定して、現実的な構成例を示します。
パーティション構成の一例(UEFI/GPT)
| 順番 | 用途 | サイズ目安 | ラベル例 | 最終レター | 備考 |
|---|---|---|---|---|---|
| 1 | EFI システム | 100〜300MB | EFI | なし | ブート用、レター不要 |
| 2 | MSR | 16MB | MSR | なし | レター不要 |
| 3 | OS | 100GB〜 | OS | C: | Windows 11 本体 |
| 4 | データ | 残り全て | DATA | D: | ユーザーデータ・アプリデータ |
| 5 | 回復 | 500MB〜1GB | Recovery | なし | レター不要 |
構成例:AutoUnattend.xml + winpeshl.ini の二段構え
- AutoUnattend.xml で上記のようなパーティション構成とラベルを定義
- WinPE 起動時に winpeshl.ini の [LaunchApps] から PowerShell スクリプトを起動
- スクリプトは「ラベル → レター」のマッピング(OS→C, DATA→D…)だけを行う
こうすることで、
- ディスク容量や構成の変更は AutoUnattend.xml を修正
- レターの割り当てルールの変更は PowerShell スクリプトを修正
と、役割を分離して管理しやすくなります。
まとめ:WinPEではドライブレターは「勝手に変わる」前提で設計する
本記事で扱ったポイントを改めて整理します。
- WinPE/セットアップ環境では、ドライブレターは環境や起動ごとに変動するのが前提仕様
- 「CATUD → CGDEF」のような変化は珍しいことではなく、OS の挙動として正しい範囲
- ドライブレターを安定させるには、setup.exe を起動する前に、スクリプトで明示的にレターを割り当てる必要がある
- その実装場所として、winpeshl.ini と AutoUnattend.xml(RunSynchronous) が選択肢になる
- スクリプトの内部では、レターよりラベル/GPTタイプ/Volume GUID で対象を特定する設計が再現性が高い
- インストール後には、ディスクの管理や DiskPart で最終的なレターを確認し、必要に応じて光学ドライブなどとの競合を解消する
この流れを組んでおけば、質問にあったような任意のレター配列(CATUD など)でも、WinPE 経由の Windows 11 自動展開で安定して再現できるようになります。ドライブレターを「たまたま」ではなく、「設計どおり」に制御できるようになれば、その上に乗るスクリプトや運用も大幅にシンプルになるはずです。

コメント