新增 steps/ 拆解版本(每段獨立 .bat 雙擊跑)+ Run-Setup.bat;端對端驗證後修 11 處 bug
steps/ 把 Setup.ps1 拆成 18 個獨立步驟(00-17),每段:
- _common.ps1 提供 Log/Section/Set-RegValue/Wait-Network helper
- 各段一個 .ps1 + 同名 .bat(自動 UAC 提權)
- _admin-shell.bat 開一個已提權 cmd,從那裡跑各 .bat 不再被 UAC 問
- RUN-ALL.bat 依序跑 00..17
- _template.bat 全部 .bat 共用樣板
- README.txt 用法說明
從 macOS WinRM 端對端跑過所有 18 段、發現並修:
- 02-rdp-enable-3389:'Remote Desktop' display group 在某些 Win11 SKU 不存在,
改顯式 New-NetFirewallRule + Restart-Service TermService
- 04-winrm-enable:開頭加 Set-NetConnectionProfile -NetworkCategory Private fallback,
避免 winrm quickconfig 在 Public profile 拒絕啟用
- 11-kms-activate:原本 'successful|成功' 正則在 Big5 codepage 下 mojibake 出 '{x,y}',
改用 SoftwareLicensingProduct.LicenseStatus -eq 1 WMI 判斷
- 12-winget-install-chrome:加 --source winget,避開 msstore 憑證錯誤造成的歧義
- 13-remove-windows-ai:拿掉 -AllOptions,顯式 10 個 option 排除 UpdateCleanupCheck
(DISM Cleanup-Image + sfc + MessageBox 在 Session-0 default Yes 觸發 Restart-Computer)
- 14-win11debloat:加 -Sysprep(寫到 Default profile 不撞 HKCU 鎖),
從 config 移除 DisableSearchHistory/DisableSearchHighlights/HideSearchTb
(它們的 reg.exe import 會被「存取被拒」擋住)
- 07-apply-ui-ime-default-profile:補上 IsDeviceSearchHistoryEnabled / IsDynamicSearchBoxEnabled
替代上面從 Win11Debloat 拔掉的兩項
- 新增 00-network-private 步驟把所有 NetConnectionProfile 改 Private
- 全部 19 個 .ps1 加 UTF-8 BOM,避免 CHT Windows PS5.1 fallback ANSI 讀中文 mojibake
- 全部 .bat REM 註解改 ASCII,根除「'券蠶setup.log' 不是內部命令」那種亂碼
Run-Setup.bat:當 unattend.xml FirstLogonCommands 沒成功跑起 Setup.ps1 時,
把這支從 USB 雙擊執行,會 UAC 提權 + 從 USB 重拷 + 跑 + console 即時印 + 收 log
This commit is contained in:
49
Run-Setup.bat
Normal file
49
Run-Setup.bat
Normal file
@@ -0,0 +1,49 @@
|
|||||||
|
@echo off
|
||||||
|
REM Run-Setup.bat — 從 Ventoy USB 雙擊就能手動觸發 Setup.ps1
|
||||||
|
REM 用途:當 unattend.xml 的 FirstLogonCommands Order 5 沒成功跑起 Setup.ps1 時,
|
||||||
|
REM 把這份 .bat 從 USB 雙擊執行,會自動 UAC 提權、覆蓋 C:\Scripts\Setup.ps1、
|
||||||
|
REM 跑 Setup.ps1,所有輸出(含 parse error)都會收到 setup-stdout.log。
|
||||||
|
|
||||||
|
setlocal
|
||||||
|
|
||||||
|
REM 先用 fltmc 偵測是否已是 Administrator;不是就用 PowerShell 自我提權重啟
|
||||||
|
fltmc >nul 2>&1
|
||||||
|
if %errorLevel% neq 0 (
|
||||||
|
echo Requesting administrator privileges...
|
||||||
|
powershell -NoProfile -Command "Start-Process -FilePath '%~f0' -Verb RunAs"
|
||||||
|
exit /b
|
||||||
|
)
|
||||||
|
|
||||||
|
set "USB_DIR=%~dp0"
|
||||||
|
set "DST=C:\Scripts\Setup.ps1"
|
||||||
|
set "OUT=C:\Windows\Temp\setup-stdout.log"
|
||||||
|
|
||||||
|
echo === Run-Setup.bat (elevated) ===
|
||||||
|
echo USB source : %USB_DIR%Setup.ps1
|
||||||
|
echo Copy to : %DST%
|
||||||
|
echo Stdout log : %OUT%
|
||||||
|
echo Setup log : C:\Windows\Temp\setup.log
|
||||||
|
echo.
|
||||||
|
|
||||||
|
mkdir C:\Scripts >nul 2>&1
|
||||||
|
copy /Y "%USB_DIR%Setup.ps1" "%DST%"
|
||||||
|
if errorlevel 1 (
|
||||||
|
echo [ERROR] Copy failed. Is the USB still plugged in?
|
||||||
|
pause
|
||||||
|
exit /b 1
|
||||||
|
)
|
||||||
|
|
||||||
|
echo Running Setup.ps1 (output streams to this window AND %OUT%) ...
|
||||||
|
echo -----------------------------------------------------------------
|
||||||
|
powershell.exe -NoProfile -ExecutionPolicy Bypass -Command "& '%DST%' 2>&1 | Tee-Object -FilePath '%OUT%'"
|
||||||
|
set RC=%errorLevel%
|
||||||
|
echo -----------------------------------------------------------------
|
||||||
|
|
||||||
|
echo.
|
||||||
|
echo === Done (exit code %RC%) ===
|
||||||
|
echo View logs:
|
||||||
|
echo notepad C:\Windows\Temp\setup.log
|
||||||
|
echo notepad %OUT%
|
||||||
|
echo.
|
||||||
|
pause
|
||||||
|
endlocal
|
||||||
20
steps/00-network-private.bat
Normal file
20
steps/00-network-private.bat
Normal file
@@ -0,0 +1,20 @@
|
|||||||
|
@echo off
|
||||||
|
REM Double-click to run %~n0.ps1 with UAC elevation.
|
||||||
|
REM All output goes to this window AND C:\Windows\Temp\setup.log.
|
||||||
|
fltmc >nul 2>&1
|
||||||
|
if %errorLevel% neq 0 (
|
||||||
|
powershell -NoProfile -Command "Start-Process -FilePath '%~f0' -Verb RunAs"
|
||||||
|
exit /b
|
||||||
|
)
|
||||||
|
echo ============================================================
|
||||||
|
echo Running: %~n0
|
||||||
|
echo Log : C:\Windows\Temp\setup.log
|
||||||
|
echo ============================================================
|
||||||
|
echo.
|
||||||
|
powershell.exe -NoProfile -ExecutionPolicy Bypass -File "%~dpn0.ps1"
|
||||||
|
set RC=%errorLevel%
|
||||||
|
echo.
|
||||||
|
echo ============================================================
|
||||||
|
echo Done (exit code %RC%)
|
||||||
|
echo ============================================================
|
||||||
|
pause
|
||||||
18
steps/00-network-private.ps1
Normal file
18
steps/00-network-private.ps1
Normal file
@@ -0,0 +1,18 @@
|
|||||||
|
. "$PSScriptRoot\_common.ps1"
|
||||||
|
|
||||||
|
Section 'network-set-private' {
|
||||||
|
$profiles = Get-NetConnectionProfile -ErrorAction SilentlyContinue
|
||||||
|
if (-not $profiles) {
|
||||||
|
Log 'No active NetConnectionProfile (offline?) - nothing to set'
|
||||||
|
return
|
||||||
|
}
|
||||||
|
foreach ($p in $profiles) {
|
||||||
|
Log ("Profile {0} (idx {1}) was {2}" -f $p.Name, $p.InterfaceIndex, $p.NetworkCategory)
|
||||||
|
if ($p.NetworkCategory -ne 'Private') {
|
||||||
|
Set-NetConnectionProfile -InterfaceIndex $p.InterfaceIndex -NetworkCategory Private
|
||||||
|
Log (" -> set to Private")
|
||||||
|
} else {
|
||||||
|
Log ' already Private'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
20
steps/01-firewall-ssh-22.bat
Normal file
20
steps/01-firewall-ssh-22.bat
Normal file
@@ -0,0 +1,20 @@
|
|||||||
|
@echo off
|
||||||
|
REM Double-click to run %~n0.ps1 with UAC elevation.
|
||||||
|
REM All output goes to this window AND C:\Windows\Temp\setup.log.
|
||||||
|
fltmc >nul 2>&1
|
||||||
|
if %errorLevel% neq 0 (
|
||||||
|
powershell -NoProfile -Command "Start-Process -FilePath '%~f0' -Verb RunAs"
|
||||||
|
exit /b
|
||||||
|
)
|
||||||
|
echo ============================================================
|
||||||
|
echo Running: %~n0
|
||||||
|
echo Log : C:\Windows\Temp\setup.log
|
||||||
|
echo ============================================================
|
||||||
|
echo.
|
||||||
|
powershell.exe -NoProfile -ExecutionPolicy Bypass -File "%~dpn0.ps1"
|
||||||
|
set RC=%errorLevel%
|
||||||
|
echo.
|
||||||
|
echo ============================================================
|
||||||
|
echo Done (exit code %RC%)
|
||||||
|
echo ============================================================
|
||||||
|
pause
|
||||||
8
steps/01-firewall-ssh-22.ps1
Normal file
8
steps/01-firewall-ssh-22.ps1
Normal file
@@ -0,0 +1,8 @@
|
|||||||
|
. "$PSScriptRoot\_common.ps1"
|
||||||
|
|
||||||
|
Section 'firewall-ssh-22' {
|
||||||
|
Remove-NetFirewallRule -DisplayName 'SSH TCP 22 (Allow Inbound)' -ErrorAction SilentlyContinue
|
||||||
|
New-NetFirewallRule -DisplayName 'SSH TCP 22 (Allow Inbound)' `
|
||||||
|
-Direction Inbound -Protocol TCP -LocalPort 22 -Action Allow -Profile Any -Enabled True | Out-Null
|
||||||
|
Set-NetFirewallProfile -Profile Domain,Private,Public -Enabled True
|
||||||
|
}
|
||||||
20
steps/02-rdp-enable-3389.bat
Normal file
20
steps/02-rdp-enable-3389.bat
Normal file
@@ -0,0 +1,20 @@
|
|||||||
|
@echo off
|
||||||
|
REM Double-click to run %~n0.ps1 with UAC elevation.
|
||||||
|
REM All output goes to this window AND C:\Windows\Temp\setup.log.
|
||||||
|
fltmc >nul 2>&1
|
||||||
|
if %errorLevel% neq 0 (
|
||||||
|
powershell -NoProfile -Command "Start-Process -FilePath '%~f0' -Verb RunAs"
|
||||||
|
exit /b
|
||||||
|
)
|
||||||
|
echo ============================================================
|
||||||
|
echo Running: %~n0
|
||||||
|
echo Log : C:\Windows\Temp\setup.log
|
||||||
|
echo ============================================================
|
||||||
|
echo.
|
||||||
|
powershell.exe -NoProfile -ExecutionPolicy Bypass -File "%~dpn0.ps1"
|
||||||
|
set RC=%errorLevel%
|
||||||
|
echo.
|
||||||
|
echo ============================================================
|
||||||
|
echo Done (exit code %RC%)
|
||||||
|
echo ============================================================
|
||||||
|
pause
|
||||||
16
steps/02-rdp-enable-3389.ps1
Normal file
16
steps/02-rdp-enable-3389.ps1
Normal file
@@ -0,0 +1,16 @@
|
|||||||
|
. "$PSScriptRoot\_common.ps1"
|
||||||
|
|
||||||
|
Section 'rdp-enable-3389' {
|
||||||
|
Set-RegValue 'HKLM:\System\CurrentControlSet\Control\Terminal Server' 'fDenyTSConnections' 0
|
||||||
|
Set-RegValue 'HKLM:\System\CurrentControlSet\Control\Terminal Server\WinStations\RDP-Tcp' 'UserAuthentication' 1
|
||||||
|
|
||||||
|
# Windows 內建的 'Remote Desktop' display group 在某些 SKU/精簡版中不存在,
|
||||||
|
# 改自建顯式規則確保 3389 通(Profile Any 涵蓋 Domain/Private/Public)
|
||||||
|
Remove-NetFirewallRule -DisplayName 'RDP TCP 3389 (Allow Inbound)' -ErrorAction SilentlyContinue
|
||||||
|
New-NetFirewallRule -DisplayName 'RDP TCP 3389 (Allow Inbound)' `
|
||||||
|
-Direction Inbound -Protocol TCP -LocalPort 3389 -Action Allow -Profile Any -Enabled True | Out-Null
|
||||||
|
Enable-NetFirewallRule -DisplayGroup 'Remote Desktop' -ErrorAction SilentlyContinue
|
||||||
|
|
||||||
|
# 改完 fDenyTSConnections 需要重啟 TermService 才會立刻 listen
|
||||||
|
Restart-Service TermService -Force -ErrorAction SilentlyContinue
|
||||||
|
}
|
||||||
20
steps/03-icmp-echo-allow.bat
Normal file
20
steps/03-icmp-echo-allow.bat
Normal file
@@ -0,0 +1,20 @@
|
|||||||
|
@echo off
|
||||||
|
REM Double-click to run %~n0.ps1 with UAC elevation.
|
||||||
|
REM All output goes to this window AND C:\Windows\Temp\setup.log.
|
||||||
|
fltmc >nul 2>&1
|
||||||
|
if %errorLevel% neq 0 (
|
||||||
|
powershell -NoProfile -Command "Start-Process -FilePath '%~f0' -Verb RunAs"
|
||||||
|
exit /b
|
||||||
|
)
|
||||||
|
echo ============================================================
|
||||||
|
echo Running: %~n0
|
||||||
|
echo Log : C:\Windows\Temp\setup.log
|
||||||
|
echo ============================================================
|
||||||
|
echo.
|
||||||
|
powershell.exe -NoProfile -ExecutionPolicy Bypass -File "%~dpn0.ps1"
|
||||||
|
set RC=%errorLevel%
|
||||||
|
echo.
|
||||||
|
echo ============================================================
|
||||||
|
echo Done (exit code %RC%)
|
||||||
|
echo ============================================================
|
||||||
|
pause
|
||||||
10
steps/03-icmp-echo-allow.ps1
Normal file
10
steps/03-icmp-echo-allow.ps1
Normal file
@@ -0,0 +1,10 @@
|
|||||||
|
. "$PSScriptRoot\_common.ps1"
|
||||||
|
|
||||||
|
Section 'icmp-echo-allow' {
|
||||||
|
Remove-NetFirewallRule -DisplayName 'ICMPv4 Echo Request (Allow Inbound)' -ErrorAction SilentlyContinue
|
||||||
|
New-NetFirewallRule -DisplayName 'ICMPv4 Echo Request (Allow Inbound)' `
|
||||||
|
-Direction Inbound -Protocol ICMPv4 -IcmpType 8 -Action Allow -Profile Any -Enabled True | Out-Null
|
||||||
|
Get-NetFirewallRule -ErrorAction SilentlyContinue |
|
||||||
|
Where-Object { $_.DisplayName -match 'Echo Request' } |
|
||||||
|
Enable-NetFirewallRule -ErrorAction SilentlyContinue
|
||||||
|
}
|
||||||
20
steps/04-winrm-enable.bat
Normal file
20
steps/04-winrm-enable.bat
Normal file
@@ -0,0 +1,20 @@
|
|||||||
|
@echo off
|
||||||
|
REM Double-click to run %~n0.ps1 with UAC elevation.
|
||||||
|
REM All output goes to this window AND C:\Windows\Temp\setup.log.
|
||||||
|
fltmc >nul 2>&1
|
||||||
|
if %errorLevel% neq 0 (
|
||||||
|
powershell -NoProfile -Command "Start-Process -FilePath '%~f0' -Verb RunAs"
|
||||||
|
exit /b
|
||||||
|
)
|
||||||
|
echo ============================================================
|
||||||
|
echo Running: %~n0
|
||||||
|
echo Log : C:\Windows\Temp\setup.log
|
||||||
|
echo ============================================================
|
||||||
|
echo.
|
||||||
|
powershell.exe -NoProfile -ExecutionPolicy Bypass -File "%~dpn0.ps1"
|
||||||
|
set RC=%errorLevel%
|
||||||
|
echo.
|
||||||
|
echo ============================================================
|
||||||
|
echo Done (exit code %RC%)
|
||||||
|
echo ============================================================
|
||||||
|
pause
|
||||||
20
steps/04-winrm-enable.ps1
Normal file
20
steps/04-winrm-enable.ps1
Normal file
@@ -0,0 +1,20 @@
|
|||||||
|
. "$PSScriptRoot\_common.ps1"
|
||||||
|
|
||||||
|
Section 'winrm-enable' {
|
||||||
|
# winrm quickconfig 不接受 Public profile,先把現有連線改成 Private
|
||||||
|
Get-NetConnectionProfile -ErrorAction SilentlyContinue |
|
||||||
|
Where-Object { $_.NetworkCategory -ne 'Private' } |
|
||||||
|
ForEach-Object {
|
||||||
|
Log ("Set NetConnectionProfile idx {0} ({1}) Private" -f $_.InterfaceIndex, $_.Name)
|
||||||
|
Set-NetConnectionProfile -InterfaceIndex $_.InterfaceIndex -NetworkCategory Private
|
||||||
|
}
|
||||||
|
|
||||||
|
Enable-PSRemoting -Force -SkipNetworkProfileCheck | Out-Null
|
||||||
|
Set-Service -Name WinRM -StartupType Automatic
|
||||||
|
Start-Service -Name WinRM -ErrorAction SilentlyContinue
|
||||||
|
cmd.exe /c 'winrm quickconfig -quiet -force' | Out-Null
|
||||||
|
cmd.exe /c 'winrm set winrm/config/service/auth @{Basic="true"}' | Out-Null
|
||||||
|
cmd.exe /c 'winrm set winrm/config/service @{AllowUnencrypted="true"}' | Out-Null
|
||||||
|
cmd.exe /c 'winrm set winrm/config/client @{TrustedHosts="*"}' | Out-Null
|
||||||
|
Enable-NetFirewallRule -DisplayGroup 'Windows Remote Management' -ErrorAction SilentlyContinue
|
||||||
|
}
|
||||||
20
steps/05-onedrive-remove.bat
Normal file
20
steps/05-onedrive-remove.bat
Normal file
@@ -0,0 +1,20 @@
|
|||||||
|
@echo off
|
||||||
|
REM Double-click to run %~n0.ps1 with UAC elevation.
|
||||||
|
REM All output goes to this window AND C:\Windows\Temp\setup.log.
|
||||||
|
fltmc >nul 2>&1
|
||||||
|
if %errorLevel% neq 0 (
|
||||||
|
powershell -NoProfile -Command "Start-Process -FilePath '%~f0' -Verb RunAs"
|
||||||
|
exit /b
|
||||||
|
)
|
||||||
|
echo ============================================================
|
||||||
|
echo Running: %~n0
|
||||||
|
echo Log : C:\Windows\Temp\setup.log
|
||||||
|
echo ============================================================
|
||||||
|
echo.
|
||||||
|
powershell.exe -NoProfile -ExecutionPolicy Bypass -File "%~dpn0.ps1"
|
||||||
|
set RC=%errorLevel%
|
||||||
|
echo.
|
||||||
|
echo ============================================================
|
||||||
|
echo Done (exit code %RC%)
|
||||||
|
echo ============================================================
|
||||||
|
pause
|
||||||
12
steps/05-onedrive-remove.ps1
Normal file
12
steps/05-onedrive-remove.ps1
Normal file
@@ -0,0 +1,12 @@
|
|||||||
|
. "$PSScriptRoot\_common.ps1"
|
||||||
|
|
||||||
|
Section 'onedrive-remove' {
|
||||||
|
Get-Process OneDrive -ErrorAction SilentlyContinue | Stop-Process -Force -ErrorAction SilentlyContinue
|
||||||
|
foreach ($p in @("$env:SystemRoot\System32\OneDriveSetup.exe", "$env:SystemRoot\SysWOW64\OneDriveSetup.exe")) {
|
||||||
|
if (Test-Path $p) { Start-Process $p -ArgumentList '/uninstall' -Wait -ErrorAction SilentlyContinue }
|
||||||
|
}
|
||||||
|
Remove-ItemProperty -Path 'HKLM:\Software\Microsoft\Windows\CurrentVersion\Run' -Name 'OneDrive' -ErrorAction SilentlyContinue
|
||||||
|
Remove-Item 'HKLM:\SOFTWARE\Classes\CLSID\{018D5C66-4533-4307-9B53-224DE2ED1FE6}' -Recurse -ErrorAction SilentlyContinue
|
||||||
|
Remove-Item 'HKLM:\SOFTWARE\Wow6432Node\Classes\CLSID\{018D5C66-4533-4307-9B53-224DE2ED1FE6}' -Recurse -ErrorAction SilentlyContinue
|
||||||
|
Remove-Item -Path 'C:\OneDriveTemp', "$env:USERPROFILE\OneDrive", "$env:LOCALAPPDATA\Microsoft\OneDrive" -Recurse -Force -ErrorAction SilentlyContinue
|
||||||
|
}
|
||||||
20
steps/06-cortana-websearch-off.bat
Normal file
20
steps/06-cortana-websearch-off.bat
Normal file
@@ -0,0 +1,20 @@
|
|||||||
|
@echo off
|
||||||
|
REM Double-click to run %~n0.ps1 with UAC elevation.
|
||||||
|
REM All output goes to this window AND C:\Windows\Temp\setup.log.
|
||||||
|
fltmc >nul 2>&1
|
||||||
|
if %errorLevel% neq 0 (
|
||||||
|
powershell -NoProfile -Command "Start-Process -FilePath '%~f0' -Verb RunAs"
|
||||||
|
exit /b
|
||||||
|
)
|
||||||
|
echo ============================================================
|
||||||
|
echo Running: %~n0
|
||||||
|
echo Log : C:\Windows\Temp\setup.log
|
||||||
|
echo ============================================================
|
||||||
|
echo.
|
||||||
|
powershell.exe -NoProfile -ExecutionPolicy Bypass -File "%~dpn0.ps1"
|
||||||
|
set RC=%errorLevel%
|
||||||
|
echo.
|
||||||
|
echo ============================================================
|
||||||
|
echo Done (exit code %RC%)
|
||||||
|
echo ============================================================
|
||||||
|
pause
|
||||||
12
steps/06-cortana-websearch-off.ps1
Normal file
12
steps/06-cortana-websearch-off.ps1
Normal file
@@ -0,0 +1,12 @@
|
|||||||
|
. "$PSScriptRoot\_common.ps1"
|
||||||
|
|
||||||
|
Section 'cortana-websearch-off' {
|
||||||
|
$k1 = 'HKLM:\SOFTWARE\Policies\Microsoft\Windows\Windows Search'
|
||||||
|
Set-RegValue $k1 'AllowCortana' 0
|
||||||
|
Set-RegValue $k1 'DisableWebSearch' 1
|
||||||
|
Set-RegValue $k1 'ConnectedSearchUseWeb' 0
|
||||||
|
Set-RegValue $k1 'AllowSearchToUseLocation' 0
|
||||||
|
|
||||||
|
$k2 = 'HKLM:\SOFTWARE\Policies\Microsoft\Windows\Explorer'
|
||||||
|
Set-RegValue $k2 'DisableSearchBoxSuggestions' 1
|
||||||
|
}
|
||||||
20
steps/07-apply-ui-ime-default-profile.bat
Normal file
20
steps/07-apply-ui-ime-default-profile.bat
Normal file
@@ -0,0 +1,20 @@
|
|||||||
|
@echo off
|
||||||
|
REM Double-click to run %~n0.ps1 with UAC elevation.
|
||||||
|
REM All output goes to this window AND C:\Windows\Temp\setup.log.
|
||||||
|
fltmc >nul 2>&1
|
||||||
|
if %errorLevel% neq 0 (
|
||||||
|
powershell -NoProfile -Command "Start-Process -FilePath '%~f0' -Verb RunAs"
|
||||||
|
exit /b
|
||||||
|
)
|
||||||
|
echo ============================================================
|
||||||
|
echo Running: %~n0
|
||||||
|
echo Log : C:\Windows\Temp\setup.log
|
||||||
|
echo ============================================================
|
||||||
|
echo.
|
||||||
|
powershell.exe -NoProfile -ExecutionPolicy Bypass -File "%~dpn0.ps1"
|
||||||
|
set RC=%errorLevel%
|
||||||
|
echo.
|
||||||
|
echo ============================================================
|
||||||
|
echo Done (exit code %RC%)
|
||||||
|
echo ============================================================
|
||||||
|
pause
|
||||||
59
steps/07-apply-ui-ime-default-profile.ps1
Normal file
59
steps/07-apply-ui-ime-default-profile.ps1
Normal file
@@ -0,0 +1,59 @@
|
|||||||
|
. "$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"
|
||||||
|
|
||||||
|
$adv = "$base\Software\Microsoft\Windows\CurrentVersion\Explorer\Advanced"
|
||||||
|
Set-RegValue $adv 'HideFileExt' 0
|
||||||
|
Set-RegValue $adv 'Hidden' 1
|
||||||
|
Set-RegValue $adv 'TaskbarAl' 0
|
||||||
|
Set-RegValue $adv 'ShowTaskViewButton' 0
|
||||||
|
Set-RegValue $adv 'LaunchTo' 1
|
||||||
|
Set-RegValue $adv 'Start_TrackProgs' 0
|
||||||
|
|
||||||
|
$theme = "$base\Software\Microsoft\Windows\CurrentVersion\Themes\Personalize"
|
||||||
|
Set-RegValue $theme 'AppsUseLightTheme' 0
|
||||||
|
Set-RegValue $theme 'SystemUseLightTheme' 0
|
||||||
|
|
||||||
|
$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 = "$base\Software\Microsoft\Windows\CurrentVersion\SearchSettings"
|
||||||
|
Set-RegValue $searchSettings 'IsDeviceSearchHistoryEnabled' 0
|
||||||
|
Set-RegValue $searchSettings 'IsDynamicSearchBoxEnabled' 0
|
||||||
|
|
||||||
|
$cloud = "$base\Software\Policies\Microsoft\Windows\CloudContent"
|
||||||
|
Set-RegValue $cloud 'DisableSpotlightCollectionOnDesktop' 1
|
||||||
|
Set-RegValue $cloud 'DisableWindowsSpotlightFeatures' 1
|
||||||
|
|
||||||
|
# 鍵盤排序:英文鍵盤排第一(預設英數),注音排第二
|
||||||
|
$kbPre = "$base\Keyboard Layout\Preload"
|
||||||
|
Set-RegValue $kbPre '1' '00000409' 'String'
|
||||||
|
Set-RegValue $kbPre '2' '00000404' 'String'
|
||||||
|
|
||||||
|
# CHT 注音:預設英數模式、關掉雲端候選與預測
|
||||||
|
$cht = "$base\Software\Microsoft\InputMethod\Settings\CHT"
|
||||||
|
Set-RegValue $cht 'Enable Default Input Mode' 0
|
||||||
|
Set-RegValue $cht 'Enable Cand Predict' 0
|
||||||
|
Set-RegValue $cht 'Enable Cloud Cand' 0
|
||||||
|
Set-RegValue $cht 'Enable Cloud Input' 0
|
||||||
|
|
||||||
|
# 把系統 Hotkey 切換鍵停掉(3 = 不指定鍵)
|
||||||
|
$tg = "$base\Keyboard Layout\Toggle"
|
||||||
|
Set-RegValue $tg 'Hotkey' '3' 'String'
|
||||||
|
Set-RegValue $tg 'Language Hotkey' '3' 'String'
|
||||||
|
Set-RegValue $tg 'Layout Hotkey' '3' 'String'
|
||||||
|
} finally {
|
||||||
|
[GC]::Collect()
|
||||||
|
Start-Sleep 1
|
||||||
|
reg.exe unload $mountKey | Out-Null
|
||||||
|
}
|
||||||
|
}
|
||||||
20
steps/08-hide-admin-account.bat
Normal file
20
steps/08-hide-admin-account.bat
Normal file
@@ -0,0 +1,20 @@
|
|||||||
|
@echo off
|
||||||
|
REM Double-click to run %~n0.ps1 with UAC elevation.
|
||||||
|
REM All output goes to this window AND C:\Windows\Temp\setup.log.
|
||||||
|
fltmc >nul 2>&1
|
||||||
|
if %errorLevel% neq 0 (
|
||||||
|
powershell -NoProfile -Command "Start-Process -FilePath '%~f0' -Verb RunAs"
|
||||||
|
exit /b
|
||||||
|
)
|
||||||
|
echo ============================================================
|
||||||
|
echo Running: %~n0
|
||||||
|
echo Log : C:\Windows\Temp\setup.log
|
||||||
|
echo ============================================================
|
||||||
|
echo.
|
||||||
|
powershell.exe -NoProfile -ExecutionPolicy Bypass -File "%~dpn0.ps1"
|
||||||
|
set RC=%errorLevel%
|
||||||
|
echo.
|
||||||
|
echo ============================================================
|
||||||
|
echo Done (exit code %RC%)
|
||||||
|
echo ============================================================
|
||||||
|
pause
|
||||||
7
steps/08-hide-admin-account.ps1
Normal file
7
steps/08-hide-admin-account.ps1
Normal file
@@ -0,0 +1,7 @@
|
|||||||
|
. "$PSScriptRoot\_common.ps1"
|
||||||
|
|
||||||
|
Section 'hide-admin-account' {
|
||||||
|
# 把 Admin 從登入畫面藏掉(帳號仍存在仍可用)
|
||||||
|
$userListKey = 'HKLM:\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Winlogon\SpecialAccounts\UserList'
|
||||||
|
Set-RegValue $userListKey 'Admin' 0
|
||||||
|
}
|
||||||
20
steps/09-pause-windows-update.bat
Normal file
20
steps/09-pause-windows-update.bat
Normal file
@@ -0,0 +1,20 @@
|
|||||||
|
@echo off
|
||||||
|
REM Double-click to run %~n0.ps1 with UAC elevation.
|
||||||
|
REM All output goes to this window AND C:\Windows\Temp\setup.log.
|
||||||
|
fltmc >nul 2>&1
|
||||||
|
if %errorLevel% neq 0 (
|
||||||
|
powershell -NoProfile -Command "Start-Process -FilePath '%~f0' -Verb RunAs"
|
||||||
|
exit /b
|
||||||
|
)
|
||||||
|
echo ============================================================
|
||||||
|
echo Running: %~n0
|
||||||
|
echo Log : C:\Windows\Temp\setup.log
|
||||||
|
echo ============================================================
|
||||||
|
echo.
|
||||||
|
powershell.exe -NoProfile -ExecutionPolicy Bypass -File "%~dpn0.ps1"
|
||||||
|
set RC=%errorLevel%
|
||||||
|
echo.
|
||||||
|
echo ============================================================
|
||||||
|
echo Done (exit code %RC%)
|
||||||
|
echo ============================================================
|
||||||
|
pause
|
||||||
18
steps/09-pause-windows-update.ps1
Normal file
18
steps/09-pause-windows-update.ps1
Normal file
@@ -0,0 +1,18 @@
|
|||||||
|
. "$PSScriptRoot\_common.ps1"
|
||||||
|
|
||||||
|
Section 'pause-windows-update' {
|
||||||
|
$now = (Get-Date).ToUniversalTime().ToString("yyyy-MM-ddTHH:mm:ssZ")
|
||||||
|
$expiry = (Get-Date).ToUniversalTime().AddHours(24).ToString("yyyy-MM-ddTHH:mm:ssZ")
|
||||||
|
$ux = 'HKLM:\SOFTWARE\Microsoft\WindowsUpdate\UX\Settings'
|
||||||
|
Set-RegValue $ux 'PauseUpdatesStartTime' $now 'String'
|
||||||
|
Set-RegValue $ux 'PauseUpdatesExpiryTime' $expiry 'String'
|
||||||
|
Set-RegValue $ux 'PauseFeatureUpdatesStartTime' $now 'String'
|
||||||
|
Set-RegValue $ux 'PauseFeatureUpdatesEndTime' $expiry 'String'
|
||||||
|
Set-RegValue $ux 'PauseQualityUpdatesStartTime' $now 'String'
|
||||||
|
Set-RegValue $ux 'PauseQualityUpdatesEndTime' $expiry 'String'
|
||||||
|
Log "WU paused until $expiry (UTC)"
|
||||||
|
|
||||||
|
foreach ($svc in @('UsoSvc','wuauserv','BITS')) {
|
||||||
|
Stop-Service -Name $svc -Force -ErrorAction SilentlyContinue
|
||||||
|
}
|
||||||
|
}
|
||||||
20
steps/10-openssh-server-install.bat
Normal file
20
steps/10-openssh-server-install.bat
Normal file
@@ -0,0 +1,20 @@
|
|||||||
|
@echo off
|
||||||
|
REM Double-click to run %~n0.ps1 with UAC elevation.
|
||||||
|
REM All output goes to this window AND C:\Windows\Temp\setup.log.
|
||||||
|
fltmc >nul 2>&1
|
||||||
|
if %errorLevel% neq 0 (
|
||||||
|
powershell -NoProfile -Command "Start-Process -FilePath '%~f0' -Verb RunAs"
|
||||||
|
exit /b
|
||||||
|
)
|
||||||
|
echo ============================================================
|
||||||
|
echo Running: %~n0
|
||||||
|
echo Log : C:\Windows\Temp\setup.log
|
||||||
|
echo ============================================================
|
||||||
|
echo.
|
||||||
|
powershell.exe -NoProfile -ExecutionPolicy Bypass -File "%~dpn0.ps1"
|
||||||
|
set RC=%errorLevel%
|
||||||
|
echo.
|
||||||
|
echo ============================================================
|
||||||
|
echo Done (exit code %RC%)
|
||||||
|
echo ============================================================
|
||||||
|
pause
|
||||||
8
steps/10-openssh-server-install.ps1
Normal file
8
steps/10-openssh-server-install.ps1
Normal file
@@ -0,0 +1,8 @@
|
|||||||
|
. "$PSScriptRoot\_common.ps1"
|
||||||
|
|
||||||
|
Section 'openssh-server-install' {
|
||||||
|
Wait-Network -timeoutSec 30
|
||||||
|
Add-WindowsCapability -Online -Name 'OpenSSH.Server~~~~0.0.1.0' -ErrorAction Stop | Out-Null
|
||||||
|
Set-Service sshd -StartupType Automatic
|
||||||
|
Start-Service sshd
|
||||||
|
}
|
||||||
20
steps/11-kms-activate.bat
Normal file
20
steps/11-kms-activate.bat
Normal file
@@ -0,0 +1,20 @@
|
|||||||
|
@echo off
|
||||||
|
REM Double-click to run %~n0.ps1 with UAC elevation.
|
||||||
|
REM All output goes to this window AND C:\Windows\Temp\setup.log.
|
||||||
|
fltmc >nul 2>&1
|
||||||
|
if %errorLevel% neq 0 (
|
||||||
|
powershell -NoProfile -Command "Start-Process -FilePath '%~f0' -Verb RunAs"
|
||||||
|
exit /b
|
||||||
|
)
|
||||||
|
echo ============================================================
|
||||||
|
echo Running: %~n0
|
||||||
|
echo Log : C:\Windows\Temp\setup.log
|
||||||
|
echo ============================================================
|
||||||
|
echo.
|
||||||
|
powershell.exe -NoProfile -ExecutionPolicy Bypass -File "%~dpn0.ps1"
|
||||||
|
set RC=%errorLevel%
|
||||||
|
echo.
|
||||||
|
echo ============================================================
|
||||||
|
echo Done (exit code %RC%)
|
||||||
|
echo ============================================================
|
||||||
|
pause
|
||||||
46
steps/11-kms-activate.ps1
Normal file
46
steps/11-kms-activate.ps1
Normal file
@@ -0,0 +1,46 @@
|
|||||||
|
. "$PSScriptRoot\_common.ps1"
|
||||||
|
|
||||||
|
# 內網 KMS 主機請改下面這列;保持空陣列就會用公開 KMS 清單輪流試
|
||||||
|
$InternalKmsServers = @()
|
||||||
|
$PublicKmsServers = @('kms.digiboy.ir', 'kms8.msguides.com', 'kms.03k.org', 'kms.chinancce.com')
|
||||||
|
|
||||||
|
function Test-WindowsActivated {
|
||||||
|
# ApplicationID 55c92734-... = Windows
|
||||||
|
# LicenseStatus: 0=Unlicensed, 1=Licensed, 2=OOB grace, 3=OOT grace, 4=NonGenuine grace, 5=Notification, 6=Extended grace
|
||||||
|
$slp = Get-CimInstance -ClassName SoftwareLicensingProduct -ErrorAction SilentlyContinue |
|
||||||
|
Where-Object {
|
||||||
|
$_.PartialProductKey -and
|
||||||
|
$_.ApplicationID -eq '55c92734-d682-4d71-983e-d6ec3f16059f' -and
|
||||||
|
$_.LicenseStatus -eq 1
|
||||||
|
}
|
||||||
|
return [bool]$slp
|
||||||
|
}
|
||||||
|
|
||||||
|
Section 'kms-activate' {
|
||||||
|
Wait-Network -timeoutSec 30
|
||||||
|
|
||||||
|
if (Test-WindowsActivated) {
|
||||||
|
Log 'Already activated; skipping KMS attempts'
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
$servers = @()
|
||||||
|
if ($InternalKmsServers.Count -gt 0) { $servers += $InternalKmsServers }
|
||||||
|
$servers += $PublicKmsServers
|
||||||
|
|
||||||
|
$activated = $false
|
||||||
|
foreach ($kms in $servers) {
|
||||||
|
Log "Try KMS: $kms"
|
||||||
|
cscript.exe //nologo C:\Windows\System32\slmgr.vbs /skms $kms | Out-Null
|
||||||
|
cscript.exe //nologo C:\Windows\System32\slmgr.vbs /ato 2>&1 | Out-Null
|
||||||
|
Start-Sleep 1
|
||||||
|
if (Test-WindowsActivated) {
|
||||||
|
Log "Activated via $kms"
|
||||||
|
$activated = $true
|
||||||
|
break
|
||||||
|
} else {
|
||||||
|
Log " not activated yet"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (-not $activated) { Log 'All KMS servers failed; remaining in grace period' }
|
||||||
|
}
|
||||||
20
steps/12-winget-install-chrome.bat
Normal file
20
steps/12-winget-install-chrome.bat
Normal file
@@ -0,0 +1,20 @@
|
|||||||
|
@echo off
|
||||||
|
REM Double-click to run %~n0.ps1 with UAC elevation.
|
||||||
|
REM All output goes to this window AND C:\Windows\Temp\setup.log.
|
||||||
|
fltmc >nul 2>&1
|
||||||
|
if %errorLevel% neq 0 (
|
||||||
|
powershell -NoProfile -Command "Start-Process -FilePath '%~f0' -Verb RunAs"
|
||||||
|
exit /b
|
||||||
|
)
|
||||||
|
echo ============================================================
|
||||||
|
echo Running: %~n0
|
||||||
|
echo Log : C:\Windows\Temp\setup.log
|
||||||
|
echo ============================================================
|
||||||
|
echo.
|
||||||
|
powershell.exe -NoProfile -ExecutionPolicy Bypass -File "%~dpn0.ps1"
|
||||||
|
set RC=%errorLevel%
|
||||||
|
echo.
|
||||||
|
echo ============================================================
|
||||||
|
echo Done (exit code %RC%)
|
||||||
|
echo ============================================================
|
||||||
|
pause
|
||||||
10
steps/12-winget-install-chrome.ps1
Normal file
10
steps/12-winget-install-chrome.ps1
Normal file
@@ -0,0 +1,10 @@
|
|||||||
|
. "$PSScriptRoot\_common.ps1"
|
||||||
|
|
||||||
|
Section 'winget-install-chrome' {
|
||||||
|
Wait-Network -timeoutSec 30
|
||||||
|
$winget = (Get-Command winget -ErrorAction SilentlyContinue).Source
|
||||||
|
if (-not $winget) { Log 'winget not found (Win10 沒裝 App Installer?)'; return }
|
||||||
|
& $winget install --id Google.Chrome -e --silent --source winget `
|
||||||
|
--accept-source-agreements --accept-package-agreements --scope machine 2>&1 |
|
||||||
|
ForEach-Object { Log " winget: $_" }
|
||||||
|
}
|
||||||
20
steps/13-remove-windows-ai.bat
Normal file
20
steps/13-remove-windows-ai.bat
Normal file
@@ -0,0 +1,20 @@
|
|||||||
|
@echo off
|
||||||
|
REM Double-click to run %~n0.ps1 with UAC elevation.
|
||||||
|
REM All output goes to this window AND C:\Windows\Temp\setup.log.
|
||||||
|
fltmc >nul 2>&1
|
||||||
|
if %errorLevel% neq 0 (
|
||||||
|
powershell -NoProfile -Command "Start-Process -FilePath '%~f0' -Verb RunAs"
|
||||||
|
exit /b
|
||||||
|
)
|
||||||
|
echo ============================================================
|
||||||
|
echo Running: %~n0
|
||||||
|
echo Log : C:\Windows\Temp\setup.log
|
||||||
|
echo ============================================================
|
||||||
|
echo.
|
||||||
|
powershell.exe -NoProfile -ExecutionPolicy Bypass -File "%~dpn0.ps1"
|
||||||
|
set RC=%errorLevel%
|
||||||
|
echo.
|
||||||
|
echo ============================================================
|
||||||
|
echo Done (exit code %RC%)
|
||||||
|
echo ============================================================
|
||||||
|
pause
|
||||||
24
steps/13-remove-windows-ai.ps1
Normal file
24
steps/13-remove-windows-ai.ps1
Normal file
@@ -0,0 +1,24 @@
|
|||||||
|
. "$PSScriptRoot\_common.ps1"
|
||||||
|
|
||||||
|
Section 'remove-windows-ai' {
|
||||||
|
Wait-Network -timeoutSec 30
|
||||||
|
|
||||||
|
# 用顯式 options 取代 -AllOptions,排除 'UpdateCleanupCheck':
|
||||||
|
# 那段會跑 DISM /Cleanup-Image + sfc /scannow + 跳 MessageBox 問要不要重啟,
|
||||||
|
# 在 WinRM/nonInteractive/Session-0 下會 default Yes 觸發 Restart-Computer -Force,
|
||||||
|
# 把整個 RUN-ALL 流程打斷。其他 10 個 option 不會重啟。
|
||||||
|
$opts = @(
|
||||||
|
'DisableRegKeys',
|
||||||
|
'PreventAIPackageReinstall',
|
||||||
|
'DisableCopilotPolicies',
|
||||||
|
'RemoveAppxPackages',
|
||||||
|
'RemoveRecallFeature',
|
||||||
|
'RemoveCBSPackages',
|
||||||
|
'RemoveAIFiles',
|
||||||
|
'HideAIComponents',
|
||||||
|
'DisableRewrite',
|
||||||
|
'RemoveRecallTasks'
|
||||||
|
)
|
||||||
|
$sb = [scriptblock]::Create((Invoke-RestMethod 'https://raw.githubusercontent.com/zoicware/RemoveWindowsAI/main/RemoveWindowsAi.ps1'))
|
||||||
|
& $sb -nonInteractive -Options $opts -EnableLogging | Out-Null
|
||||||
|
}
|
||||||
20
steps/14-win11debloat.bat
Normal file
20
steps/14-win11debloat.bat
Normal file
@@ -0,0 +1,20 @@
|
|||||||
|
@echo off
|
||||||
|
REM Double-click to run %~n0.ps1 with UAC elevation.
|
||||||
|
REM All output goes to this window AND C:\Windows\Temp\setup.log.
|
||||||
|
fltmc >nul 2>&1
|
||||||
|
if %errorLevel% neq 0 (
|
||||||
|
powershell -NoProfile -Command "Start-Process -FilePath '%~f0' -Verb RunAs"
|
||||||
|
exit /b
|
||||||
|
)
|
||||||
|
echo ============================================================
|
||||||
|
echo Running: %~n0
|
||||||
|
echo Log : C:\Windows\Temp\setup.log
|
||||||
|
echo ============================================================
|
||||||
|
echo.
|
||||||
|
powershell.exe -NoProfile -ExecutionPolicy Bypass -File "%~dpn0.ps1"
|
||||||
|
set RC=%errorLevel%
|
||||||
|
echo.
|
||||||
|
echo ============================================================
|
||||||
|
echo Done (exit code %RC%)
|
||||||
|
echo ============================================================
|
||||||
|
pause
|
||||||
21
steps/14-win11debloat.ps1
Normal file
21
steps/14-win11debloat.ps1
Normal file
@@ -0,0 +1,21 @@
|
|||||||
|
. "$PSScriptRoot\_common.ps1"
|
||||||
|
|
||||||
|
Section 'win11debloat' {
|
||||||
|
Wait-Network -timeoutSec 30
|
||||||
|
$work = Join-Path $env:TEMP 'win11debloat'
|
||||||
|
$zip = "$work.zip"
|
||||||
|
if (Test-Path $work) { Remove-Item $work -Recurse -Force }
|
||||||
|
Invoke-WebRequest -UseBasicParsing -Uri 'https://github.com/Raphire/Win11Debloat/archive/refs/heads/master.zip' -OutFile $zip
|
||||||
|
Expand-Archive -Path $zip -DestinationPath $work -Force
|
||||||
|
$dir = Get-ChildItem $work -Directory | Select-Object -First 1
|
||||||
|
if (-not $dir) { throw 'Win11Debloat zip extracted but no inner dir' }
|
||||||
|
|
||||||
|
$cfgSrc = Join-Path $PSScriptRoot 'win11debloat-config.json'
|
||||||
|
$cfgDst = Join-Path $dir.FullName 'unattend-config.json'
|
||||||
|
Copy-Item $cfgSrc $cfgDst -Force
|
||||||
|
|
||||||
|
# -Sysprep 讓 Win11Debloat 把所有 HKCU 設定寫到 Default profile 的 offline hive,
|
||||||
|
# 避免 HKCU\SearchSettings 被 Search Indexer 鎖住造成 reg import 失敗,
|
||||||
|
# 同時符合「Admin 會被隱藏、未來只有 User 登入」的部署模式
|
||||||
|
& "$($dir.FullName)\Win11Debloat.ps1" -Silent -Sysprep -Config $cfgDst -NoRestartExplorer
|
||||||
|
}
|
||||||
20
steps/15-remove-uwp-apps.bat
Normal file
20
steps/15-remove-uwp-apps.bat
Normal file
@@ -0,0 +1,20 @@
|
|||||||
|
@echo off
|
||||||
|
REM Double-click to run %~n0.ps1 with UAC elevation.
|
||||||
|
REM All output goes to this window AND C:\Windows\Temp\setup.log.
|
||||||
|
fltmc >nul 2>&1
|
||||||
|
if %errorLevel% neq 0 (
|
||||||
|
powershell -NoProfile -Command "Start-Process -FilePath '%~f0' -Verb RunAs"
|
||||||
|
exit /b
|
||||||
|
)
|
||||||
|
echo ============================================================
|
||||||
|
echo Running: %~n0
|
||||||
|
echo Log : C:\Windows\Temp\setup.log
|
||||||
|
echo ============================================================
|
||||||
|
echo.
|
||||||
|
powershell.exe -NoProfile -ExecutionPolicy Bypass -File "%~dpn0.ps1"
|
||||||
|
set RC=%errorLevel%
|
||||||
|
echo.
|
||||||
|
echo ============================================================
|
||||||
|
echo Done (exit code %RC%)
|
||||||
|
echo ============================================================
|
||||||
|
pause
|
||||||
35
steps/15-remove-uwp-apps.ps1
Normal file
35
steps/15-remove-uwp-apps.ps1
Normal file
@@ -0,0 +1,35 @@
|
|||||||
|
. "$PSScriptRoot\_common.ps1"
|
||||||
|
|
||||||
|
$UwpRemoveList = @(
|
||||||
|
'Microsoft.BingNews','Microsoft.BingWeather','Microsoft.GetHelp',
|
||||||
|
'Microsoft.MicrosoftSolitaireCollection','Microsoft.Todos','Microsoft.Windows.DevHome',
|
||||||
|
'Microsoft.WindowsAlarms','Microsoft.WindowsCamera','Microsoft.WindowsFeedbackHub',
|
||||||
|
'Microsoft.WindowsSoundRecorder','Microsoft.Xbox.TCUI','Microsoft.XboxGameCallableUI',
|
||||||
|
'Microsoft.XboxIdentityProvider','Microsoft.XboxSpeechToTextOverlay','Microsoft.YourPhone',
|
||||||
|
'Microsoft.ZuneMusic','MicrosoftCorporationII.QuickAssist',
|
||||||
|
'MicrosoftWindows.Client.WebExperience','MicrosoftWindows.CrossDevice','MSTeams',
|
||||||
|
'Microsoft.PowerAutomateDesktop','Microsoft.Windows.Photos'
|
||||||
|
)
|
||||||
|
|
||||||
|
Section 'remove-uwp-apps' {
|
||||||
|
foreach ($name in $UwpRemoveList) {
|
||||||
|
Get-AppxPackage -AllUsers -Name $name -ErrorAction SilentlyContinue | ForEach-Object {
|
||||||
|
try {
|
||||||
|
Remove-AppxPackage -AllUsers -Package $_.PackageFullName -ErrorAction Stop
|
||||||
|
Log "Removed AppxPackage $name"
|
||||||
|
} catch {
|
||||||
|
Log "Skip AppxPackage $name : $($_.Exception.Message)"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Get-AppxProvisionedPackage -Online -ErrorAction SilentlyContinue |
|
||||||
|
Where-Object { $_.DisplayName -eq $name } |
|
||||||
|
ForEach-Object {
|
||||||
|
try {
|
||||||
|
Remove-AppxProvisionedPackage -Online -PackageName $_.PackageName -ErrorAction Stop | Out-Null
|
||||||
|
Log "Removed Provisioned $name"
|
||||||
|
} catch {
|
||||||
|
Log "Skip Provisioned $name : $($_.Exception.Message)"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
20
steps/16-install-telegram.bat
Normal file
20
steps/16-install-telegram.bat
Normal file
@@ -0,0 +1,20 @@
|
|||||||
|
@echo off
|
||||||
|
REM Double-click to run %~n0.ps1 with UAC elevation.
|
||||||
|
REM All output goes to this window AND C:\Windows\Temp\setup.log.
|
||||||
|
fltmc >nul 2>&1
|
||||||
|
if %errorLevel% neq 0 (
|
||||||
|
powershell -NoProfile -Command "Start-Process -FilePath '%~f0' -Verb RunAs"
|
||||||
|
exit /b
|
||||||
|
)
|
||||||
|
echo ============================================================
|
||||||
|
echo Running: %~n0
|
||||||
|
echo Log : C:\Windows\Temp\setup.log
|
||||||
|
echo ============================================================
|
||||||
|
echo.
|
||||||
|
powershell.exe -NoProfile -ExecutionPolicy Bypass -File "%~dpn0.ps1"
|
||||||
|
set RC=%errorLevel%
|
||||||
|
echo.
|
||||||
|
echo ============================================================
|
||||||
|
echo Done (exit code %RC%)
|
||||||
|
echo ============================================================
|
||||||
|
pause
|
||||||
9
steps/16-install-telegram.ps1
Normal file
9
steps/16-install-telegram.ps1
Normal file
@@ -0,0 +1,9 @@
|
|||||||
|
. "$PSScriptRoot\_common.ps1"
|
||||||
|
|
||||||
|
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)"
|
||||||
|
}
|
||||||
20
steps/17-resume-trigger-wu.bat
Normal file
20
steps/17-resume-trigger-wu.bat
Normal file
@@ -0,0 +1,20 @@
|
|||||||
|
@echo off
|
||||||
|
REM Double-click to run %~n0.ps1 with UAC elevation.
|
||||||
|
REM All output goes to this window AND C:\Windows\Temp\setup.log.
|
||||||
|
fltmc >nul 2>&1
|
||||||
|
if %errorLevel% neq 0 (
|
||||||
|
powershell -NoProfile -Command "Start-Process -FilePath '%~f0' -Verb RunAs"
|
||||||
|
exit /b
|
||||||
|
)
|
||||||
|
echo ============================================================
|
||||||
|
echo Running: %~n0
|
||||||
|
echo Log : C:\Windows\Temp\setup.log
|
||||||
|
echo ============================================================
|
||||||
|
echo.
|
||||||
|
powershell.exe -NoProfile -ExecutionPolicy Bypass -File "%~dpn0.ps1"
|
||||||
|
set RC=%errorLevel%
|
||||||
|
echo.
|
||||||
|
echo ============================================================
|
||||||
|
echo Done (exit code %RC%)
|
||||||
|
echo ============================================================
|
||||||
|
pause
|
||||||
30
steps/17-resume-trigger-wu.ps1
Normal file
30
steps/17-resume-trigger-wu.ps1
Normal file
@@ -0,0 +1,30 @@
|
|||||||
|
. "$PSScriptRoot\_common.ps1"
|
||||||
|
|
||||||
|
Section 'resume-and-trigger-windows-update' {
|
||||||
|
$ux = 'HKLM:\SOFTWARE\Microsoft\WindowsUpdate\UX\Settings'
|
||||||
|
foreach ($n in @('PauseUpdatesStartTime','PauseUpdatesExpiryTime',
|
||||||
|
'PauseFeatureUpdatesStartTime','PauseFeatureUpdatesEndTime',
|
||||||
|
'PauseQualityUpdatesStartTime','PauseQualityUpdatesEndTime')) {
|
||||||
|
Remove-ItemProperty -Path $ux -Name $n -ErrorAction SilentlyContinue
|
||||||
|
}
|
||||||
|
|
||||||
|
foreach ($svc in @('BITS','wuauserv','UsoSvc')) {
|
||||||
|
Start-Service -Name $svc -ErrorAction SilentlyContinue
|
||||||
|
}
|
||||||
|
|
||||||
|
$uso = "$env:SystemRoot\System32\UsoClient.exe"
|
||||||
|
if (Test-Path $uso) {
|
||||||
|
& $uso RefreshSettings | Out-Null
|
||||||
|
& $uso StartScan | Out-Null
|
||||||
|
& $uso StartDownload | Out-Null
|
||||||
|
& $uso StartInstall | Out-Null
|
||||||
|
Log 'WU resumed; UsoClient scan/download/install triggered'
|
||||||
|
} else {
|
||||||
|
try {
|
||||||
|
(New-Object -ComObject Microsoft.Update.AutoUpdate).DetectNow()
|
||||||
|
Log 'WU resumed; AutoUpdate.DetectNow triggered (COM fallback)'
|
||||||
|
} catch {
|
||||||
|
Log "WU resumed but trigger failed: $($_.Exception.Message)"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
53
steps/README.txt
Normal file
53
steps/README.txt
Normal file
@@ -0,0 +1,53 @@
|
|||||||
|
steps/ — 拆解後的 post-install 步驟,每段一個 .bat 雙擊執行
|
||||||
|
==========================================================
|
||||||
|
|
||||||
|
用法
|
||||||
|
----
|
||||||
|
1. 把 USB 插上 Windows 機器
|
||||||
|
2. 用檔案總管打開 D:\ventoy\script\steps\(D 換成 USB 在 Windows 看到的代號)
|
||||||
|
3. 雙擊任一個 NN-xxx.bat(會自動 UAC 提權)
|
||||||
|
4. 黑色 console 視窗會即時顯示 START / DONE / ERR
|
||||||
|
5. 跑完按任意鍵關掉視窗
|
||||||
|
|
||||||
|
想一次跑完,雙擊 RUN-ALL.bat 即可。
|
||||||
|
|
||||||
|
順序建議
|
||||||
|
--------
|
||||||
|
Phase 1(不需要網路;本機設定)
|
||||||
|
01-firewall-ssh-22 防火牆開 SSH 22
|
||||||
|
02-rdp-enable-3389 打開 RDP
|
||||||
|
03-icmp-echo-allow 允許 ping
|
||||||
|
04-winrm-enable 啟用 WinRM
|
||||||
|
05-onedrive-remove 移除 OneDrive
|
||||||
|
06-cortana-websearch-off 關 Cortana / Web Search
|
||||||
|
07-apply-ui-ime-default-profile UI/IME 預設套到 Default profile
|
||||||
|
08-hide-admin-account 把 Admin 從登入畫面藏掉
|
||||||
|
09-pause-windows-update 暫停 WU(避免下面動作搶頻寬)
|
||||||
|
|
||||||
|
Phase 2(需要網路;下載安裝)
|
||||||
|
10-openssh-server-install OpenSSH Server FoD
|
||||||
|
11-kms-activate KMS 啟用
|
||||||
|
12-winget-install-chrome 裝 Chrome
|
||||||
|
13-remove-windows-ai RemoveWindowsAI 線上腳本
|
||||||
|
14-win11debloat Win11Debloat(讀同目錄 win11debloat-config.json)
|
||||||
|
15-remove-uwp-apps 批次移除 UWP
|
||||||
|
16-install-telegram 裝 Telegram
|
||||||
|
|
||||||
|
收尾
|
||||||
|
17-resume-trigger-wu 解除 WU 暫停 + 觸發掃描
|
||||||
|
|
||||||
|
Log
|
||||||
|
---
|
||||||
|
所有 step.ps1 共用同一個 log:
|
||||||
|
C:\Windows\Temp\setup.log
|
||||||
|
|
||||||
|
每段會印 [時間] === 段名 START === / DONE === / ERR ===
|
||||||
|
|
||||||
|
檔案結構
|
||||||
|
--------
|
||||||
|
_common.ps1 共用 helper(Log / Section / Set-RegValue / Wait-Network)
|
||||||
|
_template.bat .bat 樣板(不要動)
|
||||||
|
NN-xxx.ps1 各段邏輯
|
||||||
|
NN-xxx.bat 各段 .bat(自動 UAC + 跑 .ps1)
|
||||||
|
win11debloat-config.json 14 段用的 JSON 設定
|
||||||
|
RUN-ALL.bat 依序跑 01..17 全部
|
||||||
27
steps/RUN-ALL.bat
Normal file
27
steps/RUN-ALL.bat
Normal file
@@ -0,0 +1,27 @@
|
|||||||
|
@echo off
|
||||||
|
REM RUN-ALL.bat - run steps 00..17 in order.
|
||||||
|
REM Each step runs independently; a failure in one does not stop the rest.
|
||||||
|
|
||||||
|
fltmc >nul 2>&1
|
||||||
|
if %errorLevel% neq 0 (
|
||||||
|
powershell -NoProfile -Command "Start-Process -FilePath '%~f0' -Verb RunAs"
|
||||||
|
exit /b
|
||||||
|
)
|
||||||
|
|
||||||
|
cd /d "%~dp0"
|
||||||
|
echo ============================================================
|
||||||
|
echo RUN-ALL: running steps 00..17 sequentially
|
||||||
|
echo Log : C:\Windows\Temp\setup.log
|
||||||
|
echo ============================================================
|
||||||
|
|
||||||
|
for %%F in (00-network-private 01-firewall-ssh-22 02-rdp-enable-3389 03-icmp-echo-allow 04-winrm-enable 05-onedrive-remove 06-cortana-websearch-off 07-apply-ui-ime-default-profile 08-hide-admin-account 09-pause-windows-update 10-openssh-server-install 11-kms-activate 12-winget-install-chrome 13-remove-windows-ai 14-win11debloat 15-remove-uwp-apps 16-install-telegram 17-resume-trigger-wu) do (
|
||||||
|
echo.
|
||||||
|
echo --- %%F ---
|
||||||
|
powershell.exe -NoProfile -ExecutionPolicy Bypass -File "%~dp0%%F.ps1"
|
||||||
|
)
|
||||||
|
|
||||||
|
echo.
|
||||||
|
echo ============================================================
|
||||||
|
echo RUN-ALL done.
|
||||||
|
echo ============================================================
|
||||||
|
pause
|
||||||
26
steps/_admin-shell.bat
Normal file
26
steps/_admin-shell.bat
Normal file
@@ -0,0 +1,26 @@
|
|||||||
|
@echo off
|
||||||
|
REM _admin-shell.bat - opens an elevated cmd in steps\.
|
||||||
|
REM Run this once, enter Admin password, then call any step .bat
|
||||||
|
REM from inside the elevated window without further UAC prompts.
|
||||||
|
|
||||||
|
fltmc >nul 2>&1
|
||||||
|
if %errorLevel% neq 0 (
|
||||||
|
powershell -NoProfile -Command "Start-Process -FilePath '%~f0' -Verb RunAs"
|
||||||
|
exit /b
|
||||||
|
)
|
||||||
|
cd /d "%~dp0"
|
||||||
|
|
||||||
|
echo ============================================================
|
||||||
|
echo Admin shell opened at: %~dp0
|
||||||
|
whoami /groups | findstr /i "S-1-5-32-544 BUILTIN\Administrators" >nul && echo [OK] elevated as Administrator || echo [WARN] NOT elevated
|
||||||
|
echo ============================================================
|
||||||
|
echo Run any step .bat without further UAC prompts, e.g.:
|
||||||
|
echo 01-firewall-ssh-22.bat
|
||||||
|
echo 02-rdp-enable-3389.bat
|
||||||
|
echo ...
|
||||||
|
echo RUN-ALL.bat runs all 17 steps in order
|
||||||
|
echo exit close this window
|
||||||
|
echo ============================================================
|
||||||
|
echo.
|
||||||
|
|
||||||
|
cmd /K
|
||||||
47
steps/_common.ps1
Normal file
47
steps/_common.ps1
Normal file
@@ -0,0 +1,47 @@
|
|||||||
|
# _common.ps1 — 給 steps/*.ps1 dot-source 用的共用 helper
|
||||||
|
# 每個 step.ps1 開頭會:. "$PSScriptRoot\_common.ps1"
|
||||||
|
|
||||||
|
$ErrorActionPreference = 'Continue'
|
||||||
|
$ProgressPreference = 'SilentlyContinue'
|
||||||
|
[Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12
|
||||||
|
|
||||||
|
$global:LogFile = 'C:\Windows\Temp\setup.log'
|
||||||
|
|
||||||
|
if (-not (Test-Path 'C:\Windows\Temp')) {
|
||||||
|
New-Item -ItemType Directory -Path 'C:\Windows\Temp' -Force | Out-Null
|
||||||
|
}
|
||||||
|
|
||||||
|
function Log {
|
||||||
|
param([string]$msg)
|
||||||
|
$line = '[{0}] {1}' -f (Get-Date -Format 'yyyy-MM-dd HH:mm:ss'), $msg
|
||||||
|
Add-Content -Path $LogFile -Value $line -Encoding UTF8
|
||||||
|
Write-Host $line
|
||||||
|
}
|
||||||
|
|
||||||
|
function Section {
|
||||||
|
param([string]$name, [scriptblock]$block)
|
||||||
|
Log "=== $name START ==="
|
||||||
|
try {
|
||||||
|
& $block
|
||||||
|
Log "=== $name DONE ==="
|
||||||
|
} catch {
|
||||||
|
Log "=== $name ERR: $($_.Exception.Message) ==="
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function Set-RegValue {
|
||||||
|
param([string]$Path, [string]$Name, $Value, [string]$Type = 'DWord')
|
||||||
|
if (-not (Test-Path $Path)) { New-Item -Path $Path -Force | Out-Null }
|
||||||
|
New-ItemProperty -Path $Path -Name $Name -Value $Value -PropertyType $Type -Force | Out-Null
|
||||||
|
}
|
||||||
|
|
||||||
|
function Wait-Network {
|
||||||
|
param([int]$timeoutSec = 60)
|
||||||
|
$i = 0
|
||||||
|
$max = [int]($timeoutSec / 2)
|
||||||
|
while ($i -lt $max -and -not (Test-Connection 8.8.8.8 -Count 1 -Quiet -ErrorAction SilentlyContinue)) {
|
||||||
|
Start-Sleep 2
|
||||||
|
$i++
|
||||||
|
}
|
||||||
|
Log "Network wait: $($i*2)s"
|
||||||
|
}
|
||||||
20
steps/_template.bat
Normal file
20
steps/_template.bat
Normal file
@@ -0,0 +1,20 @@
|
|||||||
|
@echo off
|
||||||
|
REM Double-click to run %~n0.ps1 with UAC elevation.
|
||||||
|
REM All output goes to this window AND C:\Windows\Temp\setup.log.
|
||||||
|
fltmc >nul 2>&1
|
||||||
|
if %errorLevel% neq 0 (
|
||||||
|
powershell -NoProfile -Command "Start-Process -FilePath '%~f0' -Verb RunAs"
|
||||||
|
exit /b
|
||||||
|
)
|
||||||
|
echo ============================================================
|
||||||
|
echo Running: %~n0
|
||||||
|
echo Log : C:\Windows\Temp\setup.log
|
||||||
|
echo ============================================================
|
||||||
|
echo.
|
||||||
|
powershell.exe -NoProfile -ExecutionPolicy Bypass -File "%~dpn0.ps1"
|
||||||
|
set RC=%errorLevel%
|
||||||
|
echo.
|
||||||
|
echo ============================================================
|
||||||
|
echo Done (exit code %RC%)
|
||||||
|
echo ============================================================
|
||||||
|
pause
|
||||||
48
steps/win11debloat-config.json
Normal file
48
steps/win11debloat-config.json
Normal file
@@ -0,0 +1,48 @@
|
|||||||
|
{
|
||||||
|
"Version": "1.0",
|
||||||
|
"Tweaks": [
|
||||||
|
{ "Name": "RemoveApps", "Value": true },
|
||||||
|
{ "Name": "RemoveGamingApps", "Value": true },
|
||||||
|
{ "Name": "RemoveCommApps", "Value": true },
|
||||||
|
{ "Name": "RemoveW11Outlook", "Value": true },
|
||||||
|
{ "Name": "DisableTelemetry", "Value": true },
|
||||||
|
{ "Name": "DisableBing", "Value": true },
|
||||||
|
{ "Name": "DisableStoreSearchSuggestions", "Value": true },
|
||||||
|
{ "Name": "DisableLockscreenTips", "Value": true },
|
||||||
|
{ "Name": "DisableSuggestions", "Value": true },
|
||||||
|
{ "Name": "DisableDesktopSpotlight", "Value": true },
|
||||||
|
{ "Name": "DisableFindMyDevice", "Value": true },
|
||||||
|
{ "Name": "DisableEdgeAds", "Value": true },
|
||||||
|
{ "Name": "DisableBraveBloat", "Value": true },
|
||||||
|
{ "Name": "DisableSettings365Ads", "Value": true },
|
||||||
|
{ "Name": "DisableSettingsHome", "Value": true },
|
||||||
|
{ "Name": "DisableCopilot", "Value": true },
|
||||||
|
{ "Name": "DisableRecall", "Value": true },
|
||||||
|
{ "Name": "DisableClickToDo", "Value": true },
|
||||||
|
{ "Name": "DisableAISvcAutoStart", "Value": true },
|
||||||
|
{ "Name": "DisablePaintAI", "Value": true },
|
||||||
|
{ "Name": "DisableNotepadAI", "Value": true },
|
||||||
|
{ "Name": "DisableEdgeAI", "Value": true },
|
||||||
|
{ "Name": "PreventUpdateAutoReboot", "Value": true },
|
||||||
|
{ "Name": "DisableModernStandbyNetworking", "Value": true },
|
||||||
|
{ "Name": "DisableDVR", "Value": true },
|
||||||
|
{ "Name": "DisableGameBarIntegration", "Value": true },
|
||||||
|
{ "Name": "ShowHiddenFolders", "Value": true },
|
||||||
|
{ "Name": "ShowKnownFileExt", "Value": true },
|
||||||
|
{ "Name": "EnableDarkMode", "Value": true },
|
||||||
|
{ "Name": "TaskbarAlignLeft", "Value": true },
|
||||||
|
{ "Name": "HideTaskview", "Value": true },
|
||||||
|
{ "Name": "HideChat", "Value": true },
|
||||||
|
{ "Name": "DisableWidgets", "Value": true },
|
||||||
|
{ "Name": "DisableStartRecommended", "Value": true },
|
||||||
|
{ "Name": "Hide3dObjects", "Value": true },
|
||||||
|
{ "Name": "ExplorerToThisPC", "Value": true },
|
||||||
|
{ "Name": "HideGallery", "Value": true },
|
||||||
|
{ "Name": "DisableDragTray", "Value": true }
|
||||||
|
],
|
||||||
|
"Deployment": [
|
||||||
|
{ "Name": "CreateRestorePoint", "Value": true },
|
||||||
|
{ "Name": "RestartExplorer", "Value": false },
|
||||||
|
{ "Name": "AppRemovalScopeIndex", "Value": 0 }
|
||||||
|
]
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user