# Fresh Windows setup helper # Assumes backup/install drive is E: param( [switch]$Packages, [switch]$Tweaks, [switch]$Features, [switch]$Restore, [switch]$SkipMenu, [switch]$Custom ) $BackupRoot = "E:\" $LogFile = "$BackupRoot\Setup-Chatlo.log" $InstalledOK = @() $Failed = @() $Skipped = @() $CustomMode = $false function Test-IsAdmin { $identity = [Security.Principal.WindowsIdentity]::GetCurrent() $principal = [Security.Principal.WindowsPrincipal]$identity return $principal.IsInRole([Security.Principal.WindowsBuiltInRole]::Administrator) } function Restart-Elevated($Options) { $runner = if ($PSVersionTable.PSEdition -eq 'Core') { 'pwsh.exe' } else { 'powershell.exe' } $argList = @( '-NoProfile', '-ExecutionPolicy', 'Bypass', '-File', $PSCommandPath, '-SkipMenu' ) if ($Options.Packages) { $argList += '-Packages' } if ($Options.Tweaks) { $argList += '-Tweaks' } if ($Options.Features) { $argList += '-Features' } if ($Options.Restore) { $argList += '-Restore' } if ($Options.Custom) { $argList += '-Custom' } Write-Host "`nAdministrator rights are required for this setup." -ForegroundColor Yellow Write-Host "Approve the UAC prompt to continue..." -ForegroundColor Yellow Start-Process -FilePath $runner -Verb RunAs -ArgumentList $argList -Wait exit 0 } function Test-SetupNeedsAdmin($Options) { return $true } function Write-Step($Message) { Write-Host "`n==== $Message ====" -ForegroundColor Cyan Add-Content $LogFile "`n==== $Message ====" } function Test-WingetInstalled($Id) { $result = winget list --id $Id --exact 2>$null return ($LASTEXITCODE -eq 0 -and ($result -match [regex]::Escape($Id))) } function Install-WingetPackage($Id, $Name = $Id) { Write-Host "`nInstalling $Name..." -ForegroundColor Yellow try { if (Test-WingetInstalled $Id) { Write-Host "Already installed: $Name" -ForegroundColor DarkGray $script:Skipped += $Name return } winget install ` --id $Id ` --exact ` --silent ` --accept-package-agreements ` --accept-source-agreements if ($LASTEXITCODE -eq 0) { Write-Host "Installed: $Name" -ForegroundColor Green $script:InstalledOK += $Name } else { Write-Host "Failed: $Name - exit code $LASTEXITCODE" -ForegroundColor Red $script:Failed += "$Name ($Id) - exit code $LASTEXITCODE" } } catch { Write-Host "Exception installing $Name" -ForegroundColor Red Write-Host $_.Exception.Message -ForegroundColor Red $script:Failed += "$Name ($Id) - $($_.Exception.Message)" } } function Install-Feature($Name) { Write-Host "Installing Windows feature: $Name" -ForegroundColor Yellow try { Add-WindowsCapability -Online -Name $Name if ($LASTEXITCODE -eq 0 -or $?) { Write-Host "Feature installed/enabled: $Name" -ForegroundColor Green } else { Write-Host "Feature may have failed: $Name" -ForegroundColor Red $script:Failed += "Windows feature: $Name" } } catch { Write-Host "Exception installing feature $Name" -ForegroundColor Red Write-Host $_.Exception.Message -ForegroundColor Red $script:Failed += "Windows feature: $Name - $($_.Exception.Message)" } } function Show-SelectionUI ($Title, $Instruction, $Items) { Add-Type -AssemblyName System.Windows.Forms Add-Type -AssemblyName System.Drawing $form = New-Object System.Windows.Forms.Form $form.Text = $Title $form.Size = New-Object System.Drawing.Size(500, 720) $form.StartPosition = 'CenterScreen' $form.FormBorderStyle = 'FixedDialog' $form.MaximizeBox = $false $form.TopMost = $true $label = New-Object System.Windows.Forms.Label $label.Text = $Instruction $label.AutoSize = $true $label.Location = New-Object System.Drawing.Point(10, 15) $form.Controls.Add($label) $checkedListBox = New-Object System.Windows.Forms.CheckedListBox $checkedListBox.Location = New-Object System.Drawing.Point(10, 40) $checkedListBox.Size = New-Object System.Drawing.Size(460, 500) $checkedListBox.CheckOnClick = $true foreach ($item in $Items) { $display = "[$($item.Category)] $($item.Name)" $checkedListBox.Items.Add($display, $true) | Out-Null } $form.Controls.Add($checkedListBox) # Select All Button $selectAllBtn = New-Object System.Windows.Forms.Button $selectAllBtn.Text = "Select All" $selectAllBtn.Location = New-Object System.Drawing.Point(10, 550) $selectAllBtn.Size = New-Object System.Drawing.Size(100, 25) $selectAllBtn.Add_Click({ for ($i = 0; $i -lt $checkedListBox.Items.Count; $i++) { $checkedListBox.SetItemChecked($i, $true) } }) $form.Controls.Add($selectAllBtn) # Deselect All Button $deselectAllBtn = New-Object System.Windows.Forms.Button $deselectAllBtn.Text = "Deselect All" $deselectAllBtn.Location = New-Object System.Drawing.Point(120, 550) $deselectAllBtn.Size = New-Object System.Drawing.Size(100, 25) $deselectAllBtn.Add_Click({ for ($i = 0; $i -lt $checkedListBox.Items.Count; $i++) { $checkedListBox.SetItemChecked($i, $false) } }) $form.Controls.Add($deselectAllBtn) # Category Filter controls $catLabel = New-Object System.Windows.Forms.Label $catLabel.Text = "Filter Category:" $catLabel.Location = New-Object System.Drawing.Point(10, 588) $catLabel.Size = New-Object System.Drawing.Size(110, 20) $form.Controls.Add($catLabel) $catComboBox = New-Object System.Windows.Forms.ComboBox $catComboBox.Location = New-Object System.Drawing.Point(120, 585) $catComboBox.Size = New-Object System.Drawing.Size(180, 25) $catComboBox.DropDownStyle = [System.Windows.Forms.ComboBoxStyle]::DropDownList # Get unique categories $categories = $Items | ForEach-Object { $_.Category } | Select-Object -Unique | Sort-Object foreach ($cat in $categories) { $catComboBox.Items.Add($cat) | Out-Null } if ($catComboBox.Items.Count -gt 0) { $catComboBox.SelectedIndex = 0 } $form.Controls.Add($catComboBox) # Check Category Button $checkCatBtn = New-Object System.Windows.Forms.Button $checkCatBtn.Text = "Check Cat" $checkCatBtn.Location = New-Object System.Drawing.Point(310, 584) $checkCatBtn.Size = New-Object System.Drawing.Size(75, 25) $checkCatBtn.Add_Click({ $selectedCat = $catComboBox.SelectedItem if ($null -ne $selectedCat) { $prefix = "[$selectedCat]" for ($i = 0; $i -lt $checkedListBox.Items.Count; $i++) { if ($checkedListBox.Items[$i].StartsWith($prefix)) { $checkedListBox.SetItemChecked($i, $true) } } } }) $form.Controls.Add($checkCatBtn) # Uncheck Category Button $uncheckCatBtn = New-Object System.Windows.Forms.Button $uncheckCatBtn.Text = "Uncheck Cat" $uncheckCatBtn.Location = New-Object System.Drawing.Point(395, 584) $uncheckCatBtn.Size = New-Object System.Drawing.Size(75, 25) $uncheckCatBtn.Add_Click({ $selectedCat = $catComboBox.SelectedItem if ($null -ne $selectedCat) { $prefix = "[$selectedCat]" for ($i = 0; $i -lt $checkedListBox.Items.Count; $i++) { if ($checkedListBox.Items[$i].StartsWith($prefix)) { $checkedListBox.SetItemChecked($i, $false) } } } }) $form.Controls.Add($uncheckCatBtn) # OK Button $okButton = New-Object System.Windows.Forms.Button $okButton.Text = "OK" $okButton.Location = New-Object System.Drawing.Point(310, 635) $okButton.Size = New-Object System.Drawing.Size(75, 30) $okButton.DialogResult = 'OK' $form.Controls.Add($okButton) # Cancel Button $cancelButton = New-Object System.Windows.Forms.Button $cancelButton.Text = "Cancel" $cancelButton.Location = New-Object System.Drawing.Point(395, 635) $cancelButton.Size = New-Object System.Drawing.Size(75, 30) $cancelButton.DialogResult = 'Cancel' $form.Controls.Add($cancelButton) $form.AcceptButton = $okButton $form.CancelButton = $cancelButton $result = $form.ShowDialog() $selectedItems = @() if ($result -eq 'OK') { for ($i = 0; $i -lt $checkedListBox.Items.Count; $i++) { if ($checkedListBox.GetItemChecked($i)) { $selectedItems += $Items[$i] } } } else { $form.Dispose() return $null } $form.Dispose() return $selectedItems } function Get-SetupMenuItems { return @( [pscustomobject]@{ Key = "Packages"; Label = "Install packages"; Enabled = $true }, [pscustomobject]@{ Key = "Tweaks"; Label = "Apply registry / Windows tweaks"; Enabled = $true }, [pscustomobject]@{ Key = "Features"; Label = "Install OpenSSH Server"; Enabled = $false }, [pscustomobject]@{ Key = "Restore"; Label = "Restore backups"; Enabled = $false } ) } function ConvertTo-SetupMenuOptions($items) { $selectedItems = $items | Where-Object { $_.Enabled } if (-not $selectedItems) { throw "No setup sections selected." } return [pscustomobject]@{ Packages = [bool](($items | Where-Object Key -eq "Packages").Enabled) Tweaks = [bool](($items | Where-Object Key -eq "Tweaks").Enabled) Features = [bool](($items | Where-Object Key -eq "Features").Enabled) Restore = [bool](($items | Where-Object Key -eq "Restore").Enabled) Custom = [bool]$script:CustomMode } } function Write-SetupMenuTextScreen($items) { Write-Host "" Write-Host "===========================================" -ForegroundColor Cyan Write-Host " CHATLO Windows Setup" -ForegroundColor Cyan Write-Host "===========================================" -ForegroundColor Cyan Write-Host "" Write-Host "Toggle items by number, then press Enter to run." -ForegroundColor Gray Write-Host "A = all | N = none | C = custom | Q = quit" -ForegroundColor Gray Write-Host "" for ($i = 0; $i -lt $items.Count; $i++) { $num = $i + 1 $box = if ($items[$i].Enabled) { "[x]" } else { "[ ]" } Write-Host " $num. $box $($items[$i].Label)" } Write-Host "" } function Show-SetupMenuText { $items = Get-SetupMenuItems Write-SetupMenuTextScreen $items :menuLoop while ($true) { $choice = Read-Host "Toggle (1-4) or Enter to run" if ([string]::IsNullOrWhiteSpace($choice)) { break } $changed = $false switch ($choice.Trim().ToLower()) { "q" { throw "Setup cancelled by user." } "a" { foreach ($item in $items) { $item.Enabled = $true }; $changed = $true } "n" { foreach ($item in $items) { $item.Enabled = $false }; $changed = $true } "c" { $script:CustomMode = $true ( $items | Where-Object Key -eq "Packages" ).Enabled = $true ( $items | Where-Object Key -eq "Tweaks" ).Enabled = $true break menuLoop } default { foreach ($part in ($choice -split '[,\s]+')) { if ($part -match '^\d+$') { $idx = [int]$part - 1 if ($idx -ge 0 -and $idx -lt $items.Count) { $items[$idx].Enabled = -not $items[$idx].Enabled $changed = $true } } } } } if ($changed) { Write-Host "" Write-SetupMenuTextScreen $items } } return ConvertTo-SetupMenuOptions $items } function Show-SetupMenu { return Show-SetupMenuText } if ($SkipMenu) { if (-not ($Packages -or $Tweaks -or $Features -or $Restore)) { throw "Elevated re-launch requires at least one -Packages, -Tweaks, -Features, or -Restore switch." } $Options = [pscustomobject]@{ Packages = [bool]$Packages Tweaks = [bool]$Tweaks Features = [bool]$Features Restore = [bool]$Restore Custom = [bool]$Custom } $script:CustomMode = [bool]$Custom } else { $Options = Show-SetupMenu if ((Test-SetupNeedsAdmin $Options) -and -not (Test-IsAdmin)) { Restart-Elevated $Options } } Write-Step "Starting Chatlo setup" Write-Host "Selected sections:" -ForegroundColor Cyan Write-Host " Packages: $($Options.Packages)" Write-Host " Tweaks: $($Options.Tweaks)" Write-Host " OpenSSH Server: $($Options.Features)" Write-Host " Restore: $($Options.Restore)" Add-Content $LogFile "Selected sections: Packages=$($Options.Packages), Tweaks=$($Options.Tweaks), Features=$($Options.Features), Restore=$($Options.Restore)" # ------------------------- # App Installer / Winget Check # ------------------------- Write-Step "Checking Winget / App Installer" try { Write-Host "Testing winget by updating sources..." -ForegroundColor Cyan $wingetTest = winget source update 2>&1 if ($LASTEXITCODE -ne 0 -or $wingetTest -match "mismatch|error|failed") { Write-Host "WARNING: Winget returned an error. You may have a certificate mismatch or App Installer issue." -ForegroundColor Red Write-Host "Output:" -ForegroundColor DarkGray Write-Host $wingetTest -ForegroundColor DarkGray Write-Host "`nPlease open the Microsoft Store and update 'App Installer'." -ForegroundColor Yellow Read-Host "Press Enter once you have checked/updated it, or to continue anyway..." } else { Write-Host "Winget sources updated successfully." -ForegroundColor Green } } catch { Write-Host "WARNING: Winget is not recognized. You may need to install/update 'App Installer' from the MS Store." -ForegroundColor Red Read-Host "Press Enter once you have updated it, or to continue anyway..." } # ------------------------- # Restore point # ------------------------- Write-Step "Creating restore point" try { Enable-ComputerRestore -Drive "C:\" # Force restore point creation by temporarily disabling the 24-hour limit $srKey = "HKLM:\Software\Microsoft\Windows NT\CurrentVersion\SystemRestore" $oldFreq = $null if (Test-Path $srKey) { $oldFreq = (Get-ItemProperty -Path $srKey -Name "SystemRestorePointCreationFrequency" -ErrorAction SilentlyContinue).SystemRestorePointCreationFrequency Set-ItemProperty -Path $srKey -Name "SystemRestorePointCreationFrequency" -Value 0 -ErrorAction SilentlyContinue | Out-Null } Checkpoint-Computer -Description "Pre Chatlo Setup" -RestorePointType "MODIFY_SETTINGS" if ($null -ne $oldFreq) { Set-ItemProperty -Path $srKey -Name "SystemRestorePointCreationFrequency" -Value $oldFreq -ErrorAction SilentlyContinue | Out-Null } } catch { Write-Host "Restore point failed." -ForegroundColor DarkYellow } # ------------------------- # Packages Installation # ------------------------- if ($Options.Packages) { Write-Step "Preparing Package Installation" $AllPackages = @( [pscustomobject]@{ Category = "Core tools"; Id = "Microsoft.PowerShell"; Name = "PowerShell 7" } [pscustomobject]@{ Category = "Core tools"; Id = "7zip.7zip"; Name = "7-Zip" } [pscustomobject]@{ Category = "Core tools"; Id = "Git.Git"; Name = "Git" } [pscustomobject]@{ Category = "Core tools"; Id = "Microsoft.WindowsTerminal"; Name = "Windows Terminal" } [pscustomobject]@{ Category = "Browsers"; Id = "Google.Chrome"; Name = "Google Chrome" } [pscustomobject]@{ Category = "Browsers"; Id = "Mozilla.Firefox.DeveloperEdition"; Name = "Firefox Developer Edition" } [pscustomobject]@{ Category = "Browsers"; Id = "Brave.Brave"; Name = "Brave" } [pscustomobject]@{ Category = "Development tools"; Id = "Microsoft.VisualStudioCode"; Name = "Visual Studio Code" } [pscustomobject]@{ Category = "Development tools"; Id = "Microsoft.VisualStudio.Enterprise"; Name = "Visual Studio Enterprise" } [pscustomobject]@{ Category = "Development tools"; Id = "Microsoft.DotNet.SDK.8"; Name = ".NET SDK 8" } [pscustomobject]@{ Category = "Development tools"; Id = "Microsoft.DotNet.SDK.9"; Name = ".NET SDK 9" } [pscustomobject]@{ Category = "Development tools"; Id = "Microsoft.DotNet.SDK.10"; Name = ".NET SDK 10" } [pscustomobject]@{ Category = "Development tools"; Id = "OpenJS.NodeJS"; Name = "Node.js" } [pscustomobject]@{ Category = "Development tools"; Id = "Python.Python.3.14"; Name = "Python 3.14" } [pscustomobject]@{ Category = "Development tools"; Id = "DEVCOM.Lua"; Name = "Lua" } [pscustomobject]@{ Category = "Development tools"; Id = "GitHub.GitHubDesktop"; Name = "GitHub Desktop" } [pscustomobject]@{ Category = "Development tools"; Id = "Google.Antigravity"; Name = "Antigravity" } [pscustomobject]@{ Category = "Development tools"; Id = "Anysphere.Cursor"; Name = "Cursor" } [pscustomobject]@{ Category = "Utilities"; Id = "Microsoft.PowerToys"; Name = "PowerToys" } [pscustomobject]@{ Category = "Utilities"; Id = "Flow-Launcher.Flow-Launcher"; Name = "Flow Launcher" } [pscustomobject]@{ Category = "Utilities"; Id = "ShareX.ShareX"; Name = "ShareX" } [pscustomobject]@{ Category = "Utilities"; Id = "Proton.ProtonVPN"; Name = "Proton VPN" } [pscustomobject]@{ Category = "Utilities"; Id = "Discord.Discord"; Name = "Discord" } [pscustomobject]@{ Category = "Utilities"; Id = "Logitech.GHUB"; Name = "Logitech G HUB" } [pscustomobject]@{ Category = "Utilities"; Id = "Logitech.OptionsPlus"; Name = "Logi Options+" } [pscustomobject]@{ Category = "Utilities"; Id = "MartiCliment.UniGetUI"; Name = "UniGetUI" } [pscustomobject]@{ Category = "Network and cloud tools"; Id = "WinFsp.WinFsp"; Name = "WinFsp" } [pscustomobject]@{ Category = "Network and cloud tools"; Id = "Rclone.Rclone"; Name = "Rclone" } [pscustomobject]@{ Category = "Network and cloud tools"; Id = "RClone-Manager.rclone-manager"; Name = "Rclone Manager" } [pscustomobject]@{ Category = "Network and cloud tools"; Id = "Tailscale.Tailscale"; Name = "Tailscale" } [pscustomobject]@{ Category = "Network and cloud tools"; Id = "WinSCP.WinSCP"; Name = "WinSCP" } [pscustomobject]@{ Category = "Media and download tools"; Id = "mpv.net"; Name = "mpv.net" } [pscustomobject]@{ Category = "Media and download tools"; Id = "Gyan.FFmpeg"; Name = "FFmpeg" } [pscustomobject]@{ Category = "Media and download tools"; Id = "yt-dlp.yt-dlp"; Name = "yt-dlp" } [pscustomobject]@{ Category = "Media and download tools"; Id = "yt-dlp.FFmpeg"; Name = "FFmpeg for yt-dlp" } [pscustomobject]@{ Category = "Media and download tools"; Id = "Spotify.Spotify"; Name = "Spotify" } [pscustomobject]@{ Category = "Media and download tools"; Id = "Nicotine+.Nicotine+"; Name = "Nicotine+" } [pscustomobject]@{ Category = "Media and download tools"; Id = "MusicBrainz.Picard"; Name = "MusicBrainz Picard" } [pscustomobject]@{ Category = "Media and download tools"; Id = "Mp3tag.Mp3tag"; Name = "Mp3tag" } [pscustomobject]@{ Category = "Media and download tools"; Id = "PeterPawlowski.foobar2000"; Name = "foobar2000" } [pscustomobject]@{ Category = "Media and download tools"; Id = "MusicBee.MusicBee"; Name = "MusicBee" } [pscustomobject]@{ Category = "Media and download tools"; Id = "AriaNg.AriaNg"; Name = "AriaNg" } [pscustomobject]@{ Category = "Home lab"; Id = "Jellyfin.Server"; Name = "Jellyfin Server" } [pscustomobject]@{ Category = "Home lab"; Id = "Navidrome.Navidrome"; Name = "Navidrome" } [pscustomobject]@{ Category = "Home lab"; Id = "nzbget.nzbget"; Name = "NZBGet" } [pscustomobject]@{ Category = "Home lab"; Id = "TeamSonarr.Sonarr"; Name = "Sonarr" } [pscustomobject]@{ Category = "Home lab"; Id = "TeamRadarr.Radarr"; Name = "Radarr" } [pscustomobject]@{ Category = "Home lab"; Id = "TeamLidarr.Lidarr"; Name = "Lidarr" } [pscustomobject]@{ Category = "Home lab"; Id = "qBittorrent.qBittorrent"; Name = "qBittorrent" } [pscustomobject]@{ Category = "Diagnostics"; Id = "REALiX.HWiNFO"; Name = "HWiNFO" } [pscustomobject]@{ Category = "Diagnostics"; Id = "CrystalDewWorld.CrystalDiskInfo"; Name = "CrystalDiskInfo" } [pscustomobject]@{ Category = "Diagnostics"; Id = "CrystalDewWorld.CrystalDiskMark"; Name = "CrystalDiskMark" } [pscustomobject]@{ Category = "Diagnostics"; Id = "Rem0o.FanControl"; Name = "FanControl" } [pscustomobject]@{ Category = "Diagnostics"; Id = "CPUID.HWMonitor"; Name = "HWMonitor" } ) $SelectedPackages = if ($script:CustomMode) { Show-SelectionUI -Title "Select Packages to Install" -Instruction "Deselect any applications you do not wish to install:" -Items $AllPackages } else { $AllPackages } if ($null -ne $SelectedPackages -and $SelectedPackages.Count -gt 0) { $CurrentCategory = "" foreach ($pkg in $SelectedPackages) { if ($pkg.Category -ne $CurrentCategory) { $CurrentCategory = $pkg.Category Write-Step $CurrentCategory } Install-WingetPackage $pkg.Id $pkg.Name } } else { Write-Host "Package installation cancelled or no packages selected." -ForegroundColor DarkGray } } else { Write-Host "Skipping package installs." -ForegroundColor DarkGray } # ------------------------- # Windows tweaks # ------------------------- if ($Options.Tweaks) { Write-Step "Preparing Registry Tweaks" $AllTweaks = @( [pscustomobject]@{ Category = "Explorer" Name = "Show file extensions" Check = { (Get-ItemPropertyValue "HKCU:\Software\Microsoft\Windows\CurrentVersion\Explorer\Advanced" -Name "HideFileExt" -ErrorAction SilentlyContinue) -eq 0 } Action = { Set-ItemProperty "HKCU:\Software\Microsoft\Windows\CurrentVersion\Explorer\Advanced" HideFileExt 0 } } [pscustomobject]@{ Category = "Explorer" Name = "Show hidden files" Check = { (Get-ItemPropertyValue "HKCU:\Software\Microsoft\Windows\CurrentVersion\Explorer\Advanced" -Name "Hidden" -ErrorAction SilentlyContinue) -eq 1 } Action = { Set-ItemProperty "HKCU:\Software\Microsoft\Windows\CurrentVersion\Explorer\Advanced" Hidden 1 } } [pscustomobject]@{ Category = "Explorer" Name = "Explorer opens This PC" Check = { (Get-ItemPropertyValue "HKCU:\Software\Microsoft\Windows\CurrentVersion\Explorer\Advanced" -Name "LaunchTo" -ErrorAction SilentlyContinue) -eq 1 } Action = { Set-ItemProperty "HKCU:\Software\Microsoft\Windows\CurrentVersion\Explorer\Advanced" LaunchTo 1 } } [pscustomobject]@{ Category = "Explorer" Name = "Classic context menus" Check = { (Test-Path "HKCU:\Software\Classes\CLSID\{86ca1aa0-34aa-4e8b-a509-50c905bae2a2}\InprocServer32") -and ((Get-Item -Path "HKCU:\Software\Classes\CLSID\{86ca1aa0-34aa-4e8b-a509-50c905bae2a2}\InprocServer32").GetValue("") -eq "") } Action = { New-Item -Path "HKCU:\Software\Classes\CLSID\{86ca1aa0-34aa-4e8b-a509-50c905bae2a2}\InprocServer32" -Force | Out-Null Set-ItemProperty -Path "HKCU:\Software\Classes\CLSID\{86ca1aa0-34aa-4e8b-a509-50c905bae2a2}\InprocServer32" -Name "(Default)" -Value "" } } [pscustomobject]@{ Category = "Theme" Name = "Enable Dark mode" Check = $null Action = { New-Item -Path "HKCU:\Software\Microsoft\Windows\CurrentVersion\Themes\Personalize" -Force | Out-Null Set-ItemProperty "HKCU:\Software\Microsoft\Windows\CurrentVersion\Themes\Personalize" AppsUseLightTheme 0 Set-ItemProperty "HKCU:\Software\Microsoft\Windows\CurrentVersion\Themes\Personalize" SystemUsesLightTheme 0 } } [pscustomobject]@{ Category = "Privacy" Name = "Disable Activity History" Check = { (Get-ItemPropertyValue "HKLM:\SOFTWARE\Policies\Microsoft\Windows\System" -Name "EnableActivityFeed" -ErrorAction SilentlyContinue) -eq 0 } Action = { New-Item -Path "HKLM:\SOFTWARE\Policies\Microsoft\Windows\System" -Force | Out-Null Set-ItemProperty "HKLM:\SOFTWARE\Policies\Microsoft\Windows\System" EnableActivityFeed 0 Set-ItemProperty "HKLM:\SOFTWARE\Policies\Microsoft\Windows\System" PublishUserActivities 0 Set-ItemProperty "HKLM:\SOFTWARE\Policies\Microsoft\Windows\System" UploadUserActivities 0 } } [pscustomobject]@{ Category = "Privacy" Name = "Disable Consumer Features" Check = { (Get-ItemPropertyValue "HKLM:\SOFTWARE\Policies\Microsoft\Windows\CloudContent" -Name "DisableWindowsConsumerFeatures" -ErrorAction SilentlyContinue) -eq 1 } Action = { New-Item -Path "HKLM:\SOFTWARE\Policies\Microsoft\Windows\CloudContent" -Force | Out-Null Set-ItemProperty "HKLM:\SOFTWARE\Policies\Microsoft\Windows\CloudContent" DisableWindowsConsumerFeatures 1 } } [pscustomobject]@{ Category = "Privacy" Name = "Disable telemetry" Check = { (Get-ItemPropertyValue "HKLM:\SOFTWARE\Policies\Microsoft\Windows\DataCollection" -Name "AllowTelemetry" -ErrorAction SilentlyContinue) -eq 0 } Action = { New-Item -Path "HKLM:\SOFTWARE\Policies\Microsoft\Windows\DataCollection" -Force | Out-Null Set-ItemProperty "HKLM:\SOFTWARE\Policies\Microsoft\Windows\DataCollection" AllowTelemetry 0 } } [pscustomobject]@{ Category = "System" Name = "Enable long paths" Check = { (Get-ItemPropertyValue "HKLM:\SYSTEM\CurrentControlSet\Control\FileSystem" -Name "LongPathsEnabled" -ErrorAction SilentlyContinue) -eq 1 } Action = { New-Item -Path "HKLM:\SYSTEM\CurrentControlSet\Control\FileSystem" -Force | Out-Null Set-ItemProperty "HKLM:\SYSTEM\CurrentControlSet\Control\FileSystem" LongPathsEnabled 1 } } [pscustomobject]@{ Category = "System" Name = "Disable hibernation" Check = { -not (Test-Path "C:\hiberfil.sys") } Action = { powercfg /hibernate off } } [pscustomobject]@{ Category = "System" Name = "Ultimate Performance plan" Check = { (powercfg /getactivescheme) -match "e9a42b02-d5df-448d-aa00-03f14749eb61" } Action = { powercfg -duplicatescheme e9a42b02-d5df-448d-aa00-03f14749eb61 | Out-Null } } [pscustomobject]@{ Category = "System" Name = "Verbose BSOD" Check = { (Get-ItemPropertyValue "HKLM:\SYSTEM\CurrentControlSet\Control\CrashControl" -Name "DisplayParameters" -ErrorAction SilentlyContinue) -eq 1 } Action = { New-Item -Path "HKLM:\SYSTEM\CurrentControlSet\Control\CrashControl" -Force | Out-Null Set-ItemProperty "HKLM:\SYSTEM\CurrentControlSet\Control\CrashControl" DisplayParameters 1 } } [pscustomobject]@{ Category = "System" Name = "Mouse pointer size 3" Check = { (Get-ItemPropertyValue "HKCU:\Control Panel\Cursors" -Name "CursorBaseSize" -ErrorAction SilentlyContinue) -eq 48 } Action = { New-Item -Path "HKCU:\Control Panel\Cursors" -Force | Out-Null Set-ItemProperty "HKCU:\Control Panel\Cursors" CursorBaseSize 48 } } [pscustomobject]@{ Category = "Taskbar" Name = "Taskbar left alignment" Check = { (Get-ItemPropertyValue "HKCU:\Software\Microsoft\Windows\CurrentVersion\Explorer\Advanced" -Name "TaskbarAl" -ErrorAction SilentlyContinue) -eq 0 } Action = { New-Item -Path "HKCU:\Software\Microsoft\Windows\CurrentVersion\Explorer\Advanced" -Force | Out-Null Set-ItemProperty "HKCU:\Software\Microsoft\Windows\CurrentVersion\Explorer\Advanced" TaskbarAl 0 } } [pscustomobject]@{ Category = "Taskbar" Name = "Hide task view button" Check = { (Get-ItemPropertyValue "HKCU:\Software\Microsoft\Windows\CurrentVersion\Explorer\Advanced" -Name "ShowTaskViewButton" -ErrorAction SilentlyContinue) -eq 0 } Action = { Set-ItemProperty "HKCU:\Software\Microsoft\Windows\CurrentVersion\Explorer\Advanced" ShowTaskViewButton 0 } } [pscustomobject]@{ Category = "Taskbar" Name = "Hide search box/icon" Check = { (Get-ItemPropertyValue "HKCU:\Software\Microsoft\Windows\CurrentVersion\Search" -Name "SearchboxTaskbarMode" -ErrorAction SilentlyContinue) -eq 0 } Action = { Set-ItemProperty "HKCU:\Software\Microsoft\Windows\CurrentVersion\Search" SearchboxTaskbarMode 0 } } [pscustomobject]@{ Category = "Taskbar" Name = "Never combine taskbar buttons" Check = { (Get-ItemPropertyValue "HKCU:\Software\Microsoft\Windows\CurrentVersion\Explorer\Advanced" -Name "TaskbarGlomLevel" -ErrorAction SilentlyContinue) -eq 2 } Action = { Set-ItemProperty "HKCU:\Software\Microsoft\Windows\CurrentVersion\Explorer\Advanced" TaskbarGlomLevel 2 Set-ItemProperty "HKCU:\Software\Microsoft\Windows\CurrentVersion\Explorer\Advanced" MMTaskbarGlomLevel 2 } } [pscustomobject]@{ Category = "Taskbar" Name = "Show taskbar on all displays" Check = { (Get-ItemPropertyValue "HKCU:\Software\Microsoft\Windows\CurrentVersion\Explorer\Advanced" -Name "MMTaskbarEnabled" -ErrorAction SilentlyContinue) -eq 1 } Action = { Set-ItemProperty "HKCU:\Software\Microsoft\Windows\CurrentVersion\Explorer\Advanced" MMTaskbarEnabled 1 } } [pscustomobject]@{ Category = "Taskbar" Name = "Show taskbar apps only where window is open" Check = { (Get-ItemPropertyValue "HKCU:\Software\Microsoft\Windows\CurrentVersion\Explorer\Advanced" -Name "MMTaskbarMode" -ErrorAction SilentlyContinue) -eq 2 } Action = { Set-ItemProperty "HKCU:\Software\Microsoft\Windows\CurrentVersion\Explorer\Advanced" MMTaskbarMode 2 } } [pscustomobject]@{ Category = "Taskbar" Name = "Enable End Task in taskbar" Check = { (Get-ItemPropertyValue "HKCU:\Software\Microsoft\Windows\CurrentVersion\Explorer\Advanced\TaskbarDeveloperSettings" -Name "TaskbarEndTask" -ErrorAction SilentlyContinue) -eq 1 } Action = { New-Item -Path "HKCU:\Software\Microsoft\Windows\CurrentVersion\Explorer\Advanced\TaskbarDeveloperSettings" -Force | Out-Null Set-ItemProperty "HKCU:\Software\Microsoft\Windows\CurrentVersion\Explorer\Advanced\TaskbarDeveloperSettings" TaskbarEndTask 1 } } [pscustomobject]@{ Category = "Taskbar" Name = "Disable widgets" Check = { (Get-ItemPropertyValue "HKLM:\SOFTWARE\Policies\Microsoft\Dsh" -Name "AllowNewsAndInterests" -ErrorAction SilentlyContinue) -eq 0 } Action = { New-Item -Path "HKLM:\SOFTWARE\Policies\Microsoft\Dsh" -Force | Out-Null Set-ItemProperty "HKLM:\SOFTWARE\Policies\Microsoft\Dsh" AllowNewsAndInterests 0 } } ) $SelectedTweaks = if ($script:CustomMode) { Show-SelectionUI -Title "Select Registry Tweaks to Apply" -Instruction "Deselect any tweaks you do not wish to apply:" -Items $AllTweaks } else { $AllTweaks } if ($null -ne $SelectedTweaks -and $SelectedTweaks.Count -gt 0) { $CurrentCategory = "" foreach ($tweak in $SelectedTweaks) { if ($tweak.Category -ne $CurrentCategory) { $CurrentCategory = $tweak.Category Write-Step $CurrentCategory } $alreadyApplied = $false if ($null -ne $tweak.Check) { try { $alreadyApplied = & $tweak.Check } catch { $alreadyApplied = $false } } if ($alreadyApplied) { Write-Host "Registry tweak already applied: $($tweak.Name)" -ForegroundColor DarkGray Add-Content $LogFile "Registry tweak already applied: $($tweak.Name)" $script:Skipped += "Tweak: $($tweak.Name)" } else { Write-Host "Applying tweak: $($tweak.Name)" -ForegroundColor Yellow try { & $tweak.Action $script:InstalledOK += "Tweak: $($tweak.Name)" } catch { Write-Host "Failed applying tweak: $($tweak.Name)" -ForegroundColor Red Write-Host $_.Exception.Message -ForegroundColor Red $script:Failed += "Tweak: $($tweak.Name) - $($_.Exception.Message)" } } } } else { Write-Host "Tweaks cancelled or no tweaks selected." -ForegroundColor DarkGray } } else { Write-Host "Skipping registry / Windows tweaks." -ForegroundColor DarkGray } # ------------------------- # Restore configs from E: # ------------------------- if ($Options.Restore) { Write-Step "Restoring configs where possible" # rclone.conf if (Test-Path "$BackupRoot\rclone.conf") { New-Item -ItemType Directory -Force "$env:APPDATA\rclone" | Out-Null Copy-Item "$BackupRoot\rclone.conf" "$env:APPDATA\rclone\rclone.conf" -Force Write-Host "Restored rclone.conf" } # mpv portable config if (Test-Path "$BackupRoot\mpv.7z") { New-Item -ItemType Directory -Force "C:\mpv" | Out-Null 7z x "$BackupRoot\mpv.7z" -o"C:\mpv" -y Write-Host "Extracted mpv backup to C:\mpv" } # PowerToys if (Test-Path "$BackupRoot\PowerToys.7z") { New-Item -ItemType Directory -Force "$env:LOCALAPPDATA\Microsoft\PowerToys" | Out-Null 7z x "$BackupRoot\PowerToys.7z" -o"$env:LOCALAPPDATA\Microsoft\PowerToys" -y Write-Host "Extracted PowerToys backup" } # ShareX if (Test-Path "$BackupRoot\ShareX.7z") { New-Item -ItemType Directory -Force "$env:USERPROFILE\Documents\ShareX" | Out-Null 7z x "$BackupRoot\ShareX.7z" -o"$env:USERPROFILE\Documents\ShareX" -y Write-Host "Extracted ShareX backup" } # Navidrome backup if (Test-Path "$BackupRoot\Navidrome.zip") { New-Item -ItemType Directory -Force "$BackupRoot\Restored\Navidrome" | Out-Null Expand-Archive "$BackupRoot\Navidrome.zip" "$BackupRoot\Restored\Navidrome" -Force Write-Host "Extracted Navidrome backup to E:\Restored\Navidrome" } # The arrs if (Test-Path "$BackupRoot\the arrs.zip") { New-Item -ItemType Directory -Force "$BackupRoot\Restored\the arrs" | Out-Null Expand-Archive "$BackupRoot\the arrs.zip" "$BackupRoot\Restored\the arrs" -Force Write-Host "Extracted arr backups to E:\Restored\the arrs" } # ChatPlayer config if (Test-Path "$BackupRoot\chatplayer-config.json") { New-Item -ItemType Directory -Force "$BackupRoot\Restored\ChatPlayer" | Out-Null Copy-Item "$BackupRoot\chatplayer-config.json" "$BackupRoot\Restored\ChatPlayer\chatplayer-config.json" -Force Write-Host "Copied ChatPlayer config to E:\Restored\ChatPlayer" } # g70d remote backup if (Test-Path "$BackupRoot\g70d_remote_backup.json") { New-Item -ItemType Directory -Force "$BackupRoot\Restored\G70D" | Out-Null Copy-Item "$BackupRoot\g70d_remote_backup.json" "$BackupRoot\Restored\G70D\g70d_remote_backup.json" -Force Write-Host "Copied G70D remote backup" } # Scripts backup - don't auto-place, just extract for manual use if (Test-Path "$BackupRoot\Scripts.7z") { New-Item -ItemType Directory -Force "$BackupRoot\Restored\Scripts" | Out-Null 7z x "$BackupRoot\Scripts.7z" -o"$BackupRoot\Restored\Scripts" -y Write-Host "Extracted Scripts backup to E:\Restored\Scripts" } # aria2 backup if (Test-Path "$BackupRoot\aria2.7z") { New-Item -ItemType Directory -Force "$BackupRoot\Restored\aria2" | Out-Null 7z x "$BackupRoot\aria2.7z" -o"$BackupRoot\Restored\aria2" -y Write-Host "Extracted aria2 backup to E:\Restored\aria2" } # UniGetUI bundle - just keep reference if (Test-Path "$BackupRoot\CHATLO installed packages.ubundle") { Write-Host "UniGetUI bundle found. Leaving in place as fallback." } } else { Write-Host "Skipping backup restore." -ForegroundColor DarkGray } # ------------------------- # Install OpenSSH Server # ------------------------- if ($Options.Features) { Write-Step "Install OpenSSH Server" Install-Feature "OpenSSH.Server~~~~0.0.1.0" Set-Service sshd -StartupType Automatic -ErrorAction SilentlyContinue Start-Service sshd -ErrorAction SilentlyContinue } else { Write-Host "Skipping OpenSSH Server." -ForegroundColor DarkGray } # ------------------------- # Manual reminders # ------------------------- Write-Step "Manual install reminders" $ManualList = @" Manual / semi-manual tasks still recommended: 1. Install chipset / Intel ME / LAN / Wi-Fi drivers if not already done. 2. Install AMD Adrenalin manually. 3. Set display scaling to 175%. 4. Enable HDR and run Windows HDR Calibration. 5. Sign into Tailscale. 6. Import Rclone Manager backups if needed. 7. Confirm rclone mount works. 8. Restore Jellyfin/Navidrome/Sonarr/Radarr/Lidarr configs manually if needed. 9. Install TONEX MAX. 10. Install NeuralDSP Archetype John Mayer. 11. Install Reaper. 12. Install Adobe Creative Cloud / Photoshop. 13. Restore Logitech profiles if needed. 14. Confirm OpenSSH Server works from Victus. 15. Reboot after everything settles. Backup placement notes: rclone.conf: %APPDATA%\rclone\rclone.conf mpv: C:\mpv\portable_config ShareX: %USERPROFILE%\Documents\ShareX PowerToys: %LOCALAPPDATA%\Microsoft\PowerToys Navidrome: Check E:\Restored\Navidrome Sonarr/Radarr/Lidarr: Check E:\Restored\the arrs aria2: Check E:\Restored\aria2 Scripts: Check E:\Restored\Scripts "@ $ManualList | Out-File "$BackupRoot\PostInstall-Manual-Steps.txt" -Encoding UTF8 Write-Host $ManualList -ForegroundColor Green if ($Options.Tweaks) { Write-Step "Restarting Explorer" Stop-Process -Name explorer -Force -ErrorAction SilentlyContinue Start-Process explorer.exe } Write-Step "Setup complete" Write-Host "`nDone. Reboot when ready." -ForegroundColor Green Write-Step "Install summary" $Summary = @" Installed successfully: $($InstalledOK | ForEach-Object { " � $_" } | Out-String) Skipped / already installed: $($Skipped | ForEach-Object { " - $_" } | Out-String) Failed: $($Failed | ForEach-Object { " ✗ $_" } | Out-String) "@ Write-Host $Summary $Summary | Out-File "$BackupRoot\Setup-Chatlo-Summary.txt" -Encoding UTF8 Write-Host "`nSummary saved to E:\Setup-Chatlo-Summary.txt" -ForegroundColor Cyan Write-Host "`nPress any key to exit..." -ForegroundColor Gray $null = [System.Console]::ReadKey($true) # SIG # Begin signature block # MIIFoQYJKoZIhvcNAQcCoIIFkjCCBY4CAQExDzANBglghkgBZQMEAgEFADB5Bgor # BgEEAYI3AgEEoGswaTA0BgorBgEEAYI3AgEeMCYCAwEAAAQQH8w7YFlLCE63JNLG # KX7zUQIBAAIBAAIBAAIBAAIBADAxMA0GCWCGSAFlAwQCAQUABCCQJ1DaMxOmyhCg # YAgTfA2ws620o+1O/IwVOV2LP1jGA6CCAxIwggMOMIIB9qADAgECAhBpuMZISSkQ # vUZEAEcgFdCtMA0GCSqGSIb3DQEBCwUAMB8xHTAbBgNVBAMMFENoYXRsbyBTZXR1 # cCBTY3JpcHRzMB4XDTI2MDYyNTA3MzE1M1oXDTMxMDYyNTA3NDE1NFowHzEdMBsG # A1UEAwwUQ2hhdGxvIFNldHVwIFNjcmlwdHMwggEiMA0GCSqGSIb3DQEBAQUAA4IB # DwAwggEKAoIBAQCvrwNxwiz1RKTOFCrNB5APi+6dFPUS9bJboz+ZBLHs7D/Hu8AF # +l7CjzdwqfLtDCk+94gFR3vRrfxgPuNfrsa8eb6qb7qY9kenYIsZi011oojyQ8P+ # doKxl2HYqCyw/y1gRyCiNXsTrwBYWlff6HZlhqzbAETX3bXOlwhhPWnp8/er/EmX # UCJLif/KWl0ri7zIia1UndG0LdAHIbapnOLAJmAul6WwrmMykBpV06Jbv6VQxuLQ # Faqic++oY1voYbYNZsnVYxQH7HaQWvoC9XUXl39VJoXGtawHnWECj4bez9o6sbsc # KB4ggYAtBz9l8cwgx+8No7T+6fZXvbpX4WXdAgMBAAGjRjBEMA4GA1UdDwEB/wQE # AwIHgDATBgNVHSUEDDAKBggrBgEFBQcDAzAdBgNVHQ4EFgQUlqr5IhD2Zwe3NMt1 # 7THxzBl8E9UwDQYJKoZIhvcNAQELBQADggEBAAc0yGVCiQEJgyIwmQ/2UhiJ0+4L # YQDWOjttGWK3hkbcTwZi9PpQmgXgG61jpi/TDWWNu3maA+itxHnnTnUWBz5Ho4Y0 # qXidldlzBwwP/dtIb0puCveN0xk5XvlYw3djs6Ih1shNZHuiptSIisIuNKug6LeW # /y0RRxtvEvwOomi3bgFpaEk5AjlgZ9y3gwC5kiRDHa0qn1Gc9LQsXvgIJ7SGSbrY # QVp9ah7s6vAF3M5Q1Aebvr4U74nmKfnJBl2EB0584EahkLR/Cbd0FAL0b1JA0O/3 # djGb6Wzb0ZQp4x7Zc05Ai+J2YiwWfeuA5JeQ/E/T1gKu2Til4dAErjBi+IYxggHl # MIIB4QIBATAzMB8xHTAbBgNVBAMMFENoYXRsbyBTZXR1cCBTY3JpcHRzAhBpuMZI # SSkQvUZEAEcgFdCtMA0GCWCGSAFlAwQCAQUAoIGEMBgGCisGAQQBgjcCAQwxCjAI # oAKAAKECgAAwGQYJKoZIhvcNAQkDMQwGCisGAQQBgjcCAQQwHAYKKwYBBAGCNwIB # CzEOMAwGCisGAQQBgjcCARUwLwYJKoZIhvcNAQkEMSIEIFXoPmMzUNgf+LKwP1BG # g5l7Ip62EWlwSOYT0V7S/vGWMA0GCSqGSIb3DQEBAQUABIIBAFaE3rNxx71P9h9Z # +n/mBj6X/TiyoFe0Hj/GkTAQNqZ3149LMTDngBn3DihTgW8r7/HtIkl+odCVzt1f # 7+q5wuuIwirXsf2Mo0HjJIveWOg/OLirSj8phP/BCq8ypOZ0fiMKzQKGNFC4nN+E # kMcyAZUa7Szs1LRfTmQnIgar2eDq0VauZf3towqEOhrTBoRFYeWNTZ+85jgo3Dmv # 7Mgf8c+WShP5NsAw1FElAXk4Z2IfZcXqofIyv8oeuiG7Z/kOBgyD9ePZEGXZ6xVq # hKTXYW+vkw5M27JM+vHrZlUn6Ln9w9C+Isy3XULzdevbqb9OSX73JChV/Lb7gqcV # y7/QxNQ= # SIG # End signature block