Compare commits
7 Commits
935cddbbf2
...
main
| Author | SHA1 | Date | |
|---|---|---|---|
| 6173ef90a5 | |||
| 2b6ae854f9 | |||
| a7975343c3 | |||
| 22e002d444 | |||
| ff796ff299 | |||
| 8fdce82737 | |||
| 29c6ddf982 |
@@ -176,6 +176,7 @@ Shift + F10 在任何安裝畫面會開出命令提示字元,可以 `notepad`
|
||||
|
||||
| 現象 | 原因 | 解法 |
|
||||
|---|---|---|
|
||||
| Ventoy 一啟動就跳 `Verification failed: (0x1A) Security Violation` | 目標機(ThinkPad / Dell 商用機常見)BIOS 開著 Secure Boot,Ventoy bootloader 不在受信任金鑰裡被 shim 擋下 | 進 BIOS(ThinkPad 是 F1)→ Security → Secure Boot → Disabled → F10 存檔 → 重開 F12 重選 USB |
|
||||
| Ventoy 沒跳「Auto Install Template」選單 | `ventoy.json` 的 `image` 路徑對不上 ISO 實際路徑 | 路徑以 `/` 開頭、相對 USB 根目錄;或改用 fuzzy / `parent` 比對 |
|
||||
| 跳了選單但跳過後仍停在選語系畫面 | `unattend.xml` 路徑錯誤或 XML schema 有誤 | 用 Windows SIM 驗證 XML;確認 `template` 指到的檔案真的存在 |
|
||||
| 磁碟分割失敗或裝到 Ventoy USB 上 | `DiskID` 挑到 Ventoy USB | 確認用的是 `$$VT_WINDOWS_DISK_1ST_NONVTOY$$`,不是硬寫 `0`;多硬碟環境可改用 `$$VT_WINDOWS_DISK_MAX_SIZE$$` |
|
||||
|
||||
269
REINSTALL.md
Normal file
269
REINSTALL.md
Normal file
@@ -0,0 +1,269 @@
|
||||
# REINSTALL — Windows 重灌完整流程
|
||||
|
||||
從 macOS 同步 USB 到目標機開機部署完成、能 SSH 進去為止的全套程序。
|
||||
失敗也涵蓋:插 USB 雙擊 `_admin-shell.bat` 手動把 17 段跑完。
|
||||
|
||||
> 概念與單一檔案說明請看 `QUICKSTART.md` / `SUMMARY.md` / `DEPLOY.md`。
|
||||
> 這份是 **照著做就會 work** 的清單。
|
||||
|
||||
---
|
||||
|
||||
## TL;DR — 正常情境
|
||||
|
||||
1. 插 Ventoy USB → 開機 → 選 Win11 ISO(或 Win10)+ `unattend.xml`
|
||||
2. 等 ~15-25 分鐘(OOBE 跳過 → AutoLogon Admin → `Setup.ps1` 跑 17 段 → reboot)
|
||||
3. 登入畫面選 **User**(Admin 已被 SpecialAccounts 隱藏,要用打字輸入帳號名仍可進)
|
||||
4. **User 預設空密碼**,按 Enter 登入時系統會強制設定新密碼
|
||||
5. **桌面已套好**:黑暗模式、工作列靠左、本機+控制台+資源回收筒、Telegram + Chrome 捷徑
|
||||
|
||||
從 Mac 確認:
|
||||
|
||||
```bash
|
||||
ssh User@<windows-ip> # 22 通了代表 Setup.ps1 跑到 step 10 以後
|
||||
# 或開 Microsoft Remote Desktop 連 <windows-ip>:3389
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Stage 0 — Mac 端準備 USB
|
||||
|
||||
確認 repo `main` 是最新,然後一次同步:
|
||||
|
||||
```bash
|
||||
cd ~/Projects/Personal/windows-unattend
|
||||
|
||||
# USB 掛載點通常是 /Volumes/Ventoy
|
||||
ls /Volumes/Ventoy
|
||||
|
||||
# 同步全部到 USB
|
||||
USB=/Volumes/Ventoy/ventoy/script
|
||||
mkdir -p "$USB/steps"
|
||||
cp unattend.xml Setup.ps1 Run-Setup.bat "$USB/"
|
||||
cp -r steps/* "$USB/steps/"
|
||||
|
||||
# 清掉 macOS 寫的 ._ AppleDouble 檔(Ventoy 會抓錯)
|
||||
find /Volumes/Ventoy -name "._*" -delete 2>/dev/null
|
||||
find /Volumes/Ventoy -name ".DS_Store" -delete 2>/dev/null
|
||||
|
||||
# 退出磁碟(強制 unmount + eject 才能保證 flush)
|
||||
sync
|
||||
diskutil unmount force /Volumes/Ventoy
|
||||
diskutil eject /Volumes/Ventoy 2>/dev/null || diskutil eject /dev/disk2
|
||||
```
|
||||
|
||||
驗證 USB 上 `/ventoy/script/` 該有:
|
||||
|
||||
```
|
||||
unattend.xml
|
||||
Setup.ps1
|
||||
Run-Setup.bat
|
||||
steps/ (43 個檔:17 對 .bat/.ps1 + _common.ps1 + _admin-shell.bat
|
||||
+ _template.bat + RUN-ALL.bat + win11debloat-config.json + README.txt)
|
||||
```
|
||||
|
||||
> **改了任何 `.ps1`/`.bat`/`unattend.xml` 之後沒重新 cp = 部署到舊版本**。
|
||||
> 這是迄今最常見的失誤。
|
||||
|
||||
---
|
||||
|
||||
## Stage 1 — 目標機開機到第一次登入
|
||||
|
||||
插 USB → 開機 → BIOS 設 USB 優先 → Ventoy 選單。
|
||||
|
||||
> **首次部署到一台新機(特別是 ThinkPad / Dell 商用機)先確認 BIOS 設定**:
|
||||
>
|
||||
> - **Secure Boot 必須關閉**。Ventoy 的 bootloader 不在 Microsoft 預設信任金鑰清單裡,
|
||||
> Secure Boot 開著就會被 shim 擋下、跳 `Verification failed: (0x1A) Security Violation`,
|
||||
> USB 開機直接失敗。ThinkPad 進 BIOS 的步驟:
|
||||
> 1. 重開機按 **F1** 進 BIOS(部分機型是 Enter → F1)
|
||||
> 2. **Security → Secure Boot → Disabled**
|
||||
> 3. **F10** 存檔離開
|
||||
> 4. 重開後按 **F12** 選 `USB HDD: External USB3.0`(或對應 USB 名稱)進 Ventoy
|
||||
> - 其他可能要動的:CSM/Legacy Boot **關閉**(保持純 UEFI);Boot Order 把 USB 放到 HDD 之前;
|
||||
> 有些機種需要先 disable BitLocker 否則裝完原系統開不回來(這份範本反正會清碟,不影響)。
|
||||
|
||||
| 步驟 | 預期畫面 | 大約時間 |
|
||||
|---|---|---|
|
||||
| Ventoy 選單 | 選 Win11 ISO(會顯示 menu_tip) | — |
|
||||
| Auto Install Template 選單 | 選 `unattend.xml` | — |
|
||||
| WinPE 起動 | Windows 標誌 | 30-60 秒 |
|
||||
| 磁碟分割 + 映像展開 | 「正在安裝 Windows」百分比 | 5-15 分鐘 |
|
||||
| 第一次重開 | 黑屏 → 「請稍候」 | 1-2 分鐘 |
|
||||
| OOBE | **不該有任何畫面**直接跳過 | 秒殺 |
|
||||
| AutoLogon Admin | 桌面顯示 `Administrator` | — |
|
||||
| FirstLogonCommands | 黑色 cmd / PowerShell 視窗閃過 6 條 | — |
|
||||
| Setup.ps1(17 段) | 視窗持續顯示 `=== xxx START/DONE ===` | 5-15 分鐘 |
|
||||
| 第二次重開 | `shutdown /r /t 5` 倒數重啟 | — |
|
||||
| 第二次開機完成 | 登入畫面顯示 **User** 一個帳號 | — |
|
||||
|
||||
**FirstLogonCommands 6 條**(按 Order):
|
||||
|
||||
| Order | 動作 |
|
||||
|---|---|
|
||||
| 1 | `net accounts /maxpwage:unlimited`(密碼永不過期) |
|
||||
| 2 | `Rename-Computer PC-XXXXX`(重開後生效) |
|
||||
| 3 | `net user User /add` + `/logonpasswordchg:yes` + `net localgroup Administrators User /add`(建立 User 帳號、加入管理員、空密碼、首次登入強制改密) |
|
||||
| 4 | 掃所有掛載碟找 `\ventoy\script\Setup.ps1`,拷到 `C:\Scripts\Setup.ps1`(log: `firstlogon-copysetup.log`) |
|
||||
| 5 | `cmd /c (echo …& if exist Setup.ps1 (powershell -File ...) else (echo SETUP_NOT_FOUND)) > firstlogon-runsetup.log 2>&1`(**所有 stderr/stdout 都收進 log**) |
|
||||
| 6 | `shutdown /r /t 5` |
|
||||
|
||||
**Setup.ps1 的 17 段**(按執行順序,全部寫到 `C:\Windows\Temp\setup.log`):
|
||||
|
||||
```
|
||||
Phase 1(不需網路) Phase 2(需網路,wait-network 後)
|
||||
───────────────────────── ─────────────────────────────────
|
||||
00 network-private (內嵌在 04 開頭)
|
||||
01 firewall-ssh-22 10 openssh-server-install
|
||||
02 rdp-enable-3389 11 kms-activate
|
||||
03 icmp-echo-allow 12 winget-install-chrome
|
||||
04 winrm-enable 13 remove-windows-ai
|
||||
05 onedrive-remove 14 win11debloat
|
||||
06 cortana-websearch-off 15 remove-uwp-apps
|
||||
07 apply-ui-ime-default-profile 16 install-telegram (winget machine + 桌面捷徑)
|
||||
08 hide-admin-account 17 resume-trigger-wu
|
||||
09 pause-windows-update
|
||||
```
|
||||
|
||||
> 在原本的 `Setup.ps1` 單檔流程裡,這 17 段是直接內嵌的;`steps/` 目錄
|
||||
> 是同一份邏輯拆出來的 **手動可單獨執行版**,給 Recovery 用。兩邊只要改了
|
||||
> 都要記得同步另一邊(目前 17 段邏輯一致,差在 `Setup.ps1` 還包了
|
||||
> `wait-network` 一個共用區塊)。
|
||||
|
||||
---
|
||||
|
||||
## Stage 2 — User 第一次登入
|
||||
|
||||
1. 鎖定畫面點 **User**(不用打密碼直接 Enter)
|
||||
2. 系統跳「您的密碼必須變更」→ 輸入新密碼兩次 → Enter
|
||||
3. 進桌面,應該已經是:
|
||||
- **黑暗模式**
|
||||
- 工作列靠左(沒有 Search box / Task View)
|
||||
- 桌面圖示:本機、控制台、資源回收筒、Chrome、Telegram
|
||||
- 鍵盤切換英文第一、注音第二(不用按 Win+空白也是英文)
|
||||
- File Explorer 預設打開「本機」、有副檔名、有隱藏檔
|
||||
4. Telegram 雙擊應該能直接開(machine-wide 安裝、ACL 已修)
|
||||
|
||||
從 Mac 確認 SSH 通:
|
||||
|
||||
```bash
|
||||
ssh User@<windows-ip>
|
||||
# 進得去 = step 10 (openssh-server-install) 跟 step 02 (RDP firewall) 都 OK
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Recovery — 自動化跑掛了怎麼辦
|
||||
|
||||
三種主要失敗情境:
|
||||
|
||||
### A. `Setup.ps1` 本身連跑都沒跑
|
||||
|
||||
症狀:登入後 `C:\Windows\Temp\setup.log` 不存在。
|
||||
|
||||
檢查:
|
||||
|
||||
```powershell
|
||||
notepad C:\Windows\Temp\firstlogon-copysetup.log # 有沒有「OK from D:\...」一行?
|
||||
notepad C:\Windows\Temp\firstlogon-runsetup.log # Order 5 的全部 stdout/stderr
|
||||
Test-Path C:\Scripts\Setup.ps1 # 拷貝有沒有成功?
|
||||
```
|
||||
|
||||
| `firstlogon-copysetup.log` | 處置 |
|
||||
|---|---|
|
||||
| `OK from X:\...` | 拷成功,問題在 Setup.ps1 執行階段,看 `firstlogon-runsetup.log` 找原因 |
|
||||
| `NOT FOUND` | USB 在 OOBE 前被拔掉,或檔不在 `/ventoy/script/` —— 重新插上 USB 走 B |
|
||||
| 不存在 | FirstLogonCommands Order 4 整個沒跑,AutoLogon 可能沒成功 —— 看 `C:\Windows\Panther\setupact.log` |
|
||||
|
||||
### B. 雙擊 USB 上的 `Run-Setup.bat`(最快復原)
|
||||
|
||||
USB 插上 Windows,檔案總管進到 USB `\ventoy\script\`:
|
||||
|
||||
1. 雙擊 **`Run-Setup.bat`**
|
||||
2. UAC 跳(如果是 User 登入要打 Admin 密碼一次)
|
||||
3. 自動:UAC 提權 → 從 USB 重拷 Setup.ps1 → 跑 → 視窗即時印每段進度 → 結束按任意鍵關閉
|
||||
|
||||
跑完所有 log 同樣在 `C:\Windows\Temp\`:
|
||||
- `setup.log` —— Setup.ps1 自己的 START/DONE/ERR
|
||||
- `setup-stdout.log` —— Run-Setup.bat 收的全部 stdout/stderr(含 PowerShell parse error)
|
||||
|
||||
### C. 一段一段跑(最細的單元)
|
||||
|
||||
當你只想重跑某一段(例如 14 win11debloat 跑掛),用 `steps/` 目錄:
|
||||
|
||||
1. 進 USB `\ventoy\script\steps\`
|
||||
2. 雙擊 **`_admin-shell.bat`** → UAC 一次(之後不用再打密碼)
|
||||
3. 在開出來的提權視窗裡:
|
||||
```
|
||||
.\14-win11debloat.bat 單獨重跑某段
|
||||
.\RUN-ALL.bat 一次跑 18 段(00..17)
|
||||
```
|
||||
4. 每段都會印 `=== <name> START ... DONE ===` 到視窗 + 寫到 `C:\Windows\Temp\setup.log`
|
||||
|
||||
每段都是冪等的,重跑安全。
|
||||
|
||||
---
|
||||
|
||||
## 從 Mac 遠端管理(部署完成後)
|
||||
|
||||
| 服務 | Port | 工具 |
|
||||
|---|---|---|
|
||||
| ICMP | — | `ping <ip>` |
|
||||
| SSH | 22 | `ssh User@<ip>`(password 走 keyboard-interactive) |
|
||||
| RDP | 3389 | Microsoft Remote Desktop.app |
|
||||
| WinRM | 5985 | Python `pypsrp`(NTLM auth;Basic 設定可能因 Public profile 沒套上) |
|
||||
|
||||
WinRM 從 Mac 連的範例(無需 OpenSSH):
|
||||
|
||||
```python
|
||||
from pypsrp.client import Client
|
||||
c = Client('<ip>', username='Admin', password='<password>',
|
||||
ssl=False, auth='ntlm')
|
||||
out, _, _ = c.execute_ps('whoami; hostname; Get-Content C:\\Windows\\Temp\\setup.log -Tail 20')
|
||||
print(out)
|
||||
```
|
||||
|
||||
需要 `pip3 install pypsrp` 一次。
|
||||
|
||||
---
|
||||
|
||||
## 常見坑(修過的留個紀錄)
|
||||
|
||||
| 現象 | 根因 | 已修在 |
|
||||
|---|---|---|
|
||||
| Ventoy 一啟動就跳 `Verification failed: (0x1A) Security Violation` | 目標機(常見於 ThinkPad)BIOS 開了 Secure Boot,Ventoy bootloader 不在受信任金鑰中被 shim 擋下 | BIOS → Security → Secure Boot → Disabled → F10 存檔 → F12 重選 USB |
|
||||
| OpenSSH FoD 卡住 10+ 分鐘 | Add-WindowsCapability 真的就那麼慢,不是壞 | 等就好 |
|
||||
| RDP firewall 沒打開 | 某些 Win11 SKU 沒有 `Remote Desktop` display group | step 02 改顯式 New-NetFirewallRule |
|
||||
| WinRM `winrm quickconfig` 拒絕 | 網路被當成 Public profile | step 04 開頭 Set-NetConnectionProfile Private |
|
||||
| KMS 段噴 `{x,y}` regex error | `'successful|成功'` 的 UTF-8 中文被 ANSI 讀成 Big5 mojibake | step 11 改用 SoftwareLicensingProduct WMI |
|
||||
| winget Chrome 失敗 | msstore 來源憑證錯造成歧義 | step 12 加 `--source winget` |
|
||||
| RemoveAI 做到一半重啟 | `UpdateCleanupCheck` 跑 DISM repair → MessageBox → Session-0 default Yes | step 13 顯式 10 個 option 排除 UpdateCleanupCheck |
|
||||
| Win11Debloat reg.exe import 失敗 | `SearchSettings` key reg.exe 被「存取被拒」 | step 14 加 `-Sysprep` + 移掉 3 個衝突 tweak,改在 step 07 用 PS .NET API 直寫 |
|
||||
| Telegram 裝了 User 看不到 | Inno Setup `PrivilegesRequired=lowest` 強制 per-user | step 16 改用 winget `--scope machine` + Public Desktop 捷徑 |
|
||||
| Telegram 能看到不能點(沒有適當權限) | winget portable 解壓時 `Telegram\` 內層斷 ACL inheritance | step 16 加 `icacls /grant *S-1-5-32-545:RX /T` |
|
||||
| 中文 .bat REM 亂碼引發 `'券蠶setup.log' 不是內部命令` | cmd 用 Big5 codepage 讀 UTF-8 註解 | 全部 .bat REM 改 ASCII |
|
||||
| `.ps1` 中文字串 mojibake | PS 5.1 沒 BOM 時 fallback ANSI/Big5 | 全部 `.ps1` 加 UTF-8 BOM |
|
||||
|
||||
---
|
||||
|
||||
## Checklist — 每次重灌前
|
||||
|
||||
- [ ] repo 是 `main` 最新,本地沒 uncommitted 改動
|
||||
- [ ] USB 上 `unattend.xml` / `Setup.ps1` / `Run-Setup.bat` / `steps/` 都 sync 過
|
||||
- [ ] `unattend.xml` 的密碼 / Computer name / KMS 設定符合本次部署
|
||||
- [ ] 目標機是 **UEFI + GPT**(這份範本不支援 BIOS/MBR)
|
||||
- [ ] 目標機 BIOS **Secure Boot 已關閉**(ThinkPad 必踩;不關 Ventoy 直接跳 `Verification failed: (0x1A)`)
|
||||
- [ ] 目標機有網路(Ethernet+DHCP,或記住的 Wi-Fi)—— Phase 2 七段需要
|
||||
- [ ] 目標機 USB 開機優先順序最高
|
||||
- [ ] **USB 撐到第二次重開機進登入畫面才拔**(OOBE 太早拔,Order 4 找不到 Setup.ps1)
|
||||
|
||||
---
|
||||
|
||||
## Checklist — 部署完成後
|
||||
|
||||
- [ ] User 桌面已是黑暗模式 + 工作列靠左 + 本機/控制台圖示
|
||||
- [ ] Telegram、Chrome 雙擊能開
|
||||
- [ ] 從 Mac `ssh User@<ip>` 通
|
||||
- [ ] `notepad C:\Windows\Temp\setup.log` 沒有任何 `=== ... ERR ===` 行
|
||||
- [ ] `Get-NetConnectionProfile | Format-Table` 顯示 NetworkCategory=Private
|
||||
- [ ] `slmgr /xpr` 顯示永久授權或 KMS 啟用
|
||||
- [ ] **改 Admin 與 User 密碼**(這份範本是測試用空 / `P@ssw0rd!`,正式機別放著)
|
||||
@@ -1,12 +1,10 @@
|
||||
. "$PSScriptRoot\_common.ps1"
|
||||
|
||||
# 把 UI / IME 預設套到 Default profile,新使用者首次登入會繼承
|
||||
Section 'apply-ui-ime-default-profile' {
|
||||
$hivePath = 'C:\Users\Default\NTUSER.DAT'
|
||||
$mountKey = 'HKU\SetupDefault'
|
||||
reg.exe load $mountKey $hivePath | Out-Null
|
||||
try {
|
||||
$base = "Registry::$mountKey"
|
||||
# Apply UI/IME settings to (a) Default profile NTUSER.DAT (so brand-new users
|
||||
# inherit) and (b) every currently-loaded real-user hive (so re-runs against
|
||||
# an already-logged-in box still take effect immediately on those users).
|
||||
function Apply-UiImeSettings {
|
||||
param([string]$base) # e.g. "Registry::HKU\SetupDefault" or "Registry::HKEY_USERS\<SID>"
|
||||
|
||||
$adv = "$base\Software\Microsoft\Windows\CurrentVersion\Explorer\Advanced"
|
||||
Set-RegValue $adv 'HideFileExt' 0
|
||||
@@ -23,9 +21,9 @@ Section 'apply-ui-ime-default-profile' {
|
||||
$search = "$base\Software\Microsoft\Windows\CurrentVersion\Search"
|
||||
Set-RegValue $search 'SearchboxTaskbarMode' 0
|
||||
|
||||
# SearchSettings 這個 key 在某些 build 上 reg.exe import/add 會被「存取被拒」
|
||||
# (Win11Debloat 的 Disable_Search_History.reg 跟 Disable_Search_Highlights.reg 都會撞),
|
||||
# 但 PowerShell 的 .NET API 寫得進去——所以這裡一次處理掉,Win11Debloat config 已把這兩項移除
|
||||
# SearchSettings 在某些 build 上 reg.exe 會「存取被拒」(Win11Debloat 的
|
||||
# Disable_Search_History.reg 跟 Disable_Search_Highlights.reg 都會撞),
|
||||
# 但 PowerShell .NET API 寫得進去——這裡一次處理掉,Win11Debloat config 已把這兩項移除
|
||||
$searchSettings = "$base\Software\Microsoft\Windows\CurrentVersion\SearchSettings"
|
||||
Set-RegValue $searchSettings 'IsDeviceSearchHistoryEnabled' 0
|
||||
Set-RegValue $searchSettings 'IsDynamicSearchBoxEnabled' 0
|
||||
@@ -51,9 +49,53 @@ Section 'apply-ui-ime-default-profile' {
|
||||
Set-RegValue $tg 'Hotkey' '3' 'String'
|
||||
Set-RegValue $tg 'Language Hotkey' '3' 'String'
|
||||
Set-RegValue $tg 'Layout Hotkey' '3' 'String'
|
||||
|
||||
# 桌面圖示顯示控制(HideDesktopIcons:0=顯示,1=隱藏;
|
||||
# NewStartPanel 是 Win11 用的 key,ClassicStartMenu 是舊版相容)
|
||||
# 內建可控的 5 個 CLSID:
|
||||
# 1 本機 This PC {20D04FE0-3AEA-1069-A2D8-08002B30309D}
|
||||
# 2 使用者檔案 User's Files {59031A47-3F72-44A7-89C5-5595FE6B30EE}
|
||||
# 3 網路 Network {F02C1A0D-BE21-4350-88B0-7367FC96EF3C}
|
||||
# 4 資源回收筒 Recycle Bin {645FF040-5081-101B-9F08-00AA002F954E}
|
||||
# 5 控制台 Control Panel {5399E694-6CE5-4D6C-8FCE-1D8870FDCBA0}
|
||||
# 目前需求:顯示「本機」與「控制台」(資源回收筒 Win11 預設就有)
|
||||
$showOnDesktop = @(
|
||||
'{20D04FE0-3AEA-1069-A2D8-08002B30309D}', # This PC
|
||||
'{5399E694-6CE5-4D6C-8FCE-1D8870FDCBA0}' # Control Panel
|
||||
)
|
||||
foreach ($keyName in @('NewStartPanel','ClassicStartMenu')) {
|
||||
$hk = "$base\Software\Microsoft\Windows\CurrentVersion\Explorer\HideDesktopIcons\$keyName"
|
||||
foreach ($clsid in $showOnDesktop) {
|
||||
Set-RegValue $hk $clsid 0
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Section 'apply-ui-ime-default-profile' {
|
||||
# (a) Default profile(新使用者首次登入會繼承)
|
||||
$hivePath = 'C:\Users\Default\NTUSER.DAT'
|
||||
$mountKey = 'HKU\SetupDefault'
|
||||
reg.exe load $mountKey $hivePath | Out-Null
|
||||
try {
|
||||
Apply-UiImeSettings "Registry::$mountKey"
|
||||
Log "Applied to Default profile"
|
||||
} finally {
|
||||
[GC]::Collect()
|
||||
Start-Sleep 1
|
||||
reg.exe unload $mountKey | Out-Null
|
||||
}
|
||||
|
||||
# (b) 已載入的真人 user hive(HKU\<SID>,跳過 .DEFAULT / 系統 SID)
|
||||
# 取自 Win32_UserProfile,過濾 Special;只在 hive 已載入時寫
|
||||
$profiles = Get-CimInstance Win32_UserProfile -ErrorAction SilentlyContinue |
|
||||
Where-Object { -not $_.Special }
|
||||
foreach ($p in $profiles) {
|
||||
$sid = $p.SID
|
||||
if (Test-Path "Registry::HKEY_USERS\$sid") {
|
||||
Apply-UiImeSettings "Registry::HKEY_USERS\$sid"
|
||||
Log ("Applied to live user hive {0} ({1})" -f $sid, (Split-Path $p.LocalPath -Leaf))
|
||||
} else {
|
||||
Log ("Skip {0} ({1}) - hive not loaded" -f $sid, (Split-Path $p.LocalPath -Leaf))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,8 +2,39 @@
|
||||
|
||||
Section 'install-telegram' {
|
||||
Wait-Network -timeoutSec 30
|
||||
$p = Join-Path $env:TEMP 'tsetup.exe'
|
||||
Invoke-WebRequest -UseBasicParsing -Uri 'https://telegram.org/dl/desktop/win64' -OutFile $p
|
||||
$proc = Start-Process -FilePath $p -ArgumentList '/VERYSILENT','/SUPPRESSMSGBOXES','/NORESTART' -Wait -PassThru
|
||||
Log "Telegram installer exit code: $($proc.ExitCode)"
|
||||
|
||||
# Telegram 官方 tsetup.exe 是 Inno Setup PrivilegesRequired=lowest,
|
||||
# /VERYSILENT /ALLUSERS 都會 fallback per-user,裝到 Admin 的 AppData
|
||||
# 而 User 帳號看不到。改用 winget 的 portable 包 (--scope machine),
|
||||
# 所有 user 都能用,並在 Public Desktop 放一個捷徑讓使用者看得到。
|
||||
$winget = (Get-Command winget -ErrorAction SilentlyContinue).Source
|
||||
if (-not $winget) { Log 'winget not found; skipping Telegram'; return }
|
||||
|
||||
& $winget install --id Telegram.TelegramDesktop -e --silent --source winget --scope machine `
|
||||
--accept-source-agreements --accept-package-agreements 2>&1 |
|
||||
ForEach-Object { Log " winget: $_" }
|
||||
|
||||
# 找實際 Telegram.exe(winget portable 路徑包含版本字尾,動態找)
|
||||
$exe = Get-ChildItem 'C:\Program Files\WinGet\Packages' -Recurse -Filter 'Telegram.exe' -EA SilentlyContinue |
|
||||
Where-Object { $_.Length -gt 1MB } |
|
||||
Select-Object -First 1 -ExpandProperty FullName
|
||||
if (-not $exe) { Log 'Telegram.exe not found after winget install'; return }
|
||||
Log "Telegram.exe: $exe"
|
||||
|
||||
# 修 ACL:winget 解 portable zip 時 'Telegram\' 內層目錄會 break inherit,
|
||||
# 只剩 Admin/Administrators/SYSTEM,標準 token 的 User 雙擊會「沒有適當的權限」。
|
||||
# 強制 grant BUILTIN\Users (S-1-5-32-545) RX 在整個 package 目錄(含子物件)。
|
||||
$pkgDir = (Get-Item $exe).Directory.Parent.FullName
|
||||
& icacls.exe $pkgDir '/grant' '*S-1-5-32-545:(OI)(CI)RX' '/T' '/C' 2>&1 |
|
||||
Select-Object -Last 1 | ForEach-Object { Log " icacls: $_" }
|
||||
|
||||
# Public Desktop 捷徑(C:\Users\Public\Desktop\Telegram.lnk)
|
||||
$lnkPath = Join-Path $env:PUBLIC 'Desktop\Telegram.lnk'
|
||||
$shell = New-Object -ComObject WScript.Shell
|
||||
$lnk = $shell.CreateShortcut($lnkPath)
|
||||
$lnk.TargetPath = $exe
|
||||
$lnk.WorkingDirectory = (Split-Path $exe -Parent)
|
||||
$lnk.IconLocation = $exe
|
||||
$lnk.Save()
|
||||
Log "Created Public desktop shortcut: $lnkPath"
|
||||
}
|
||||
|
||||
@@ -169,8 +169,8 @@
|
||||
</SynchronousCommand>
|
||||
<SynchronousCommand wcm:action="add">
|
||||
<Order>3</Order>
|
||||
<CommandLine>cmd.exe /c "net user User /add & net user User /logonpasswordchg:yes"</CommandLine>
|
||||
<Description>建立本機帳號 User(空密碼,首次登入強制設定新密碼)</Description>
|
||||
<CommandLine>cmd.exe /c "net user User /add & net user User /logonpasswordchg:yes & net localgroup Administrators User /add"</CommandLine>
|
||||
<Description>建立本機帳號 User(空密碼、首次登入強制設定新密碼、加入 Administrators 群組)</Description>
|
||||
<RequiresUserInput>false</RequiresUserInput>
|
||||
</SynchronousCommand>
|
||||
<SynchronousCommand wcm:action="add">
|
||||
|
||||
Reference in New Issue
Block a user