diff --git a/Run-Setup.bat b/Run-Setup.bat new file mode 100644 index 0000000..c3e54ca --- /dev/null +++ b/Run-Setup.bat @@ -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 diff --git a/steps/00-network-private.bat b/steps/00-network-private.bat new file mode 100644 index 0000000..5126609 --- /dev/null +++ b/steps/00-network-private.bat @@ -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 diff --git a/steps/00-network-private.ps1 b/steps/00-network-private.ps1 new file mode 100644 index 0000000..6e1744d --- /dev/null +++ b/steps/00-network-private.ps1 @@ -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' + } + } +} diff --git a/steps/01-firewall-ssh-22.bat b/steps/01-firewall-ssh-22.bat new file mode 100644 index 0000000..5126609 --- /dev/null +++ b/steps/01-firewall-ssh-22.bat @@ -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 diff --git a/steps/01-firewall-ssh-22.ps1 b/steps/01-firewall-ssh-22.ps1 new file mode 100644 index 0000000..fde1730 --- /dev/null +++ b/steps/01-firewall-ssh-22.ps1 @@ -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 +} diff --git a/steps/02-rdp-enable-3389.bat b/steps/02-rdp-enable-3389.bat new file mode 100644 index 0000000..5126609 --- /dev/null +++ b/steps/02-rdp-enable-3389.bat @@ -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 diff --git a/steps/02-rdp-enable-3389.ps1 b/steps/02-rdp-enable-3389.ps1 new file mode 100644 index 0000000..85c6ab9 --- /dev/null +++ b/steps/02-rdp-enable-3389.ps1 @@ -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 +} diff --git a/steps/03-icmp-echo-allow.bat b/steps/03-icmp-echo-allow.bat new file mode 100644 index 0000000..5126609 --- /dev/null +++ b/steps/03-icmp-echo-allow.bat @@ -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 diff --git a/steps/03-icmp-echo-allow.ps1 b/steps/03-icmp-echo-allow.ps1 new file mode 100644 index 0000000..4a1d3cc --- /dev/null +++ b/steps/03-icmp-echo-allow.ps1 @@ -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 +} diff --git a/steps/04-winrm-enable.bat b/steps/04-winrm-enable.bat new file mode 100644 index 0000000..5126609 --- /dev/null +++ b/steps/04-winrm-enable.bat @@ -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 diff --git a/steps/04-winrm-enable.ps1 b/steps/04-winrm-enable.ps1 new file mode 100644 index 0000000..61297df --- /dev/null +++ b/steps/04-winrm-enable.ps1 @@ -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 +} diff --git a/steps/05-onedrive-remove.bat b/steps/05-onedrive-remove.bat new file mode 100644 index 0000000..5126609 --- /dev/null +++ b/steps/05-onedrive-remove.bat @@ -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 diff --git a/steps/05-onedrive-remove.ps1 b/steps/05-onedrive-remove.ps1 new file mode 100644 index 0000000..84dc9ac --- /dev/null +++ b/steps/05-onedrive-remove.ps1 @@ -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 +} diff --git a/steps/06-cortana-websearch-off.bat b/steps/06-cortana-websearch-off.bat new file mode 100644 index 0000000..5126609 --- /dev/null +++ b/steps/06-cortana-websearch-off.bat @@ -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 diff --git a/steps/06-cortana-websearch-off.ps1 b/steps/06-cortana-websearch-off.ps1 new file mode 100644 index 0000000..9663aa4 --- /dev/null +++ b/steps/06-cortana-websearch-off.ps1 @@ -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 +} diff --git a/steps/07-apply-ui-ime-default-profile.bat b/steps/07-apply-ui-ime-default-profile.bat new file mode 100644 index 0000000..5126609 --- /dev/null +++ b/steps/07-apply-ui-ime-default-profile.bat @@ -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 diff --git a/steps/07-apply-ui-ime-default-profile.ps1 b/steps/07-apply-ui-ime-default-profile.ps1 new file mode 100644 index 0000000..b0239e1 --- /dev/null +++ b/steps/07-apply-ui-ime-default-profile.ps1 @@ -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 + } +} diff --git a/steps/08-hide-admin-account.bat b/steps/08-hide-admin-account.bat new file mode 100644 index 0000000..5126609 --- /dev/null +++ b/steps/08-hide-admin-account.bat @@ -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 diff --git a/steps/08-hide-admin-account.ps1 b/steps/08-hide-admin-account.ps1 new file mode 100644 index 0000000..c92d746 --- /dev/null +++ b/steps/08-hide-admin-account.ps1 @@ -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 +} diff --git a/steps/09-pause-windows-update.bat b/steps/09-pause-windows-update.bat new file mode 100644 index 0000000..5126609 --- /dev/null +++ b/steps/09-pause-windows-update.bat @@ -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 diff --git a/steps/09-pause-windows-update.ps1 b/steps/09-pause-windows-update.ps1 new file mode 100644 index 0000000..6300592 --- /dev/null +++ b/steps/09-pause-windows-update.ps1 @@ -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 + } +} diff --git a/steps/10-openssh-server-install.bat b/steps/10-openssh-server-install.bat new file mode 100644 index 0000000..5126609 --- /dev/null +++ b/steps/10-openssh-server-install.bat @@ -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 diff --git a/steps/10-openssh-server-install.ps1 b/steps/10-openssh-server-install.ps1 new file mode 100644 index 0000000..07b560c --- /dev/null +++ b/steps/10-openssh-server-install.ps1 @@ -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 +} diff --git a/steps/11-kms-activate.bat b/steps/11-kms-activate.bat new file mode 100644 index 0000000..5126609 --- /dev/null +++ b/steps/11-kms-activate.bat @@ -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 diff --git a/steps/11-kms-activate.ps1 b/steps/11-kms-activate.ps1 new file mode 100644 index 0000000..f868cb7 --- /dev/null +++ b/steps/11-kms-activate.ps1 @@ -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' } +} diff --git a/steps/12-winget-install-chrome.bat b/steps/12-winget-install-chrome.bat new file mode 100644 index 0000000..5126609 --- /dev/null +++ b/steps/12-winget-install-chrome.bat @@ -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 diff --git a/steps/12-winget-install-chrome.ps1 b/steps/12-winget-install-chrome.ps1 new file mode 100644 index 0000000..63c3f0d --- /dev/null +++ b/steps/12-winget-install-chrome.ps1 @@ -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: $_" } +} diff --git a/steps/13-remove-windows-ai.bat b/steps/13-remove-windows-ai.bat new file mode 100644 index 0000000..5126609 --- /dev/null +++ b/steps/13-remove-windows-ai.bat @@ -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 diff --git a/steps/13-remove-windows-ai.ps1 b/steps/13-remove-windows-ai.ps1 new file mode 100644 index 0000000..7ee16c6 --- /dev/null +++ b/steps/13-remove-windows-ai.ps1 @@ -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 +} diff --git a/steps/14-win11debloat.bat b/steps/14-win11debloat.bat new file mode 100644 index 0000000..5126609 --- /dev/null +++ b/steps/14-win11debloat.bat @@ -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 diff --git a/steps/14-win11debloat.ps1 b/steps/14-win11debloat.ps1 new file mode 100644 index 0000000..dae90e9 --- /dev/null +++ b/steps/14-win11debloat.ps1 @@ -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 +} diff --git a/steps/15-remove-uwp-apps.bat b/steps/15-remove-uwp-apps.bat new file mode 100644 index 0000000..5126609 --- /dev/null +++ b/steps/15-remove-uwp-apps.bat @@ -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 diff --git a/steps/15-remove-uwp-apps.ps1 b/steps/15-remove-uwp-apps.ps1 new file mode 100644 index 0000000..2aae75f --- /dev/null +++ b/steps/15-remove-uwp-apps.ps1 @@ -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)" + } + } + } +} diff --git a/steps/16-install-telegram.bat b/steps/16-install-telegram.bat new file mode 100644 index 0000000..5126609 --- /dev/null +++ b/steps/16-install-telegram.bat @@ -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 diff --git a/steps/16-install-telegram.ps1 b/steps/16-install-telegram.ps1 new file mode 100644 index 0000000..01338c6 --- /dev/null +++ b/steps/16-install-telegram.ps1 @@ -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)" +} diff --git a/steps/17-resume-trigger-wu.bat b/steps/17-resume-trigger-wu.bat new file mode 100644 index 0000000..5126609 --- /dev/null +++ b/steps/17-resume-trigger-wu.bat @@ -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 diff --git a/steps/17-resume-trigger-wu.ps1 b/steps/17-resume-trigger-wu.ps1 new file mode 100644 index 0000000..3358127 --- /dev/null +++ b/steps/17-resume-trigger-wu.ps1 @@ -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)" + } + } +} diff --git a/steps/README.txt b/steps/README.txt new file mode 100644 index 0000000..d64a054 --- /dev/null +++ b/steps/README.txt @@ -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 全部 diff --git a/steps/RUN-ALL.bat b/steps/RUN-ALL.bat new file mode 100644 index 0000000..1347f5b --- /dev/null +++ b/steps/RUN-ALL.bat @@ -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 diff --git a/steps/_admin-shell.bat b/steps/_admin-shell.bat new file mode 100644 index 0000000..650a554 --- /dev/null +++ b/steps/_admin-shell.bat @@ -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 diff --git a/steps/_common.ps1 b/steps/_common.ps1 new file mode 100644 index 0000000..ec8eb70 --- /dev/null +++ b/steps/_common.ps1 @@ -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" +} diff --git a/steps/_template.bat b/steps/_template.bat new file mode 100644 index 0000000..5126609 --- /dev/null +++ b/steps/_template.bat @@ -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 diff --git a/steps/win11debloat-config.json b/steps/win11debloat-config.json new file mode 100644 index 0000000..2f802fa --- /dev/null +++ b/steps/win11debloat-config.json @@ -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 } + ] +}