Files
windows-unattend/SUMMARY.md
Timmy b1e5b6912a unattend.xml 直接以 User(首字大寫)建帳號;Setup.ps1 拿掉 rename-LocalUser
把 Order 3 的 net user 命令直接寫成 net user User,省掉「先建小寫 user 再
Rename-LocalUser 改成大寫 User」這個迂迴。Setup.ps1 的 rename-hide-accounts
段同時改名為 hide-admin-account,內容只剩設 SpecialAccounts\\UserList\\Admin=0
這一行——隱藏 Admin 仍然由 Setup.ps1 負責。

文件全部同步:DEPLOY/QUICKSTART/SUMMARY/README/CLAUDE 把「先建小寫再改名」的
bulletproof 解釋與相關段名都拿掉。

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

8.1 KiB
Raw Permalink 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 → net accounts                     (一行搞定的雜事直接 cmd密碼永不過期
Order 2 → Rename-Computer                  (主機名改 PC-XXXXX重開後生效
Order 3 → net user User 1234 /add          (建立一般使用者 User強制首次登入改密
Order 4 → Copy Setup.ps1 from Ventoy USB   (掃磁碟找 \ventoy\script\Setup.ps1 → C:\Scripts\
Order 5 → powershell -File Setup.ps1       13 段 post-install看下表
Order 6 → shutdown /r                      (重開機收尾,讓 rename 生效)

Setup.ps1 內部分兩個 phase用空的 wait-network 段切開):

[Phase 1本機設定不需網路]
firewall-ssh-22                  → SSH 22/TCP inbound 防火牆規則
rdp-enable-3389                  → 啟用 RDP + 3389 防火牆群組
icmp-echo-allow                  → ICMPv4 Echo Request inbound外部 ping 得到)
winrm-enable                     → Enable-PSRemoting + winrm quickconfig + TrustedHosts=*
onedrive-remove                  → /uninstall + 清啟動鍵 + 移除 CLSID
cortana-websearch-off            → AllowCortana=0、DisableWebSearch=1、SearchBoxSuggestions=1
apply-ui-ime-default-profile     → reg load Default profile套 Dark mode / 工作列靠左 / 顯示副檔名 / 預設英數鍵盤 / 停 IME 切換熱鍵
hide-admin-account               → 從登入畫面隱藏 Admin帳號仍存在仍可用

[Phase 2需要網路]
wait-network                     → 等 ICMP 通到 8.8.8.8,上限 60 秒
openssh-server-install           → Add-WindowsCapability OpenSSH.Server + Start-Service sshd
kms-activate                     → 試 $InternalKmsServers → $PublicKmsServers第一個 successful 就停
winget-install-chrome            → winget install Google.Chrome --silent --scope machine
remove-windows-ai                → irm zoicware/RemoveWindowsAI | iex -nonInteractive -AllOptions
win11debloat                     → 下載 Raphire/Win11Debloat → -Silent -Config
remove-uwp-apps                  → 22 個 AppxPackageBingNews、Xbox*、MSTeams、Photos…
install-telegram                 → 下載 telegram.org/dl/desktop/win64 + /VERYSILENT
cleanup-unattend-files           → 刪 C:\Windows\Panther\unattend.xml清明碼密碼殘留

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

為什麼把 Setup.ps1 放在 Ventoy USB 上、不直接 base64 內嵌進 unattend.xml(1) unattend.xml 仍是 Windows SIM 可驗證的純 schema XML(2) Setup.ps1 改完只要 cp 一次就更新,不用重 escape(3) 每段 Section 寫到 setup.log 才方便排查。代價是USB 必須留到第一次登入完成才能拔。

remove-windows-ai 跑的是 main 分支的腳本,每次部署抓的版本可能不同。要確定性、可稽核的部署,把 Setup.ps1 中對應 URL 的 /main/ 換成 commit SHA。


為什麼分成三個 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 用磁碟掃描從 Ventoy USB 拷貝 不需要架網路服務、跨網段也能跑、USB 拔掉也能在現場補救 內部 IT 場合改用 SCCM/Intune 派送,或乾脆 base64 內嵌進 XML 拿到完全自包含
$PublicKmsServers 用第三方 KMS 沒授權主機也能跑通 $InternalKmsServers 改成自家 KMS 主機,公開那串不再被 fallback

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


對話的起點

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

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

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

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