# SUMMARY — 這份 unattend.xml 是怎麼長出來的 ## 為什麼需要它 手動裝一台 Windows 是這樣的:按「下一步」、選語系、接受 EULA、分割磁碟、填序號、建帳號、略過 OOBE 一堆隱私問題、登入後開 PowerShell 裝軟體。一台大約 20–30 分鐘,十台就是半天。**而且每次點的選項還不一定一樣。** 部署這件事的本質是:**把「一次性的人工操作」變成「可重複的檔案」。** 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 裡設 `*` 讓 Windows Setup 先給一個隨機名(否則 specialize 階段會因為 `%RAND:5%` 之類的假巨集字面送入而失敗),再由 `FirstLogonCommands` 的 `Rename-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 → Rename-Computer (主機名改 PC-XXXXX,重開後生效) Order 4 → Telegram 靜默安裝 (下載 tsetup.exe + /VERYSILENT) Order 5 → shutdown /r (重開機收尾,讓 rename 生效) ``` 這讓 `unattend.xml` 保持「只負責 Windows 本身的安裝」,其他事情外包給腳本。職責分離之後,改軟體清單不需要動 XML,改部署流程也不需要動 Setup 邏輯。 > Telegram 這條是「交棒到腳本」這條原則的例外:**單一套件、需求穩定**的情況下,直接在 `FirstLogonCommands` 裡下載安裝比起硬塞進 `Setup.ps1` 單純。一旦要裝的東西變成清單(3+ 個套件、要版本鎖定、要錯誤處理),就該整批移進 `Setup.ps1` 或改用 winget/choco。 --- ## 為什麼分成三個 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 長這樣。** 以後如果要改,知道每條線在撐著什麼,就不會拆錯地方。