Files
windows-unattend/SUMMARY.md
Timmy e106d749c7 修正兩處實機部署失敗的 XML bug;新增 DEPLOY.md 紀錄本機 USB 部署
- 根元素加上 xmlns:wcm / xmlns:xsi 命名空間宣告,否則全檔 wcm:action 無法解析(第 27 行第 9 欄即炸)
- ComputerName 改用 *,隨機後綴改由 FirstLogonCommands 的 Rename-Computer 產生;原本 PC-%RAND:5% 並非 Windows Setup 內建巨集,字面送入導致 specialize 階段 Shell-Setup 失敗
- 同步更正 CLAUDE.md / SUMMARY.md 對 %RAND:5% 的錯誤說明
- 新增 DEPLOY.md:/Volumes/Ventoy 的實際檔案佈局與重建步驟

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-22 18:59:35 +08:00

5.1 KiB
Raw Blame History

SUMMARY — 這份 unattend.xml 是怎麼長出來的

為什麼需要它

手動裝一台 Windows 是這樣的:按「下一步」、選語系、接受 EULA、分割磁碟、填序號、建帳號、略過 OOBE 一堆隱私問題、登入後開 PowerShell 裝軟體。一台大約 2030 分鐘,十台就是半天。而且每次點的選項還不一定一樣。

部署這件事的本質是:把「一次性的人工操作」變成「可重複的檔案」。

Windows 給的答案叫 Answer File(回應檔,通常是 unattend.xml)。開機時 Setup 會去讀這份 XML把原本需要人類回答的問題一題一題自己答完。


設計的三條主線

這份 unattend.xml 不是隨便把欄位湊齊,而是圍繞三個目標組出來的:

1. 零互動Zero Touch

從 USB 開機到桌面出現,中間不應該有任何畫面需要鍵盤滑鼠

為了做到這件事,檔案裡有一連串「否決畫面」的開關:

  • HideEULAPage / HideOEMRegistrationScreen / HideOnlineAccountScreens / HideWirelessSetupInOOBE — 把 OOBE 那些煩人的頁面全部隱藏
  • SkipMachineOOBE / SkipUserOOBE — 機器層與使用者層的 OOBE 都略過
  • AcceptEula=true — 安裝時的授權合約預先接受
  • WillShowUI=OnError on ProductKey — 序號正確就不跳視窗,錯了才問

這些不是可有可無的選項,而是「零互動」這個目標的具體落實。

2. 確定性Deterministic

同一份 unattend.xml 套上去,結果應該一樣。

  • 磁碟分割是硬寫的:清空 Disk 0 → EFI 500 MB → MSR 128 MB → 剩下全給 Windows。不讓 Setup 自己猜,不處理遷移場景。
  • 語系/時區是硬寫的zh-TW + Taipei Standard Time。不依賴 OEM image 預設。
  • 唯一的例外是電腦名稱XML 裡設 <ComputerName>*</ComputerName> 讓 Windows Setup 先給一個隨機名(否則 specialize 階段會因為 %RAND:5% 之類的假巨集字面送入而失敗),再由 FirstLogonCommandsRename-Computer 把它改成 PC-XXXXX 格式並在收尾 shutdown /r 時一起生效。

這是一個取捨:確定性優先,但在會造成衝突的地方(主機名)讓步。

3. 交棒到腳本Hand-off to Scripts

XML 能做的事有上限。超過這條線(裝軟體、設 Registry、拉 Git repo、裝驅動就不該硬塞 XML應該交給 PowerShell。

FirstLogonCommands 就是交棒點:

Order 1 → Setup.ps1    (所有「後續設定」都塞這裡)
Order 2 → net accounts (一行搞定的雜事直接 cmd
Order 3 → shutdown /r  (重開機收尾)

這讓 unattend.xml 保持「只負責 Windows 本身的安裝」,其他事情外包給腳本。職責分離之後,改軟體清單不需要動 XML改部署流程也不需要動 Setup 邏輯。


為什麼分成三個 Pass

Windows Setup 有七個 pass本檔只用三個。不是偷懶三個 pass 對應三個時機,各自只能做某些事:

Pass 時機 此時系統長什麼樣 只能在這裡做的事
windowsPE 從 USB 開機、Windows 還沒裝 記憶體中的迷你作業系統 磁碟分割、選要裝哪個映像、產品序號
specialize 映像展開完、第一次開機前 C:\ 已存在但沒有使用者 電腦名稱、加網域、硬體相關
oobeSystem 首次開機、OOBE 跑起來時 完整 Windows、等使用者建帳號 建本機帳號、AutoLogon、FirstLogonCommands

每個欄位都有「必須」出現的 pass放錯地方 Windows 就不讀。 語系要在 windowsPE 設(給 WinPE 用)也要在 oobeSystem 設(給 OOBE 用)——這就是為什麼 International-Core 在檔案裡出現兩次,不是冗餘。


妥協的地方

幾個「明知道不理想、但為了能動先這樣」的決定:

妥協 為什麼這樣 正式環境怎麼改
密碼明碼 方便第一次測試,看得懂 用 Windows SIM 產生 Base64或交給 MDT/SCCM 管
本機帳號 + AutoLogon 純離線可跑 改成 Domain Join + 網域管理員登入
ProtectYourPC=3 略過 OOBE 的隱私頁,預設行為 依公司政策調整,或用 GPO 蓋掉
單一 Disk 0 + 整碟清空 對測試 VM 最安全的假設 多硬碟環境要加 DiskID 判斷邏輯
*Setup.ps1 路徑硬寫 C:\Scripts* 簡單 改從 USB/網路拉,或用 MDT 的 Applications 機制

這些不是 bug當前脈絡下的合理起點。要產品化就對照這張表一個一個升級。


對話的起點

這份檔案最初是從一個問題開始的:

「透過回應檔案Answer files通常檔名為 unattend.xml來自動化配置 Windows 安裝設定。自動處理像是語系選擇、建立使用者帳號、輸入序號,甚至是執行自定義的腳本。」

答案就是上面講的那套設計。剩下的事(產 USB、跑 VM、除錯都寫在 QUICKSTART.md,每個欄位做什麼事寫在 README.md

這份 SUMMARY.md 只想講一件事:為什麼這份 XML 長這樣。 以後如果要改,知道每條線在撐著什麼,就不會拆錯地方。