<# .SYNOPSIS Applies system-wide registry settings and power configuration (HKLM). .DESCRIPTION Sets machine-wide registry tweaks under HKLM that apply to all users. Disables unwanted telemetry and cloud features, configures Edge policies, sets power plan timeouts, and disables proxy auto-detect. Uninstalls the pre-installed OneDrive consumer version via OneDriveSetup.exe /uninstall - intentional for a clean MSP deployment baseline. No DisableFileSyncNGSC policy key is set, so M365 installation can install and run its own OneDrive version without restriction. .ITEMS bypass-nro-oobe-bypassnro-1: HKLM\SOFTWARE\Microsoft\Windows\CurrentVersion\OOBE\BypassNRO = 1. Bypasses the "Let's connect you to a network" OOBE screen. Enables offline Windows setup without forcing a Microsoft account login. zakaz-auto-instalace-teams: HKLM\SOFTWARE\Microsoft\Windows\CurrentVersion\Communications\ConfigureChatAutoInstall = 0. Prevents Windows from auto-installing Teams Personal during OOBE or after Cumulative Updates. zakaz-cloud-optimized-content: ContentDeliveryManager\DisableCloudOptimizedContent = 1. Stops Windows from pushing sponsored app suggestions, tips from Microsoft servers, and "Get even more from Windows" prompts. zakaz-widgets-news-and-interests: HKLM\SOFTWARE\Policies\Microsoft\Dsh\AllowNewsAndInterests = 0. Disables the Widgets taskbar button and panel (news feed, weather, stocks). Not relevant for business deployments. hesla-bez-expirace-net-accounts-maxpwage: net accounts /maxpwage:UNLIMITED. Sets the local password expiration policy to never. MSP-managed machines handle password rotation via other means (Atera, domain policy, manual). casova-zona-central-europe-standard-time: Set-TimeZone -Id "Central Europe Standard Time". UTC+1 (UTC+2 in summer DST). Applied system-wide. Critical for correct log timestamps, scheduled task timing, and calendar sync. zakaz-gamedvr: HKLM\SOFTWARE\Policies\Microsoft\Windows\GameDVR\AppCaptureEnabled = 0. Disables Xbox Game Bar screen capture overlay. Reduces background resource usage and eliminates unintended capture prompts on business machines. edge-skryt-first-run-experience: HideFirstRunExperience=1 + DefaultBrowserSettingEnabled=0. Suppresses Edge welcome wizard and default browser prompts on first launch. edge-policies-panel-oblibeny-vyhledavac: FavoritesBarEnabled=1 (always show), DefaultSearchProviderEnabled=1, DefaultSearchProviderName=Google, ManagedSearchEngines removes other providers. edge-policies-tlacitka-zobrazit: DownloadsButtonEnabled=1, HistoryButtonEnabled=1. edge-policies-tlacitka-skryt: HomeButtonEnabled=0, SplitScreenEnabled=0, EdgeEDropEnabled=0 (Drop), WebCaptureEnabled=0 (Screenshot), ShareAllowed=0. edge-policies-obsah-a-telemetrie: NewTabPageContentEnabled=0, ShowRecommendationsEnabled=0, SpotlightExperiencesAndRecommendationsEnabled=0, PersonalizationReportingEnabled=0, EdgeShoppingAssistantEnabled=0, ShowMicrosoftRewards=0, HubsSidebarEnabled=0, SearchSuggestEnabled=0, DiagnosticData=0, FeedbackSurveysEnabled=0, EdgeCollectionsEnabled=0. onedrive-uninstall-intentional: Uninstalls the pre-installed OneDrive consumer version via OneDriveSetup.exe /uninstall and removes Start Menu shortcut. Intentional for clean MSP deployment baseline. No DisableFileSyncNGSC policy key is set - M365 installation can reinstall and run OneDrive normally. Only the stock consumer pre-install is removed. powercfg-nastaveni-spotreba-energie: powercfg /change: standby-timeout-ac 0 (never sleep on AC), monitor-timeout-ac 60 (screen off after 60 min on AC), standby-timeout-dc 30 (sleep after 30 min on battery), monitor-timeout-dc 15 (screen off after 15 min on battery). Applied to active power plan. proxy-auto-detect-zakaz-autodetect-0: HKLM\SOFTWARE\Policies\Microsoft\Windows\CurrentVersion\Internet Settings\AutoDetect = 0. Disables WPAD (Web Proxy Auto-Discovery). Eliminates startup delays from WPAD DNS lookup and prevents MITM via rogue WPAD on untrusted networks. #> param( [object]$Config, [string]$LogFile ) $ErrorActionPreference = "Continue" function Write-Log { param([string]$Message, [string]$Level = "INFO") $line = "[$(Get-Date -Format 'HH:mm:ss')] [$Level] $Message" $null = New-Item -ItemType Directory -Force -Path (Split-Path $LogFile -Parent) -ErrorAction SilentlyContinue Add-Content -Path $LogFile -Value $line -Encoding UTF8 } function Get-Feature { param([object]$Cfg, [string]$StepID, [string]$FeatureID, [bool]$Default = $true) try { if ($null -eq $Cfg) { return $Default } $stepFeatures = $Cfg.features.$StepID if ($null -eq $stepFeatures) { return $Default } $val = $stepFeatures.$FeatureID if ($null -eq $val) { return $Default } return [bool]$val } catch { return $Default } } Add-Type -TypeDefinition @" using System; using System.Runtime.InteropServices; public class RegPrivilege { [DllImport("advapi32.dll", ExactSpelling=true, SetLastError=true)] static extern bool AdjustTokenPrivileges(IntPtr htok, bool disAll, ref TokPriv1Luid newState, int len, IntPtr prev, IntPtr relen); [DllImport("kernel32.dll", ExactSpelling=true)] static extern IntPtr GetCurrentProcess(); [DllImport("advapi32.dll", ExactSpelling=true, SetLastError=true)] static extern bool OpenProcessToken(IntPtr h, int acc, ref IntPtr phtok); [DllImport("advapi32.dll", SetLastError=true)] static extern bool LookupPrivilegeValue(string host, string name, ref long pluid); [StructLayout(LayoutKind.Sequential, Pack=1)] struct TokPriv1Luid { public int Count; public long Luid; public int Attr; } const int TOKEN_QUERY = 0x8; const int TOKEN_ADJUST = 0x20; const int SE_PRIVILEGE_ENABLED = 2; public static bool Enable(string privilege) { IntPtr htok = IntPtr.Zero; if (!OpenProcessToken(GetCurrentProcess(), TOKEN_ADJUST | TOKEN_QUERY, ref htok)) return false; TokPriv1Luid tp; tp.Count = 1; tp.Luid = 0; tp.Attr = SE_PRIVILEGE_ENABLED; if (!LookupPrivilegeValue(null, privilege, ref tp.Luid)) return false; return AdjustTokenPrivileges(htok, false, ref tp, 0, IntPtr.Zero, IntPtr.Zero); } } "@ -ErrorAction SilentlyContinue function Grant-RegWriteAccess { param([string]$Path) # Grants Administrators FullControl on a TrustedInstaller-owned registry key. # Enables SeTakeOwnershipPrivilege + SeRestorePrivilege to override ACL. try { [RegPrivilege]::Enable("SeTakeOwnershipPrivilege") | Out-Null [RegPrivilege]::Enable("SeRestorePrivilege") | Out-Null $hive = $Path -replace '^(HKLM|HKCU|HKU|HKCR|HKCC):\\.*', '$1' $subkey = $Path -replace '^(HKLM|HKCU|HKU|HKCR|HKCC):\\', '' $rootKey = switch ($hive) { "HKLM" { [Microsoft.Win32.Registry]::LocalMachine } "HKCU" { [Microsoft.Win32.Registry]::CurrentUser } "HKCR" { [Microsoft.Win32.Registry]::ClassesRoot } } # Take ownership (requires SeTakeOwnershipPrivilege) $key = $rootKey.OpenSubKey($subkey, [Microsoft.Win32.RegistryKeyPermissionCheck]::ReadWriteSubTree, [System.Security.AccessControl.RegistryRights]::TakeOwnership) if ($key) { $acl = $key.GetAccessControl([System.Security.AccessControl.AccessControlSections]::None) $acl.SetOwner([System.Security.Principal.NTAccount]"BUILTIN\Administrators") $key.SetAccessControl($acl) $key.Close() } # Grant FullControl to Administrators (requires ChangePermissions) $key = $rootKey.OpenSubKey($subkey, [Microsoft.Win32.RegistryKeyPermissionCheck]::ReadWriteSubTree, [System.Security.AccessControl.RegistryRights]::ChangePermissions) if ($key) { $acl = $key.GetAccessControl() $rule = New-Object System.Security.AccessControl.RegistryAccessRule( "BUILTIN\Administrators", [System.Security.AccessControl.RegistryRights]::FullControl, [System.Security.AccessControl.InheritanceFlags]"ContainerInherit,ObjectInherit", [System.Security.AccessControl.PropagationFlags]::None, [System.Security.AccessControl.AccessControlType]::Allow) $acl.SetAccessRule($rule) $key.SetAccessControl($acl) $key.Close() } Write-Log " ACL fixed for $Path" -Level INFO } catch { Write-Log " Grant-RegWriteAccess failed for $Path - $_" -Level WARN } } function Set-Reg { param( [string]$Path, [string]$Name, $Value, [string]$Type = "DWord" ) try { if (-not (Test-Path $Path)) { New-Item -Path $Path -Force -ErrorAction Stop | Out-Null } Set-ItemProperty -Path $Path -Name $Name -Value $Value -Type $Type -Force -ErrorAction Stop Write-Log " SET $Path\$Name = $Value" -Level OK } catch { # Retry 1: grant write access via ACL manipulation try { Grant-RegWriteAccess -Path $Path if (-not (Test-Path $Path)) { New-Item -Path $Path -Force -ErrorAction Stop | Out-Null } Set-ItemProperty -Path $Path -Name $Name -Value $Value -Type $Type -Force -ErrorAction Stop Write-Log " SET $Path\$Name = $Value (after ACL fix)" -Level OK return } catch { } # Retry 2: write via scheduled task running as SYSTEM # SYSTEM has full registry access regardless of key ACL try { $regType = switch ($Type) { "DWord" { "REG_DWORD" } "String" { "REG_SZ" } "ExpandString"{ "REG_EXPAND_SZ" } "MultiString" { "REG_MULTI_SZ" } "QWord" { "REG_QWORD" } default { "REG_DWORD" } } # Convert registry PS path to reg.exe path $regPath = $Path -replace '^HKLM:\\', 'HKLM\' ` -replace '^HKCU:\\', 'HKCU\' ` -replace '^HKCR:\\', 'HKCR\' $tempScript = "$env:TEMP\set-reg-system-$([System.IO.Path]::GetRandomFileName()).ps1" "reg add `"$regPath`" /v `"$Name`" /t $regType /d $Value /f" | Set-Content -Path $tempScript -Encoding UTF8 $taskName = "TempRegFix-$([System.IO.Path]::GetRandomFileName())" $action = New-ScheduledTaskAction -Execute "cmd.exe" ` -Argument "/c reg add `"$regPath`" /v `"$Name`" /t $regType /d $Value /f" $principal = New-ScheduledTaskPrincipal -UserId "SYSTEM" -RunLevel Highest $settings = New-ScheduledTaskSettingsSet -ExecutionTimeLimit (New-TimeSpan -Seconds 30) $task = New-ScheduledTask -Action $action -Principal $principal -Settings $settings Register-ScheduledTask -TaskName $taskName -InputObject $task -Force | Out-Null Start-ScheduledTask -TaskName $taskName Start-Sleep -Seconds 2 Unregister-ScheduledTask -TaskName $taskName -Confirm:$false -ErrorAction SilentlyContinue Remove-Item $tempScript -Force -ErrorAction SilentlyContinue # Verify it was written $written = (Get-ItemProperty -Path $Path -Name $Name -ErrorAction SilentlyContinue).$Name if ($null -ne $written) { Write-Log " SET $Path\$Name = $Value (via SYSTEM task)" -Level OK } else { Write-Log " FAILED $Path\$Name - SYSTEM task ran but value not found" -Level ERROR } } catch { Write-Log " FAILED $Path\$Name - $_" -Level ERROR } } } function Remove-Reg { param([string]$Path, [string]$Name) try { if (Test-Path $Path) { Remove-ItemProperty -Path $Path -Name $Name -Force -ErrorAction SilentlyContinue Write-Log " REMOVED $Path\$Name" -Level OK } } catch { Write-Log " FAILED removing $Path\$Name - $_" -Level ERROR } } Write-Log "3 - Applying HKLM system registry tweaks" -Level STEP # ----------------------------------------------------------------------- # Always-on: password and timezone (fundamental system settings) # ----------------------------------------------------------------------- Write-Log " Setting password max age to UNLIMITED" -Level INFO $pwResult = & net accounts /maxpwage:UNLIMITED 2>&1 if ($LASTEXITCODE -eq 0) { Write-Log " Password max age set to UNLIMITED" -Level OK } else { Write-Log " Failed to set password max age: $pwResult" -Level ERROR } $tz = "Central Europe Standard Time" if ($Config -and $Config.deployment -and $Config.deployment.timezone) { $tz = $Config.deployment.timezone } Write-Log " Setting time zone: $tz" -Level INFO try { Set-TimeZone -Id $tz -ErrorAction Stop Write-Log " Time zone set: $tz" -Level OK } catch { Write-Log " Failed to set time zone: $_" -Level ERROR } # ----------------------------------------------------------------------- # System tweaks (Windows features, cloud noise, Xbox, Recall, Search UI) # ----------------------------------------------------------------------- if (Get-Feature $Config "systemRegistry" "systemTweaks") { Write-Log " Applying system tweaks" -Level INFO # Bypass Network Requirement on OOBE (BypassNRO) Set-Reg -Path "HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\OOBE" ` -Name "BypassNRO" -Value 1 # Disable auto-install of Teams (Chat) Set-Reg -Path "HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\Communications" ` -Name "ConfigureChatAutoInstall" -Value 0 # Disable Cloud Optimized Content (ads in Start menu etc.) Set-Reg -Path "HKLM:\SOFTWARE\Policies\Microsoft\Windows\CloudContent" ` -Name "DisableCloudOptimizedContent" -Value 1 Set-Reg -Path "HKLM:\SOFTWARE\Policies\Microsoft\Windows\CloudContent" ` -Name "DisableWindowsConsumerFeatures" -Value 1 # Disable Widgets (News and Interests) Set-Reg -Path "HKLM:\SOFTWARE\Policies\Microsoft\Dsh" ` -Name "AllowNewsAndInterests" -Value 0 # Disable Outlook (new) auto-install via UScheduler Write-Log " Disabling Outlook (new) auto-install" -Level INFO $uschedulerPaths = @( "HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\WindowsUpdate\Orchestrator\UScheduler_Oobe\OutlookUpdate" "HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\WindowsUpdate\Orchestrator\UScheduler\OutlookUpdate" ) foreach ($uPath in $uschedulerPaths) { if (Test-Path $uPath) { try { Remove-Item -Path $uPath -Recurse -Force Write-Log " Removed UScheduler key: $uPath" -Level OK } catch { Write-Log " Failed to remove UScheduler key: $_" -Level WARN } } } # Disable GameDVR Set-Reg -Path "HKLM:\SOFTWARE\Policies\Microsoft\Windows\GameDVR" ` -Name "AllowGameDVR" -Value 0 # Disable Recall (Windows AI feature) Set-Reg -Path "HKLM:\SOFTWARE\Policies\Microsoft\Windows\WindowsAI" ` -Name "DisableAIDataAnalysis" -Value 1 # Search on taskbar - hide via HKLM policy (Win11 22H2+ enforcement) # User-level SearchboxTaskbarMode alone is insufficient on newer Win11 builds; # this policy key ensures the setting survives Windows Updates. Set-Reg -Path "HKLM:\SOFTWARE\Policies\Microsoft\Windows\Windows Search" ` -Name "SearchOnTaskbarMode" -Value 0 # Start menu - hide Recommended section (Win11) Set-Reg -Path "HKLM:\SOFTWARE\Policies\Microsoft\Windows\Explorer" ` -Name "HideRecommendedSection" -Value 1 } else { Write-Log "systemTweaks feature disabled - skipping" -Level INFO } # ----------------------------------------------------------------------- # Microsoft Edge policies # ----------------------------------------------------------------------- if (Get-Feature $Config "systemRegistry" "edgePolicies") { Write-Log " Applying Edge policies" -Level INFO $edgePath = "HKLM:\SOFTWARE\Policies\Microsoft\Edge" # UI / first run Set-Reg -Path $edgePath -Name "HideFirstRunExperience" -Value 1 Set-Reg -Path $edgePath -Name "DefaultBrowserSettingEnabled" -Value 0 # New tab page / recommendations Set-Reg -Path $edgePath -Name "NewTabPageContentEnabled" -Value 0 Set-Reg -Path $edgePath -Name "ShowRecommendationsEnabled" -Value 0 Set-Reg -Path $edgePath -Name "SpotlightExperiencesAndRecommendationsEnabled" -Value 0 Set-Reg -Path $edgePath -Name "PersonalizationReportingEnabled" -Value 0 # Shopping / rewards / sidebar Set-Reg -Path $edgePath -Name "EdgeShoppingAssistantEnabled" -Value 0 Set-Reg -Path $edgePath -Name "ShowMicrosoftRewards" -Value 0 Set-Reg -Path $edgePath -Name "HubsSidebarEnabled" -Value 0 # Search suggestions Set-Reg -Path $edgePath -Name "SearchSuggestEnabled" -Value 0 Set-Reg -Path $edgePath -Name "ImportOnEachLaunch" -Value 0 # Telemetry / feedback Set-Reg -Path $edgePath -Name "DiagnosticData" -Value 0 Set-Reg -Path $edgePath -Name "FeedbackSurveysEnabled" -Value 0 Set-Reg -Path $edgePath -Name "EdgeCollectionsEnabled" -Value 0 # Toolbar buttons - show Set-Reg -Path $edgePath -Name "FavoritesBarEnabled" -Value 1 # Favorites bar always visible Set-Reg -Path $edgePath -Name "DownloadsButtonEnabled" -Value 1 Set-Reg -Path $edgePath -Name "HistoryButtonEnabled" -Value 1 Set-Reg -Path $edgePath -Name "PerformanceButtonEnabled" -Value 1 # Sleeping Tabs / Performance # Toolbar buttons - hide Set-Reg -Path $edgePath -Name "HomeButtonEnabled" -Value 0 Set-Reg -Path $edgePath -Name "SplitScreenEnabled" -Value 0 Set-Reg -Path $edgePath -Name "EdgeEDropEnabled" -Value 0 # Drop Set-Reg -Path $edgePath -Name "WebCaptureEnabled" -Value 0 # Screenshot Set-Reg -Path $edgePath -Name "ShareAllowed" -Value 0 # Share # Default search engine: Google # SearchProviderEnabled must be 1, SearchProviderName + URL set the provider Set-Reg -Path $edgePath -Name "DefaultSearchProviderEnabled" -Value 1 -Type "DWord" Set-Reg -Path $edgePath -Name "DefaultSearchProviderName" -Value "Google" -Type "String" Set-Reg -Path $edgePath -Name "DefaultSearchProviderSearchURL" ` -Value "https://www.google.com/search?q={searchTerms}" -Type "String" # Remove other search engines (empty list = no other providers besides default) Set-Reg -Path $edgePath -Name "ManagedSearchEngines" ` -Value '[{"is_default":true,"name":"Google","search_url":"https://www.google.com/search?q={searchTerms}","keyword":"google.com"}]' ` -Type "String" # Disable desktop shortcut on install/update Set-Reg -Path "HKLM:\SOFTWARE\Policies\Microsoft\EdgeUpdate" ` -Name "CreateDesktopShortcutDefault" -Value 0 } else { Write-Log "edgePolicies feature disabled - skipping" -Level INFO } # ----------------------------------------------------------------------- # OneDrive - uninstall from clean Windows (no policy block) # NOTE: No policy key is set intentionally - M365 installation can reinstall # and run OneDrive normally. Policy DisableFileSyncNGSC would prevent that. # ----------------------------------------------------------------------- if (Get-Feature $Config "systemRegistry" "oneDriveUninstall") { Write-Log " Uninstalling OneDrive" -Level INFO $oneDrivePaths = @( "$env:SystemRoot\System32\OneDriveSetup.exe" "$env:SystemRoot\SysWOW64\OneDriveSetup.exe" ) foreach ($odPath in $oneDrivePaths) { if (Test-Path $odPath) { try { & $odPath /uninstall 2>&1 | Out-Null Write-Log " OneDrive uninstalled via $odPath" -Level OK } catch { Write-Log " OneDrive uninstall failed: $_" -Level WARN } } } # Remove OneDrive Start Menu shortcut $odLnk = "$env:ProgramData\Microsoft\Windows\Start Menu\Programs\OneDrive.lnk" if (Test-Path $odLnk) { Remove-Item $odLnk -Force -ErrorAction SilentlyContinue Write-Log " Removed OneDrive Start Menu shortcut" -Level OK } } else { Write-Log "oneDriveUninstall feature disabled - skipping" -Level INFO } # ----------------------------------------------------------------------- # Power configuration # ----------------------------------------------------------------------- if (Get-Feature $Config "systemRegistry" "powercfg") { Write-Log " Applying power configuration" -Level INFO $powercfgArgs = @( @("/change", "standby-timeout-ac", "0"), # never sleep on AC @("/change", "monitor-timeout-ac", "60"), # screen off after 60 min on AC @("/change", "standby-timeout-dc", "30"), # sleep after 30 min on battery @("/change", "monitor-timeout-dc", "15") # screen off after 15 min on battery ) foreach ($a in $powercfgArgs) { $result = & powercfg @a 2>&1 if ($LASTEXITCODE -eq 0) { Write-Log " powercfg $($a -join ' ')" -Level OK } else { Write-Log " powercfg $($a -join ' ') failed: $result" -Level WARN } } } else { Write-Log "powercfg feature disabled - skipping" -Level INFO } # ----------------------------------------------------------------------- # Proxy auto-detect disable (WPAD) # ----------------------------------------------------------------------- if (Get-Feature $Config "systemRegistry" "proxyDisable") { Write-Log " Disabling WPAD proxy auto-detect" -Level INFO Set-Reg -Path "HKLM:\SOFTWARE\Policies\Microsoft\Windows\CurrentVersion\Internet Settings" ` -Name "AutoDetect" -Value 0 } else { Write-Log "proxyDisable feature disabled - skipping" -Level INFO } Write-Log "Step 3 complete" -Level OK