diff --git a/Setup.ps1 b/Setup.ps1 index 75f76d9..7d53456 100644 --- a/Setup.ps1 +++ b/Setup.ps1 @@ -5,8 +5,10 @@ # # Log: C:\Windows\Temp\setup.log(每段都寫 START/DONE/ERR) # -# 順序:先做不需網路的本機設定(防火牆 / 註冊機碼 / Default profile), -# 再等網路,最後跑下載安裝(OpenSSH FoD / KMS / winget / RemoveAI / Win11Debloat / Telegram)。 +# 順序:開頭先暫停 Windows Update(避免跟本腳本搶頻寬/CPU), +# 再做不需網路的本機設定(防火牆 / 註冊機碼 / Default profile), +# 接著等網路,跑下載安裝(OpenSSH FoD / KMS / winget / RemoveAI / Win11Debloat / Telegram), +# 結尾解除 WU 暫停並主動觸發掃描,這樣更新會排在所有 post-install 之後才開始下載。 $ErrorActionPreference = 'Continue' $ProgressPreference = 'SilentlyContinue' @@ -30,60 +32,30 @@ $UwpRemoveList = @( 'Microsoft.PowerAutomateDesktop','Microsoft.Windows.Photos' ) -# Win11Debloat 的設定 JSON(與 toolkit/config/win11debloat-config.json 同步) -$Win11DebloatConfigJson = @' -{ - "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": "DisableSearchHistory", "Value": true }, - { "Name": "DisableBing", "Value": true }, - { "Name": "DisableStoreSearchSuggestions", "Value": true }, - { "Name": "DisableSearchHighlights", "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": "HideSearchTb", "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 } - ] +# Win11Debloat 的設定(與 toolkit/config/win11debloat-config.json 同步) +# 改用 hashtable + ConvertTo-Json,避免 here-string 在某些 PowerShell 環境 parse 失敗 +$Win11DebloatTweakNames = @( + 'RemoveApps','RemoveGamingApps','RemoveCommApps','RemoveW11Outlook', + 'DisableTelemetry','DisableSearchHistory','DisableBing','DisableStoreSearchSuggestions', + 'DisableSearchHighlights','DisableLockscreenTips','DisableSuggestions','DisableDesktopSpotlight', + 'DisableFindMyDevice','DisableEdgeAds','DisableBraveBloat','DisableSettings365Ads', + 'DisableSettingsHome','DisableCopilot','DisableRecall','DisableClickToDo', + 'DisableAISvcAutoStart','DisablePaintAI','DisableNotepadAI','DisableEdgeAI', + 'PreventUpdateAutoReboot','DisableModernStandbyNetworking','DisableDVR','DisableGameBarIntegration', + 'ShowHiddenFolders','ShowKnownFileExt','EnableDarkMode','TaskbarAlignLeft', + 'HideSearchTb','HideTaskview','HideChat','DisableWidgets','DisableStartRecommended', + 'Hide3dObjects','ExplorerToThisPC','HideGallery','DisableDragTray' +) +$Win11DebloatConfig = [ordered]@{ + Version = '1.0' + Tweaks = @($Win11DebloatTweakNames | ForEach-Object { [ordered]@{ Name = $_; Value = $true } }) + Deployment = @( + [ordered]@{ Name = 'CreateRestorePoint'; Value = $true }, + [ordered]@{ Name = 'RestartExplorer'; Value = $false }, + [ordered]@{ Name = 'AppRemovalScopeIndex'; Value = 0 } + ) } -'@ +$Win11DebloatConfigJson = $Win11DebloatConfig | ConvertTo-Json -Depth 5 # ---- helpers ---- @@ -91,6 +63,7 @@ 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 { @@ -126,6 +99,25 @@ function Set-RegValue { # ---- Phase 1: 本機設定(不需網路)---- +Section 'pause-windows-update' { + # 設定官方暫停旗標:暫停 24 小時(Setup.ps1 結尾會主動清掉並觸發掃描) + $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)" + + # 停掉已啟動的 WU 相關服務,避免在 Setup.ps1 期間搶頻寬/CPU + foreach ($svc in @('UsoSvc','wuauserv','BITS')) { + Stop-Service -Name $svc -Force -ErrorAction SilentlyContinue + } +} + Section 'firewall-ssh-22' { Remove-NetFirewallRule -DisplayName 'SSH TCP 22 (Allow Inbound)' -ErrorAction SilentlyContinue New-NetFirewallRule -DisplayName 'SSH TCP 22 (Allow Inbound)' ` @@ -324,6 +316,39 @@ Section 'install-telegram' { Log "Telegram installer exit code: $($proc.ExitCode)" } +Section 'resume-and-trigger-windows-update' { + # 清掉暫停旗標(pause-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 + } + + # 通知 Update Orchestrator 重新讀設定,然後立即掃描/下載/安裝 + $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 { + # 後備:呼叫 COM 觸發掃描 + 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)" + } + } +} + # 結尾:刪掉殘留的明碼回應檔 Section 'cleanup-unattend-files' { Remove-Item 'C:\Windows\Panther\unattend.xml' -Force -ErrorAction SilentlyContinue diff --git a/unattend.xml b/unattend.xml index 791b488..46afe58 100644 --- a/unattend.xml +++ b/unattend.xml @@ -169,8 +169,8 @@ 3 - cmd.exe /c "net user User 1234 /add & net user User /logonpasswordchg:yes" - 建立本機帳號 User(密碼 1234,首次登入強制改密) + cmd.exe /c "net user User /add & net user User /logonpasswordchg:yes" + 建立本機帳號 User(空密碼,首次登入強制設定新密碼) false @@ -181,8 +181,8 @@ 5 - cmd.exe /c "if exist C:\Scripts\Setup.ps1 (powershell.exe -NoProfile -ExecutionPolicy Bypass -File C:\Scripts\Setup.ps1) else (echo SETUP_NOT_FOUND %DATE% %TIME% > C:\Windows\Temp\firstlogon-runsetup.log)" - 執行 Setup.ps1(13 項 post-install:SSH/RDP/WinRM/KMS/Chrome/Debloat/Telegram/RemoveAI/UI/IME/重命名帳號…,log: C:\Windows\Temp\setup.log) + cmd.exe /c "(echo == firstlogon-runsetup %DATE% %TIME% == & if exist C:\Scripts\Setup.ps1 (powershell.exe -NoProfile -ExecutionPolicy Bypass -File C:\Scripts\Setup.ps1) else (echo SETUP_NOT_FOUND)) > C:\Windows\Temp\firstlogon-runsetup.log 2>&1" + 執行 Setup.ps1(所有 stdout/stderr 都收到 firstlogon-runsetup.log,含 parse error);正常 Setup.ps1 自身寫到 setup.log false