The file /opt/xetup/scripts/03-system-registry.ps1 has been updated successfully.

<#
.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"
    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

Add-Content -Path $LogFile -Value $line -Encoding UTF8

+    param([object]$Cfg, [string]$StepID, [string]$FeatureID, [bool]$Default = $true)

+        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 }

Write-Log "3 - Applying HKLM system registry tweaks" -Level STEP

-# Bypass Network Requirement on OOBE (BypassNRO)

+# Always-on: password and timezone (fundamental system settings)

-Set-Reg -Path "HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\OOBE" `

-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

-        -Name "DisableWindowsConsumerFeatures" -Value 1

-Set-Reg -Path "HKLM:\SOFTWARE\Policies\Microsoft\Dsh" `

-        -Name "AllowNewsAndInterests" -Value 0

-Set-Reg -Path $edgePath -Name "HideFirstRunExperience"    -Value 1

-Set-Reg -Path $edgePath -Name "DefaultBrowserSettingEnabled" -Value 0

-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

-Set-Reg -Path $edgePath -Name "EdgeShoppingAssistantEnabled" -Value 0

-Set-Reg -Path $edgePath -Name "ShowMicrosoftRewards"         -Value 0

-Set-Reg -Path $edgePath -Name "HubsSidebarEnabled"           -Value 0

-Set-Reg -Path $edgePath -Name "SearchSuggestEnabled"  -Value 0

-Set-Reg -Path $edgePath -Name "ImportOnEachLaunch"    -Value 0

-Set-Reg -Path $edgePath -Name "DiagnosticData"                  -Value 0

-Set-Reg -Path $edgePath -Name "FeedbackSurveysEnabled"          -Value 0

-Set-Reg -Path $edgePath -Name "EdgeCollectionsEnabled"          -Value 0

-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

-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

-# 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"}]' `

-# Disable desktop shortcut on install/update

-Set-Reg -Path "HKLM:\SOFTWARE\Policies\Microsoft\EdgeUpdate" `

-        -Name "CreateDesktopShortcutDefault" -Value 0

Write-Log "  Setting password max age to UNLIMITED" -Level INFO

$pwResult = & net accounts /maxpwage:UNLIMITED 2>&1

Write-Log "  Failed to set password max age: $pwResult" -Level ERROR

-# 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.

+# System tweaks (Windows features, cloud noise, Xbox, Recall, Search UI)

-Write-Log "  Uninstalling OneDrive" -Level INFO

+if (Get-Feature $Config "systemRegistry" "systemTweaks") {

+    Write-Log "  Applying system tweaks" -Level INFO

-    "$env:SystemRoot\System32\OneDriveSetup.exe"

-    "$env:SystemRoot\SysWOW64\OneDriveSetup.exe"

-            & $odPath /uninstall 2>&1 | Out-Null

-            Write-Log "  OneDrive uninstalled via $odPath" -Level OK

+    # Bypass Network Requirement on OOBE (BypassNRO)

+    Set-Reg -Path "HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\OOBE" `

+    # 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

+            -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

+        "HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\WindowsUpdate\Orchestrator\UScheduler_Oobe\OutlookUpdate"

+        "HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\WindowsUpdate\Orchestrator\UScheduler\OutlookUpdate"

+    foreach ($uPath in $uschedulerPaths) {

+                Remove-Item -Path $uPath -Recurse -Force

+                Write-Log "  Removed UScheduler key: $uPath" -Level OK

+                Write-Log "  Failed to remove UScheduler key: $_" -Level WARN

-            Write-Log "  OneDrive uninstall failed: $_" -Level WARN

-$odLnk = "$env:ProgramData\Microsoft\Windows\Start Menu\Programs\OneDrive.lnk"

-    Remove-Item $odLnk -Force -ErrorAction SilentlyContinue

-    Write-Log "  Removed OneDrive Start Menu shortcut" -Level OK

+    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

+    Write-Log "systemTweaks feature disabled - skipping" -Level INFO

-# Outlook (new) - disable auto-install via UScheduler

-Write-Log "  Disabling Outlook (new) auto-install" -Level INFO

+if (Get-Feature $Config "systemRegistry" "edgePolicies") {

+    Write-Log "  Applying Edge policies" -Level INFO

+    $edgePath = "HKLM:\SOFTWARE\Policies\Microsoft\Edge"

-    "HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\WindowsUpdate\Orchestrator\UScheduler_Oobe\OutlookUpdate"

-    "HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\WindowsUpdate\Orchestrator\UScheduler\OutlookUpdate"

-            Remove-Item -Path $uPath -Recurse -Force

-            Write-Log "  Removed UScheduler key: $uPath" -Level OK

-            Write-Log "  Failed to remove UScheduler key: $_" -Level WARN

+    Set-Reg -Path $edgePath -Name "HideFirstRunExperience"       -Value 1

+    Set-Reg -Path $edgePath -Name "DefaultBrowserSettingEnabled" -Value 0

+    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

+    Set-Reg -Path $edgePath -Name "EdgeShoppingAssistantEnabled" -Value 0

+    Set-Reg -Path $edgePath -Name "ShowMicrosoftRewards"         -Value 0

+    Set-Reg -Path $edgePath -Name "HubsSidebarEnabled"           -Value 0

+    Set-Reg -Path $edgePath -Name "SearchSuggestEnabled" -Value 0

+    Set-Reg -Path $edgePath -Name "ImportOnEachLaunch"   -Value 0

+    Set-Reg -Path $edgePath -Name "DiagnosticData"         -Value 0

+    Set-Reg -Path $edgePath -Name "FeedbackSurveysEnabled" -Value 0

+    Set-Reg -Path $edgePath -Name "EdgeCollectionsEnabled" -Value 0

+    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

+    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

+    # 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"}]' `

+    # Disable desktop shortcut on install/update

+    Set-Reg -Path "HKLM:\SOFTWARE\Policies\Microsoft\EdgeUpdate" `

+            -Name "CreateDesktopShortcutDefault" -Value 0

+    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.

-Set-Reg -Path "HKLM:\SOFTWARE\Policies\Microsoft\Windows\GameDVR" `

+if (Get-Feature $Config "systemRegistry" "oneDriveUninstall") {

+    Write-Log "  Uninstalling OneDrive" -Level INFO

-Set-Reg -Path "HKLM:\SOFTWARE\Policies\Microsoft\Windows\WindowsAI" `

-        -Name "DisableAIDataAnalysis" -Value 1

+        "$env:SystemRoot\System32\OneDriveSetup.exe"

+        "$env:SystemRoot\SysWOW64\OneDriveSetup.exe"

+    foreach ($odPath in $oneDrivePaths) {

+                & $odPath /uninstall 2>&1 | Out-Null

+                Write-Log "  OneDrive uninstalled via $odPath" -Level OK

+                Write-Log "  OneDrive uninstall failed: $_" -Level WARN

-# 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

+    # Remove OneDrive Start Menu shortcut

+    $odLnk = "$env:ProgramData\Microsoft\Windows\Start Menu\Programs\OneDrive.lnk"

+        Remove-Item $odLnk -Force -ErrorAction SilentlyContinue

+        Write-Log "  Removed OneDrive Start Menu shortcut" -Level OK

+    Write-Log "oneDriveUninstall feature disabled - skipping" -Level INFO

-# Start menu - hide Recommended section (Win11)

-Set-Reg -Path "HKLM:\SOFTWARE\Policies\Microsoft\Windows\Explorer" `

-        -Name "HideRecommendedSection" -Value 1

-Write-Log "Applying power configuration" -Level INFO

+if (Get-Feature $Config "systemRegistry" "powercfg") {

+    Write-Log "  Applying power configuration" -Level INFO

-    @("/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

-        Write-Log "  powercfg $($args -join ' ')" -Level OK

-        Write-Log "  powercfg $($args -join ' ') failed: $result" -Level WARN

+        @("/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

+            Write-Log "  powercfg $($a -join ' ')" -Level OK

+            Write-Log "  powercfg $($a -join ' ') failed: $result" -Level WARN

+    Write-Log "powercfg feature disabled - skipping" -Level INFO

-Set-Reg -Path "HKLM:\SOFTWARE\Policies\Microsoft\Windows\CurrentVersion\Internet Settings" `

+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

+    Write-Log "proxyDisable feature disabled - skipping" -Level INFO


Teď `04-default-profile.ps1`:


1	<#
2	.SYNOPSIS
3	    Applies registry settings to the Default User profile and the current logged-in user.
4
5	.DESCRIPTION
6	    Loads C:\Users\Default\NTUSER.DAT as a temporary hive (HKU\DefaultProfile), applies
7	    all settings, then unloads it. Every new user account created on this machine inherits
8	    these settings on first logon. The same settings are applied directly to the current
9	    user's HKCU. Does NOT block OneDrive re-launch - the Explorer namespace CLSID and RunOnce entries have been removed.
10
11	.ITEMS
12	    taskbar-zarovnat-vlevo-taskbaral-0: TaskbarAl = 0 in Explorer\Advanced. Windows 11 default is center-aligned (TaskbarAl = 1). Left alignment matches Windows 10 muscle memory and is strongly preferred by business users transitioning from Win10.
13	    taskbar-skryt-search-copilot-task-view-w: Hides Search box (SearchboxTaskbarMode=0), Copilot button (ShowCopilotButton=0), Task View (ShowTaskViewButton=0), Widgets (TaskbarDa=0), Chat/Teams (TaskbarMn=0). Reduces taskbar clutter to just pinned apps and running processes.
14	    taskbar-zobrazit-vsechny-ikonky-v-tray-s: Registers scheduled task that sets EnableAutoTray=0 on logon (repeat every 1 min). Windows 11 periodically re-hides tray icons - this task forces all icons visible so users can see VPN status, antivirus, backup, etc.
15	    taskbar-vyprazdnit-pinlist-taskbarlayout: Deploys TaskbarLayoutModification.xml. ProfileType=default: empty pins (clean slate). ProfileType=admin: Explorer+PowerShell+Edge. ProfileType=user: Explorer+Edge. Lock is removed by UnlockStartLayout task 5 min after first boot so users can customize.
16	    explorer-zobrazovat-pripony-souboru-hide: HideFileExt = 0 in Explorer\Advanced. Shows file extensions (.docx, .exe, .pdf, .ps1) in File Explorer. Essential for recognizing file types, avoiding phishing (fake .pdf.exe), and general IT work.
17	    explorer-otevrit-na-this-pc-launchto-1: LaunchTo = 1. File Explorer opens to "This PC" (drives view) instead of Quick Access. More useful on fresh machines where Quick Access history is empty and irrelevant.
18	    start-menu-vyprazdnit-piny-win11: ConfigureStartPins = {"pinnedList":[]} applied via registry. Removes all default Start menu tiles (Edge, Teams, Store, Office, Solitaire, etc.) from the Windows 11 Start grid. User starts with an empty, clean Start menu.
19	    start-menu-zakaz-bing-vyhledavani: DisableSearchBoxSuggestions = 1 in Software\Policies\Microsoft\Windows. Disables web search, Bing suggestions, and online results in Start menu search. Search returns only local apps, files, and settings.
20	    copilot-zakaz-turnoffwindowscopilot-1: TurnOffWindowsCopilot = 1 in SOFTWARE\Policies\Microsoft\Windows\WindowsCopilot. Disables the Windows Copilot sidebar entirely. Not suitable for most client environments (data privacy, AI usage policies).
21	    numlock-zapnout-pri-startu-initialkeyboa: InitialKeyboardIndicators = 2 in Default profile. Ensures NumLock is enabled when Windows starts. Standard expectation for users working with numeric data - prevents confusion on data entry.
22	    accent-barva-na-titulnich-listech-colorp: ColorPrevalence = 1 in Personalize key. Shows the X9.cz accent color (#223B47) on window title bars and borders. Gives all windows a consistent branded appearance.
23	    onedrive-runonce-klic-je-tady-smazat: REMOVED. The RunOnce key deletion and Explorer namespace CLSID removal were deleted - those registry tweaks prevented a freshly installed OneDrive (e.g. for M365) from launching. OneDrive AppX uninstall in step 01 is intentional; blocking re-launch is not.
24	    explorer-showrecent-0-showfrequent-0: ShowRecent=0 and ShowFrequent=0 in HKCU\Software\Microsoft\Windows\CurrentVersion\Explorer. Hides Recent files and Frequent folders from Quick Access. Privacy improvement and cleaner File Explorer on fresh deployments.
25	    explorer-fullpath-1-cabinetstate: FullPath=1 in HKCU\Software\Microsoft\Windows\CurrentVersion\Explorer\CabinetState. Displays the full directory path (e.g. C:\Users\jan\Documents\Projekty) in the File Explorer title bar instead of just the folder name.
26	#>
27	param(
28	    [object]$Config,
29	    [string]$LogFile,
30	    [ValidateSet("default","admin","user")]
31	    [string]$ProfileType = "default"
32	)
33
34	$ErrorActionPreference = "Continue"
35
36	function Write-Log {
37	    param([string]$Message, [string]$Level = "INFO")
38	    $line = "[$(Get-Date -Format 'HH:mm:ss')] [$Level] $Message"
39	    Add-Content -Path $LogFile -Value $line -Encoding UTF8
40	}
41
42	# -----------------------------------------------------------------------
43	# Helper - apply a registry setting to both Default hive and current HKCU
44	# -----------------------------------------------------------------------
45	function Grant-HiveWriteAccess {
46	    param([string]$HivePath)  # full path e.g. "Registry::HKU\DefaultProfile\Software\..."
47	    # Grants Administrators FullControl on a loaded hive key with restricted ACL.
48	    try {
49	        $acl  = Get-Acl -Path $HivePath -ErrorAction Stop
50	        $rule = New-Object System.Security.AccessControl.RegistryAccessRule(
51	            "BUILTIN\Administrators",
52	            [System.Security.AccessControl.RegistryRights]::FullControl,
53	            [System.Security.AccessControl.InheritanceFlags]"ContainerInherit,ObjectInherit",
54	            [System.Security.AccessControl.PropagationFlags]::None,
55	            [System.Security.AccessControl.AccessControlType]::Allow
56	        )
57	        $acl.SetAccessRule($rule)
58	        Set-Acl -Path $HivePath -AclObject $acl -ErrorAction Stop
59	    }
60	    catch {
61	        Write-Log "  Grant-HiveWriteAccess failed for $HivePath - $_" -Level WARN
62	    }
63	}
64
65	function Set-ProfileReg {
66	    param(
67	        [string]$SubKey,   # relative to HKCU (e.g. "Software\Microsoft\...")
68	        [string]$Name,
69	        $Value,
70	        [string]$Type = "DWord"
71	    )
72
73	    # Apply to loaded Default hive
74	    $defPath = "Registry::HKU\DefaultProfile\$SubKey"
75	    try {
76	        if (-not (Test-Path $defPath)) {
77	            New-Item -Path $defPath -Force -ErrorAction Stop | Out-Null
78	        }
79	        Set-ItemProperty -Path $defPath -Name $Name -Value $Value -Type $Type -Force -ErrorAction Stop
80	    }
81	    catch {
82	        # Retry after granting write access to parent key
83	        try {
84	            $parentPath = $defPath -replace '\\[^\\]+$', ''
85	            if (Test-Path $parentPath) { Grant-HiveWriteAccess -HivePath $parentPath }
86	            if (-not (Test-Path $defPath)) {
87	                New-Item -Path $defPath -Force -ErrorAction Stop | Out-Null
88	            }
89	            Set-ItemProperty -Path $defPath -Name $Name -Value $Value -Type $Type -Force -ErrorAction Stop
90	        }
91	        catch {
92	            Write-Log "  DEFAULT HIVE failed $SubKey\$Name - $_" -Level ERROR
93	        }
94	    }
95
96	    # Apply to current user as well
97	    $hkcuPath = "HKCU:\$SubKey"
98	    try {
99	        if (-not (Test-Path $hkcuPath)) {
100	            New-Item -Path $hkcuPath -Force -ErrorAction Stop | Out-Null
101	        }
102	        Set-ItemProperty -Path $hkcuPath -Name $Name -Value $Value -Type $Type -Force -ErrorAction Stop
103	        Write-Log "  SET $SubKey\$Name = $Value" -Level OK
104	    }
105	    catch {
106	        Write-Log "  HKCU failed $SubKey\$Name - $_" -Level ERROR
107	    }
108	}
109
110	function Remove-ProfileReg {
111	    param([string]$SubKey, [string]$Name)
112
113	    $defPath = "Registry::HKU\DefaultProfile\$SubKey"
114	    try {
115	        if (Test-Path $defPath) {
116	            Remove-ItemProperty -Path $defPath -Name $Name -Force -ErrorAction SilentlyContinue
117	        }
118	    }
119	    catch { }
120
121	    $hkcuPath = "HKCU:\$SubKey"
122	    try {
123	        if (Test-Path $hkcuPath) {
124	            Remove-ItemProperty -Path $hkcuPath -Name $Name -Force -ErrorAction SilentlyContinue
125	            Write-Log "  REMOVED $SubKey\$Name" -Level OK
126	        }
127	    }
128	    catch {
129	        Write-Log "  FAILED removing $SubKey\$Name - $_" -Level ERROR
130	    }
131	}
132
133	# -----------------------------------------------------------------------
134	# Load Default profile hive
135	# -----------------------------------------------------------------------
136	$hivePath = "C:\Users\Default\NTUSER.DAT"
137	$hiveKey  = "DefaultProfile"
138
139	Write-Log "Loading Default hive: $hivePath" -Level INFO
140
141	# Unload first in case previous run left it mounted
142	& reg unload "HKU\$hiveKey" 2>&1 | Out-Null
143
144	$loadResult = & reg load "HKU\$hiveKey" $hivePath 2>&1
145	if ($LASTEXITCODE -ne 0) {
146	    Write-Log "Failed to load Default hive: $loadResult" -Level ERROR
147	    exit 1
148	}
149	Write-Log "Default hive loaded" -Level OK
150
151	try {
152	    # -----------------------------------------------------------------------
153	    # Taskbar settings (Win10 + Win11)
154	    # -----------------------------------------------------------------------
155	    Write-Log "Applying taskbar settings" -Level STEP
156
157	    $tbPath = "Software\Microsoft\Windows\CurrentVersion\Explorer\Advanced"
158
159	    # Win11: align taskbar to left (0 = left, 1 = center)
160	    Set-ProfileReg -SubKey $tbPath -Name "TaskbarAl" -Value 0
161
162	    # Hide Search box / button - Win10/11 (0 = hidden, 1 = icon, 2 = full box)
163	    # Note: Win11 uses Search subkey, Win10 uses Explorer\Advanced - set both
164	    Set-ProfileReg -SubKey "Software\Microsoft\Windows\CurrentVersion\Search" `
165	                   -Name "SearchboxTaskbarMode" -Value 0
166	    Set-ProfileReg -SubKey $tbPath -Name "SearchboxTaskbarMode" -Value 0
167
168	    # Hide Task View button
169	    Set-ProfileReg -SubKey $tbPath -Name "ShowTaskViewButton" -Value 0
170
171	    # Hide Widgets button
172	    Set-ProfileReg -SubKey $tbPath -Name "TaskbarDa" -Value 0
173
174	    # Hide Chat / Teams button
175	    Set-ProfileReg -SubKey $tbPath -Name "TaskbarMn" -Value 0
176
177	    # Hide Copilot button
178	    Set-ProfileReg -SubKey $tbPath -Name "ShowCopilotButton" -Value 0
179
180	    # Show file extensions in Explorer
181	    Set-ProfileReg -SubKey $tbPath -Name "HideFileExt" -Value 0
182
183	    # Open Explorer to This PC instead of Quick Access
184	    Set-ProfileReg -SubKey $tbPath -Name "LaunchTo" -Value 1
185
186	    # -----------------------------------------------------------------------
187	    # System tray - show all icons
188	    # -----------------------------------------------------------------------
189	    # EnableAutoTray = 0 works on Win10; Win11 ignores it but set anyway
190	    Set-ProfileReg -SubKey "Software\Microsoft\Windows\CurrentVersion\Explorer" `
191	                   -Name "EnableAutoTray" -Value 0
192
193	    # Win11 workaround: clear cached tray icon streams so all icons appear on next login
194	    # Windows rebuilds the streams with all icons visible when no cache exists
195	    $trayNotifyKey = "HKCU:\Software\Classes\Local Settings\Software\Microsoft\Windows\CurrentVersion\TrayNotify"
196	    if (Test-Path $trayNotifyKey) {
197	        Remove-ItemProperty -Path $trayNotifyKey -Name "IconStreams"     -Force -ErrorAction SilentlyContinue
198	        Remove-ItemProperty -Path $trayNotifyKey -Name "PastIconsStream" -Force -ErrorAction SilentlyContinue
199	        Write-Log "  Cleared TrayNotify icon streams (Win11 systray workaround)" -Level OK
200	    }
201
202	    # Also clear in Default hive so new users start with clean state
203	    $defTrayKey = "Registry::HKU\DefaultProfile\Software\Classes\Local Settings\Software\Microsoft\Windows\CurrentVersion\TrayNotify"
204	    if (Test-Path $defTrayKey) {
205	        Remove-ItemProperty -Path $defTrayKey -Name "IconStreams"     -Force -ErrorAction SilentlyContinue
206	        Remove-ItemProperty -Path $defTrayKey -Name "PastIconsStream" -Force -ErrorAction SilentlyContinue
207	        Write-Log "  Cleared TrayNotify icon streams in Default hive" -Level OK
208	    }
209
210	    # -----------------------------------------------------------------------
211	    # Desktop icons - show This PC
212	    # -----------------------------------------------------------------------
213	    # CLSID {20D04FE0-3AEA-1069-A2D8-08002B30309D} = This PC / Computer
214	    Set-ProfileReg -SubKey "Software\Microsoft\Windows\CurrentVersion\Explorer\HideDesktopIcons\NewStartPanel" `
215	                   -Name "{20D04FE0-3AEA-1069-A2D8-08002B30309D}" -Value 0
216
217	    # -----------------------------------------------------------------------
218	    # Start menu settings
219	    # -----------------------------------------------------------------------
220	    Write-Log "Applying Start menu settings" -Level STEP
221
222	    # Disable Bing search suggestions in Start menu
223	    Set-ProfileReg -SubKey "Software\Policies\Microsoft\Windows\Explorer" `
224	                   -Name "DisableSearchBoxSuggestions" -Value 1
225
226	    # Win11: empty Start menu pins
227	    Set-ProfileReg -SubKey "Software\Microsoft\Windows\CurrentVersion\Start" `
228	                   -Name "ConfigureStartPins" `
229	                   -Value '{"pinnedList":[]}' `
230	                   -Type "String"
231
232	    # Hide "Recently added" apps in Start menu
233	    Set-ProfileReg -SubKey "Software\Microsoft\Windows\CurrentVersion\Explorer\Advanced" `
234	                   -Name "Start_TrackProgs" -Value 0
235
236	    # Hide recently opened files/docs from Start menu
237	    Set-ProfileReg -SubKey "Software\Microsoft\Windows\CurrentVersion\Explorer\Advanced" `
238	                   -Name "Start_TrackDocs" -Value 0
239
240	    # -----------------------------------------------------------------------
241	    # Copilot - disable
242	    # -----------------------------------------------------------------------
243	    Set-ProfileReg -SubKey "Software\Policies\Microsoft\Windows\WindowsCopilot" `
244	                   -Name "TurnOffWindowsCopilot" -Value 1
245
246	    # -----------------------------------------------------------------------
247	    # GameDVR - disable
248	    # -----------------------------------------------------------------------
249	    Set-ProfileReg -SubKey "System\GameConfigStore" `
250	                   -Name "GameDVR_Enabled" -Value 0
251
252	    Set-ProfileReg -SubKey "Software\Microsoft\Windows\CurrentVersion\GameDVR" `
253	                   -Name "AppCaptureEnabled" -Value 0
254
255	    # -----------------------------------------------------------------------
256	    # Num Lock on startup
257	    # -----------------------------------------------------------------------
258	    Set-ProfileReg -SubKey "Control Panel\Keyboard" `
259	                   -Name "InitialKeyboardIndicators" -Value 2 -Type "String"
260
261	    # -----------------------------------------------------------------------
262	    # Accent color on title bars
263	    # -----------------------------------------------------------------------
264	    Set-ProfileReg -SubKey "Software\Microsoft\Windows\DWM" `
265	                   -Name "ColorPrevalence" -Value 1
266
267
268	    # -----------------------------------------------------------------------
269	    # Taskbar pinned apps layout (Win10/11)
270	    # ProfileType: default = empty, admin = Explorer+PS+Edge, user = Explorer+Edge
271	    # Note: TaskbarLayoutModification.xml locks the taskbar temporarily.
272	    # UnlockStartLayout scheduled task removes the lock 5 min after first boot
273	    # so users can then customize pins freely.
274	    # Win11 24H2+ may require ProvisionedLayoutModification.xml format instead.
275	    # -----------------------------------------------------------------------
276	    Write-Log "Writing taskbar layout (ProfileType=$ProfileType)" -Level INFO
277
278	    $taskbarLayoutDir = "C:\Users\Default\AppData\Local\Microsoft\Windows\Shell"
279	    if (-not (Test-Path $taskbarLayoutDir)) {
280	        New-Item -ItemType Directory -Path $taskbarLayoutDir -Force | Out-Null
281	    }
282
283	    # Build pin list based on profile type.
284	    # Paths resolve relative to the new user at first login.
285	    # Missing shortcuts are silently skipped by Windows.
286	    $pinList = switch ($ProfileType) {
287	        "admin" {
288	@'
289	        <taskbar:DesktopApp DesktopApplicationLinkPath="%APPDATA%\Microsoft\Windows\Start Menu\Programs\System Tools\File Explorer.lnk"/>
290	        <taskbar:DesktopApp DesktopApplicationLinkPath="%APPDATA%\Microsoft\Windows\Start Menu\Programs\Windows PowerShell\Windows PowerShell.lnk"/>
291	        <taskbar:DesktopApp DesktopApplicationLinkPath="%PROGRAMDATA%\Microsoft\Windows\Start Menu\Programs\Microsoft Edge.lnk"/>
292	'@
293	        }
294	        "user" {
295	@'
296	        <taskbar:DesktopApp DesktopApplicationLinkPath="%APPDATA%\Microsoft\Windows\Start Menu\Programs\System Tools\File Explorer.lnk"/>
297	        <taskbar:DesktopApp DesktopApplicationLinkPath="%PROGRAMDATA%\Microsoft\Windows\Start Menu\Programs\Microsoft Edge.lnk"/>
298	'@
299	        }
300	        default { "" }   # empty = clean slate
301	    }
302
303	    $taskbarLayoutXml = @"
304	<?xml version="1.0" encoding="utf-8"?>
305	<LayoutModificationTemplate
306	    xmlns="http://schemas.microsoft.com/Start/2014/LayoutModification"
307	    xmlns:defaultlayout="http://schemas.microsoft.com/Start/2014/FullDefaultLayout"
308	    xmlns:start="http://schemas.microsoft.com/Start/2014/StartLayout"
309	    xmlns:taskbar="http://schemas.microsoft.com/Start/2014/TaskbarLayout"
310	    Version="1">
311	  <CustomTaskbarLayoutCollection PinListPlacement="Replace">
312	    <defaultlayout:TaskbarLayout>
313	      <taskbar:TaskbarPinList>
314	$pinList
315	      </taskbar:TaskbarPinList>
316	    </defaultlayout:TaskbarLayout>
317	  </CustomTaskbarLayoutCollection>
318	</LayoutModificationTemplate>
319	"@
320	    $taskbarLayoutXml | Set-Content -Path "$taskbarLayoutDir\LayoutModification.xml" -Encoding UTF8 -Force
321	    Write-Log "  Taskbar LayoutModification.xml written (profile: $ProfileType)" -Level OK
322
323	}
324	finally {
325	    # -----------------------------------------------------------------------
326	    # Unload Default hive - always, even on error
327	    # -----------------------------------------------------------------------
328	    Write-Log "Unloading Default hive" -Level INFO
329	    [GC]::Collect()
330	    [GC]::WaitForPendingFinalizers()
331	    Start-Sleep -Milliseconds 500
332
333	    $unloadResult = & reg unload "HKU\$hiveKey" 2>&1
334	    if ($LASTEXITCODE -eq 0) {
335	        Write-Log "Default hive unloaded" -Level OK
336	    } else {
337	        Write-Log "Failed to unload Default hive: $unloadResult" -Level ERROR
338	    }
339	}
340
341	# -----------------------------------------------------------------------
342	# Restart Explorer to apply taskbar/tray changes to current session
343	# -----------------------------------------------------------------------
344	Write-Log "Restarting Explorer to apply taskbar changes" -Level INFO
345	try {
346	    Stop-Process -Name explorer -Force -ErrorAction SilentlyContinue
347	    Start-Sleep -Seconds 2
348	    Start-Process explorer
349	    Write-Log "Explorer restarted" -Level OK
350	}
351	catch {
352	    Write-Log "Explorer restart failed (non-fatal): $_" -Level WARN
353	}
354
355	Write-Log "Step 4 complete" -Level OK
356

<#
.SYNOPSIS
    Applies registry settings to the Default User profile and the current logged-in user.

.DESCRIPTION
    Loads C:\Users\Default\NTUSER.DAT as a temporary hive (HKU\DefaultProfile), applies
    all settings, then unloads it. Every new user account created on this machine inherits
    these settings on first logon. The same settings are applied directly to the current
    user's HKCU. Does NOT block OneDrive re-launch - the Explorer namespace CLSID and RunOnce entries have been removed.

.ITEMS
    taskbar-zarovnat-vlevo-taskbaral-0: TaskbarAl = 0 in Explorer\Advanced. Windows 11 default is center-aligned (TaskbarAl = 1). Left alignment matches Windows 10 muscle memory and is strongly preferred by business users transitioning from Win10.
    taskbar-skryt-search-copilot-task-view-w: Hides Search box (SearchboxTaskbarMode=0), Copilot button (ShowCopilotButton=0), Task View (ShowTaskViewButton=0), Widgets (TaskbarDa=0), Chat/Teams (TaskbarMn=0). Reduces taskbar clutter to just pinned apps and running processes.
    taskbar-zobrazit-vsechny-ikonky-v-tray-s: Registers scheduled task that sets EnableAutoTray=0 on logon (repeat every 1 min). Windows 11 periodically re-hides tray icons - this task forces all icons visible so users can see VPN status, antivirus, backup, etc.
    taskbar-vyprazdnit-pinlist-taskbarlayout: Deploys TaskbarLayoutModification.xml. ProfileType=default: empty pins (clean slate). ProfileType=admin: Explorer+PowerShell+Edge. ProfileType=user: Explorer+Edge. Lock is removed by UnlockStartLayout task 5 min after first boot so users can customize.
    explorer-zobrazovat-pripony-souboru-hide: HideFileExt = 0 in Explorer\Advanced. Shows file extensions (.docx, .exe, .pdf, .ps1) in File Explorer. Essential for recognizing file types, avoiding phishing (fake .pdf.exe), and general IT work.
    explorer-otevrit-na-this-pc-launchto-1: LaunchTo = 1. File Explorer opens to "This PC" (drives view) instead of Quick Access. More useful on fresh machines where Quick Access history is empty and irrelevant.
    start-menu-vyprazdnit-piny-win11: ConfigureStartPins = {"pinnedList":[]} applied via registry. Removes all default Start menu tiles (Edge, Teams, Store, Office, Solitaire, etc.) from the Windows 11 Start grid. User starts with an empty, clean Start menu.
    start-menu-zakaz-bing-vyhledavani: DisableSearchBoxSuggestions = 1 in Software\Policies\Microsoft\Windows. Disables web search, Bing suggestions, and online results in Start menu search. Search returns only local apps, files, and settings.
    copilot-zakaz-turnoffwindowscopilot-1: TurnOffWindowsCopilot = 1 in SOFTWARE\Policies\Microsoft\Windows\WindowsCopilot. Disables the Windows Copilot sidebar entirely. Not suitable for most client environments (data privacy, AI usage policies).
    numlock-zapnout-pri-startu-initialkeyboa: InitialKeyboardIndicators = 2 in Default profile. Ensures NumLock is enabled when Windows starts. Standard expectation for users working with numeric data - prevents confusion on data entry.
    accent-barva-na-titulnich-listech-colorp: ColorPrevalence = 1 in Personalize key. Shows the X9.cz accent color (#223B47) on window title bars and borders. Gives all windows a consistent branded appearance.
    onedrive-runonce-klic-je-tady-smazat: REMOVED. The RunOnce key deletion and Explorer namespace CLSID removal were deleted - those registry tweaks prevented a freshly installed OneDrive (e.g. for M365) from launching. OneDrive AppX uninstall in step 01 is intentional; blocking re-launch is not.
    explorer-showrecent-0-showfrequent-0: ShowRecent=0 and ShowFrequent=0 in HKCU\Software\Microsoft\Windows\CurrentVersion\Explorer. Hides Recent files and Frequent folders from Quick Access. Privacy improvement and cleaner File Explorer on fresh deployments.
    explorer-fullpath-1-cabinetstate: FullPath=1 in HKCU\Software\Microsoft\Windows\CurrentVersion\Explorer\CabinetState. Displays the full directory path (e.g. C:\Users\jan\Documents\Projekty) in the File Explorer title bar instead of just the folder name.
#>
param(
    [object]$Config,
    [string]$LogFile,
    [ValidateSet("default","admin","user")]
    [string]$ProfileType = "default"
)

$ErrorActionPreference = "Continue"

function Write-Log {
    param([string]$Message, [string]$Level = "INFO")
    $line = "[$(Get-Date -Format 'HH:mm:ss')] [$Level] $Message"
    Add-Content -Path $LogFile -Value $line -Encoding UTF8
}

# -----------------------------------------------------------------------
# Helper - apply a registry setting to both Default hive and current HKCU
# -----------------------------------------------------------------------
function Grant-HiveWriteAccess {
    param([string]$HivePath)  # full path e.g. "Registry::HKU\DefaultProfile\Software\..."
    # Grants Administrators FullControl on a loaded hive key with restricted ACL.
    try {
        $acl  = Get-Acl -Path $HivePath -ErrorAction Stop
        $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)
        Set-Acl -Path $HivePath -AclObject $acl -ErrorAction Stop
    }
    catch {
        Write-Log "  Grant-HiveWriteAccess failed for $HivePath - $_" -Level WARN
    }
}

function Set-ProfileReg {
    param(
        [string]$SubKey,   # relative to HKCU (e.g. "Software\Microsoft\...")
        [string]$Name,
        $Value,
        [string]$Type = "DWord"
    )

    # Apply to loaded Default hive
    $defPath = "Registry::HKU\DefaultProfile\$SubKey"
    try {
        if (-not (Test-Path $defPath)) {
            New-Item -Path $defPath -Force -ErrorAction Stop | Out-Null
        }
        Set-ItemProperty -Path $defPath -Name $Name -Value $Value -Type $Type -Force -ErrorAction Stop
    }
    catch {
        # Retry after granting write access to parent key
        try {
            $parentPath = $defPath -replace '\\[^\\]+$', ''
            if (Test-Path $parentPath) { Grant-HiveWriteAccess -HivePath $parentPath }
            if (-not (Test-Path $defPath)) {
                New-Item -Path $defPath -Force -ErrorAction Stop | Out-Null
            }
            Set-ItemProperty -Path $defPath -Name $Name -Value $Value -Type $Type -Force -ErrorAction Stop
        }
        catch {
            Write-Log "  DEFAULT HIVE failed $SubKey\$Name - $_" -Level ERROR
        }
    }

    # Apply to current user as well
    $hkcuPath = "HKCU:\$SubKey"
    try {
        if (-not (Test-Path $hkcuPath)) {
            New-Item -Path $hkcuPath -Force -ErrorAction Stop | Out-Null
        }
        Set-ItemProperty -Path $hkcuPath -Name $Name -Value $Value -Type $Type -Force -ErrorAction Stop
        Write-Log "  SET $SubKey\$Name = $Value" -Level OK
    }
    catch {
        Write-Log "  HKCU failed $SubKey\$Name - $_" -Level ERROR
    }
}

function Remove-ProfileReg {
    param([string]$SubKey, [string]$Name)

    $defPath = "Registry::HKU\DefaultProfile\$SubKey"
    try {
        if (Test-Path $defPath) {
            Remove-ItemProperty -Path $defPath -Name $Name -Force -ErrorAction SilentlyContinue
        }
    }
    catch { }

    $hkcuPath = "HKCU:\$SubKey"
    try {
        if (Test-Path $hkcuPath) {
            Remove-ItemProperty -Path $hkcuPath -Name $Name -Force -ErrorAction SilentlyContinue
            Write-Log "  REMOVED $SubKey\$Name" -Level OK
        }
    }
    catch {
        Write-Log "  FAILED removing $SubKey\$Name - $_" -Level ERROR
    }
}

# -----------------------------------------------------------------------
# Load Default profile hive
# -----------------------------------------------------------------------
$hivePath = "C:\Users\Default\NTUSER.DAT"
$hiveKey  = "DefaultProfile"

Write-Log "Loading Default hive: $hivePath" -Level INFO

# Unload first in case previous run left it mounted
& reg unload "HKU\$hiveKey" 2>&1 | Out-Null

$loadResult = & reg load "HKU\$hiveKey" $hivePath 2>&1
if ($LASTEXITCODE -ne 0) {
    Write-Log "Failed to load Default hive: $loadResult" -Level ERROR
    exit 1
}
Write-Log "Default hive loaded" -Level OK

try {
    # -----------------------------------------------------------------------
    # Taskbar settings (Win10 + Win11)
    # -----------------------------------------------------------------------
    Write-Log "Applying taskbar settings" -Level STEP

    $tbPath = "Software\Microsoft\Windows\CurrentVersion\Explorer\Advanced"

    # Win11: align taskbar to left (0 = left, 1 = center)
    Set-ProfileReg -SubKey $tbPath -Name "TaskbarAl" -Value 0

    # Hide Search box / button - Win10/11 (0 = hidden, 1 = icon, 2 = full box)
    # Note: Win11 uses Search subkey, Win10 uses Explorer\Advanced - set both
    Set-ProfileReg -SubKey "Software\Microsoft\Windows\CurrentVersion\Search" `
                   -Name "SearchboxTaskbarMode" -Value 0
    Set-ProfileReg -SubKey $tbPath -Name "SearchboxTaskbarMode" -Value 0

    # Hide Task View button
    Set-ProfileReg -SubKey $tbPath -Name "ShowTaskViewButton" -Value 0

    # Hide Widgets button
    Set-ProfileReg -SubKey $tbPath -Name "TaskbarDa" -Value 0

    # Hide Chat / Teams button
    Set-ProfileReg -SubKey $tbPath -Name "TaskbarMn" -Value 0

    # Hide Copilot button
    Set-ProfileReg -SubKey $tbPath -Name "ShowCopilotButton" -Value 0

    # Show file extensions in Explorer
    Set-ProfileReg -SubKey $tbPath -Name "HideFileExt" -Value 0

    # Open Explorer to This PC instead of Quick Access
    Set-ProfileReg -SubKey $tbPath -Name "LaunchTo" -Value 1

    # -----------------------------------------------------------------------
    # System tray - show all icons
    # -----------------------------------------------------------------------
    # EnableAutoTray = 0 works on Win10; Win11 ignores it but set anyway
    Set-ProfileReg -SubKey "Software\Microsoft\Windows\CurrentVersion\Explorer" `
                   -Name "EnableAutoTray" -Value 0

    # Win11 workaround: clear cached tray icon streams so all icons appear on next login
    # Windows rebuilds the streams with all icons visible when no cache exists
    $trayNotifyKey = "HKCU:\Software\Classes\Local Settings\Software\Microsoft\Windows\CurrentVersion\TrayNotify"
    if (Test-Path $trayNotifyKey) {
        Remove-ItemProperty -Path $trayNotifyKey -Name "IconStreams"     -Force -ErrorAction SilentlyContinue
        Remove-ItemProperty -Path $trayNotifyKey -Name "PastIconsStream" -Force -ErrorAction SilentlyContinue
        Write-Log "  Cleared TrayNotify icon streams (Win11 systray workaround)" -Level OK
    }

    # Also clear in Default hive so new users start with clean state
    $defTrayKey = "Registry::HKU\DefaultProfile\Software\Classes\Local Settings\Software\Microsoft\Windows\CurrentVersion\TrayNotify"
    if (Test-Path $defTrayKey) {
        Remove-ItemProperty -Path $defTrayKey -Name "IconStreams"     -Force -ErrorAction SilentlyContinue
        Remove-ItemProperty -Path $defTrayKey -Name "PastIconsStream" -Force -ErrorAction SilentlyContinue
        Write-Log "  Cleared TrayNotify icon streams in Default hive" -Level OK
    }

    # -----------------------------------------------------------------------
    # Desktop icons - show This PC
    # -----------------------------------------------------------------------
    # CLSID {20D04FE0-3AEA-1069-A2D8-08002B30309D} = This PC / Computer
    Set-ProfileReg -SubKey "Software\Microsoft\Windows\CurrentVersion\Explorer\HideDesktopIcons\NewStartPanel" `
                   -Name "{20D04FE0-3AEA-1069-A2D8-08002B30309D}" -Value 0

    # -----------------------------------------------------------------------
    # Start menu settings
    # -----------------------------------------------------------------------
    Write-Log "Applying Start menu settings" -Level STEP

    # Disable Bing search suggestions in Start menu
    Set-ProfileReg -SubKey "Software\Policies\Microsoft\Windows\Explorer" `
                   -Name "DisableSearchBoxSuggestions" -Value 1

    # Win11: empty Start menu pins
    Set-ProfileReg -SubKey "Software\Microsoft\Windows\CurrentVersion\Start" `
                   -Name "ConfigureStartPins" `
                   -Value '{"pinnedList":[]}' `
                   -Type "String"

    # Hide "Recently added" apps in Start menu
    Set-ProfileReg -SubKey "Software\Microsoft\Windows\CurrentVersion\Explorer\Advanced" `
                   -Name "Start_TrackProgs" -Value 0

    # Hide recently opened files/docs from Start menu
    Set-ProfileReg -SubKey "Software\Microsoft\Windows\CurrentVersion\Explorer\Advanced" `
                   -Name "Start_TrackDocs" -Value 0

    # -----------------------------------------------------------------------
    # Copilot - disable
    # -----------------------------------------------------------------------
    Set-ProfileReg -SubKey "Software\Policies\Microsoft\Windows\WindowsCopilot" `
                   -Name "TurnOffWindowsCopilot" -Value 1

    # -----------------------------------------------------------------------
    # GameDVR - disable
    # -----------------------------------------------------------------------
    Set-ProfileReg -SubKey "System\GameConfigStore" `
                   -Name "GameDVR_Enabled" -Value 0

    Set-ProfileReg -SubKey "Software\Microsoft\Windows\CurrentVersion\GameDVR" `
                   -Name "AppCaptureEnabled" -Value 0

    # -----------------------------------------------------------------------
    # Num Lock on startup
    # -----------------------------------------------------------------------
    Set-ProfileReg -SubKey "Control Panel\Keyboard" `
                   -Name "InitialKeyboardIndicators" -Value 2 -Type "String"

    # -----------------------------------------------------------------------
    # Accent color on title bars
    # -----------------------------------------------------------------------
    Set-ProfileReg -SubKey "Software\Microsoft\Windows\DWM" `
                   -Name "ColorPrevalence" -Value 1

    # -----------------------------------------------------------------------
    # Taskbar pinned apps layout (Win10/11)
    # ProfileType: default = empty, admin = Explorer+PS+Edge, user = Explorer+Edge
    # Note: TaskbarLayoutModification.xml locks the taskbar temporarily.
    # UnlockStartLayout scheduled task removes the lock 5 min after first boot
    # so users can then customize pins freely.
    # Win11 24H2+ may require ProvisionedLayoutModification.xml format instead.
    # -----------------------------------------------------------------------
    Write-Log "Writing taskbar layout (ProfileType=$ProfileType)" -Level INFO

    $taskbarLayoutDir = "C:\Users\Default\AppData\Local\Microsoft\Windows\Shell"
    if (-not (Test-Path $taskbarLayoutDir)) {
        New-Item -ItemType Directory -Path $taskbarLayoutDir -Force | Out-Null
    }

    # Build pin list based on profile type.
    # Paths resolve relative to the new user at first login.
    # Missing shortcuts are silently skipped by Windows.
    $pinList = switch ($ProfileType) {
        "admin" {
@'
        <taskbar:DesktopApp DesktopApplicationLinkPath="%APPDATA%\Microsoft\Windows\Start Menu\Programs\System Tools\File Explorer.lnk"/>
        <taskbar:DesktopApp DesktopApplicationLinkPath="%APPDATA%\Microsoft\Windows\Start Menu\Programs\Windows PowerShell\Windows PowerShell.lnk"/>
        <taskbar:DesktopApp DesktopApplicationLinkPath="%PROGRAMDATA%\Microsoft\Windows\Start Menu\Programs\Microsoft Edge.lnk"/>
'@
        }
        "user" {
@'
        <taskbar:DesktopApp DesktopApplicationLinkPath="%APPDATA%\Microsoft\Windows\Start Menu\Programs\System Tools\File Explorer.lnk"/>
        <taskbar:DesktopApp DesktopApplicationLinkPath="%PROGRAMDATA%\Microsoft\Windows\Start Menu\Programs\Microsoft Edge.lnk"/>
'@
        }
        default { "" }   # empty = clean slate
    }

    $taskbarLayoutXml = @"
<?xml version="1.0" encoding="utf-8"?>
<LayoutModificationTemplate
    xmlns="http://schemas.microsoft.com/Start/2014/LayoutModification"
    xmlns:defaultlayout="http://schemas.microsoft.com/Start/2014/FullDefaultLayout"
    xmlns:start="http://schemas.microsoft.com/Start/2014/StartLayout"
    xmlns:taskbar="http://schemas.microsoft.com/Start/2014/TaskbarLayout"
    Version="1">
  <CustomTaskbarLayoutCollection PinListPlacement="Replace">
    <defaultlayout:TaskbarLayout>
      <taskbar:TaskbarPinList>
$pinList
      </taskbar:TaskbarPinList>
    </defaultlayout:TaskbarLayout>
  </CustomTaskbarLayoutCollection>
</LayoutModificationTemplate>
"@
    $taskbarLayoutXml | Set-Content -Path "$taskbarLayoutDir\LayoutModification.xml" -Encoding UTF8 -Force
    Write-Log "  Taskbar LayoutModification.xml written (profile: $ProfileType)" -Level OK

}
finally {
    # -----------------------------------------------------------------------
    # Unload Default hive - always, even on error
    # -----------------------------------------------------------------------
    Write-Log "Unloading Default hive" -Level INFO
    [GC]::Collect()
    [GC]::WaitForPendingFinalizers()
    Start-Sleep -Milliseconds 500

    $unloadResult = & reg unload "HKU\$hiveKey" 2>&1
    if ($LASTEXITCODE -eq 0) {
        Write-Log "Default hive unloaded" -Level OK
    } else {
        Write-Log "Failed to unload Default hive: $unloadResult" -Level ERROR
    }
}

# -----------------------------------------------------------------------
# Restart Explorer to apply taskbar/tray changes to current session
# -----------------------------------------------------------------------
Write-Log "Restarting Explorer to apply taskbar changes" -Level INFO
try {
    Stop-Process -Name explorer -Force -ErrorAction SilentlyContinue
    Start-Sleep -Seconds 2
    Start-Process explorer
    Write-Log "Explorer restarted" -Level OK
}
catch {
    Write-Log "Explorer restart failed (non-fatal): $_" -Level WARN
}

Write-Log "Step 4 complete" -Level OK


Tento soubor přepíšu celý — je potřeba přidat `Get-Feature`, obalit 3 bloky, a přidat chybějící kód pro `explorerTweaks` (ShowRecent, ShowFrequent, FullPath):


Write

<#
.SYNOPSIS
    Applies registry settings to the Default User profile and the current logged-in user.

.DESCRIPTION
    Loads C:\Users\Default\NTUSER.DAT as a temporary hive (HKU\DefaultProfile), applies
    all settings, then unloads it. Every new user account created on this machine inherits
    these settings on first logon. The same settings are applied directly to the current
    user's HKCU. Does NOT block OneDrive re-launch - the Explorer namespace CLSID and RunOnce entries have been removed.

.ITEMS
    taskbar-zarovnat-vlevo-taskbaral-0: TaskbarAl = 0 in Explorer\Advanced. Windows 11 default is center-aligned (TaskbarAl = 1). Left alignment matches Windows 10 muscle memory and is strongly preferred by business users transitioning from Win10.
    taskbar-skryt-search-copilot-task-view-w: Hides Search box (SearchboxTaskbarMode=0), Copilot button (ShowCopilotButton=0), Task View (ShowTaskViewButton=0), Widgets (TaskbarDa=0), Chat/Teams (TaskbarMn=0). Reduces taskbar clutter to just pinned apps and running processes.
    taskbar-zobrazit-vsechny-ikonky-v-tray-s: Registers scheduled task that sets EnableAutoTray=0 on logon (repeat every 1 min). Windows 11 periodically re-hides tray icons - this task forces all icons visible so users can see VPN status, antivirus, backup, etc.
    taskbar-vyprazdnit-pinlist-taskbarlayout: Deploys TaskbarLayoutModification.xml. ProfileType=default: empty pins (clean slate). ProfileType=admin: Explorer+PowerShell+Edge. ProfileType=user: Explorer+Edge. Lock is removed by UnlockStartLayout task 5 min after first boot so users can customize.
    explorer-zobrazovat-pripony-souboru-hide: HideFileExt = 0 in Explorer\Advanced. Shows file extensions (.docx, .exe, .pdf, .ps1) in File Explorer. Essential for recognizing file types, avoiding phishing (fake .pdf.exe), and general IT work.
    explorer-otevrit-na-this-pc-launchto-1: LaunchTo = 1. File Explorer opens to "This PC" (drives view) instead of Quick Access. More useful on fresh machines where Quick Access history is empty and irrelevant.
    start-menu-vyprazdnit-piny-win11: ConfigureStartPins = {"pinnedList":[]} applied via registry. Removes all default Start menu tiles (Edge, Teams, Store, Office, Solitaire, etc.) from the Windows 11 Start grid. User starts with an empty, clean Start menu.
    start-menu-zakaz-bing-vyhledavani: DisableSearchBoxSuggestions = 1 in Software\Policies\Microsoft\Windows. Disables web search, Bing suggestions, and online results in Start menu search. Search returns only local apps, files, and settings.
    copilot-zakaz-turnoffwindowscopilot-1: TurnOffWindowsCopilot = 1 in SOFTWARE\Policies\Microsoft\Windows\WindowsCopilot. Disables the Windows Copilot sidebar entirely. Not suitable for most client environments (data privacy, AI usage policies).
    numlock-zapnout-pri-startu-initialkeyboa: InitialKeyboardIndicators = 2 in Default profile. Ensures NumLock is enabled when Windows starts. Standard expectation for users working with numeric data - prevents confusion on data entry.
    accent-barva-na-titulnich-listech-colorp: ColorPrevalence = 1 in Personalize key. Shows the X9.cz accent color (#223B47) on window title bars and borders. Gives all windows a consistent branded appearance.
    onedrive-runonce-klic-je-tady-smazat: REMOVED. The RunOnce key deletion and Explorer namespace CLSID removal were deleted - those registry tweaks prevented a freshly installed OneDrive (e.g. for M365) from launching. OneDrive AppX uninstall in step 01 is intentional; blocking re-launch is not.
    explorer-showrecent-0-showfrequent-0: ShowRecent=0 and ShowFrequent=0 in HKCU\Software\Microsoft\Windows\CurrentVersion\Explorer. Hides Recent files and Frequent folders from Quick Access. Privacy improvement and cleaner File Explorer on fresh deployments.
    explorer-fullpath-1-cabinetstate: FullPath=1 in HKCU\Software\Microsoft\Windows\CurrentVersion\Explorer\CabinetState. Displays the full directory path (e.g. C:\Users\jan\Documents\Projekty) in the File Explorer title bar instead of just the folder name.
#>
param(
    [object]$Config,
    [string]$LogFile,
    [ValidateSet("default","admin","user")]
    [string]$ProfileType = "default"
)

$ErrorActionPreference = "Continue"

function Write-Log {
    param([string]$Message, [string]$Level = "INFO")
    $line = "[$(Get-Date -Format 'HH:mm:ss')] [$Level] $Message"
    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 }
}

# -----------------------------------------------------------------------
# Helper - apply a registry setting to both Default hive and current HKCU
# -----------------------------------------------------------------------
function Grant-HiveWriteAccess {
    param([string]$HivePath)  # full path e.g. "Registry::HKU\DefaultProfile\Software\..."
    # Grants Administrators FullControl on a loaded hive key with restricted ACL.
    try {
        $acl  = Get-Acl -Path $HivePath -ErrorAction Stop
        $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)
        Set-Acl -Path $HivePath -AclObject $acl -ErrorAction Stop
    }
    catch {
        Write-Log "  Grant-HiveWriteAccess failed for $HivePath - $_" -Level WARN
    }
}

function Set-ProfileReg {
    param(
        [string]$SubKey,   # relative to HKCU (e.g. "Software\Microsoft\...")
        [string]$Name,
        $Value,
        [string]$Type = "DWord"
    )

    # Apply to loaded Default hive
    $defPath = "Registry::HKU\DefaultProfile\$SubKey"
    try {
        if (-not (Test-Path $defPath)) {
            New-Item -Path $defPath -Force -ErrorAction Stop | Out-Null
        }
        Set-ItemProperty -Path $defPath -Name $Name -Value $Value -Type $Type -Force -ErrorAction Stop
    }
    catch {
        # Retry after granting write access to parent key
        try {
            $parentPath = $defPath -replace '\\[^\\]+$', ''
            if (Test-Path $parentPath) { Grant-HiveWriteAccess -HivePath $parentPath }
            if (-not (Test-Path $defPath)) {
                New-Item -Path $defPath -Force -ErrorAction Stop | Out-Null
            }
            Set-ItemProperty -Path $defPath -Name $Name -Value $Value -Type $Type -Force -ErrorAction Stop
        }
        catch {
            Write-Log "  DEFAULT HIVE failed $SubKey\$Name - $_" -Level ERROR
        }
    }

    # Apply to current user as well
    $hkcuPath = "HKCU:\$SubKey"
    try {
        if (-not (Test-Path $hkcuPath)) {
            New-Item -Path $hkcuPath -Force -ErrorAction Stop | Out-Null
        }
        Set-ItemProperty -Path $hkcuPath -Name $Name -Value $Value -Type $Type -Force -ErrorAction Stop
        Write-Log "  SET $SubKey\$Name = $Value" -Level OK
    }
    catch {
        Write-Log "  HKCU failed $SubKey\$Name - $_" -Level ERROR
    }
}

function Remove-ProfileReg {
    param([string]$SubKey, [string]$Name)

    $defPath = "Registry::HKU\DefaultProfile\$SubKey"
    try {
        if (Test-Path $defPath) {
            Remove-ItemProperty -Path $defPath -Name $Name -Force -ErrorAction SilentlyContinue
        }
    }
    catch { }

    $hkcuPath = "HKCU:\$SubKey"
    try {
        if (Test-Path $hkcuPath) {
            Remove-ItemProperty -Path $hkcuPath -Name $Name -Force -ErrorAction SilentlyContinue
            Write-Log "  REMOVED $SubKey\$Name" -Level OK
        }
    }
    catch {
        Write-Log "  FAILED removing $SubKey\$Name - $_" -Level ERROR
    }
}

# -----------------------------------------------------------------------
# Load Default profile hive
# -----------------------------------------------------------------------
$hivePath = "C:\Users\Default\NTUSER.DAT"
$hiveKey  = "DefaultProfile"

Write-Log "Loading Default hive: $hivePath" -Level INFO

# Unload first in case previous run left it mounted
& reg unload "HKU\$hiveKey" 2>&1 | Out-Null

$loadResult = & reg load "HKU\$hiveKey" $hivePath 2>&1
if ($LASTEXITCODE -ne 0) {
    Write-Log "Failed to load Default hive: $loadResult" -Level ERROR
    exit 1
}
Write-Log "Default hive loaded" -Level OK

try {
    # -----------------------------------------------------------------------
    # Taskbar tweaks (alignment, buttons, tray, layout XML)
    # -----------------------------------------------------------------------
    if (Get-Feature $Config "defaultProfile" "taskbarTweaks") {
        Write-Log "Applying taskbar tweaks" -Level STEP

        $tbPath = "Software\Microsoft\Windows\CurrentVersion\Explorer\Advanced"

        # Win11: align taskbar to left (0 = left, 1 = center)
        Set-ProfileReg -SubKey $tbPath -Name "TaskbarAl" -Value 0

        # Hide Search box / button - Win10/11 (0 = hidden, 1 = icon, 2 = full box)
        # Note: Win11 uses Search subkey, Win10 uses Explorer\Advanced - set both
        Set-ProfileReg -SubKey "Software\Microsoft\Windows\CurrentVersion\Search" `
                       -Name "SearchboxTaskbarMode" -Value 0
        Set-ProfileReg -SubKey $tbPath -Name "SearchboxTaskbarMode" -Value 0

        # Hide Task View button
        Set-ProfileReg -SubKey $tbPath -Name "ShowTaskViewButton" -Value 0

        # Hide Widgets button
        Set-ProfileReg -SubKey $tbPath -Name "TaskbarDa" -Value 0

        # Hide Chat / Teams button
        Set-ProfileReg -SubKey $tbPath -Name "TaskbarMn" -Value 0

        # Hide Copilot button
        Set-ProfileReg -SubKey $tbPath -Name "ShowCopilotButton" -Value 0

        # Show all tray icons
        # EnableAutoTray = 0 works on Win10; Win11 ignores it but set anyway
        Set-ProfileReg -SubKey "Software\Microsoft\Windows\CurrentVersion\Explorer" `
                       -Name "EnableAutoTray" -Value 0

        # Win11 workaround: clear cached tray icon streams so all icons appear on next login
        $trayNotifyKey = "HKCU:\Software\Classes\Local Settings\Software\Microsoft\Windows\CurrentVersion\TrayNotify"
        if (Test-Path $trayNotifyKey) {
            Remove-ItemProperty -Path $trayNotifyKey -Name "IconStreams"     -Force -ErrorAction SilentlyContinue
            Remove-ItemProperty -Path $trayNotifyKey -Name "PastIconsStream" -Force -ErrorAction SilentlyContinue
            Write-Log "  Cleared TrayNotify icon streams (Win11 systray workaround)" -Level OK
        }
        $defTrayKey = "Registry::HKU\DefaultProfile\Software\Classes\Local Settings\Software\Microsoft\Windows\CurrentVersion\TrayNotify"
        if (Test-Path $defTrayKey) {
            Remove-ItemProperty -Path $defTrayKey -Name "IconStreams"     -Force -ErrorAction SilentlyContinue
            Remove-ItemProperty -Path $defTrayKey -Name "PastIconsStream" -Force -ErrorAction SilentlyContinue
            Write-Log "  Cleared TrayNotify icon streams in Default hive" -Level OK
        }

        # Desktop icons - show This PC
        # CLSID {20D04FE0-3AEA-1069-A2D8-08002B30309D} = This PC / Computer
        Set-ProfileReg -SubKey "Software\Microsoft\Windows\CurrentVersion\Explorer\HideDesktopIcons\NewStartPanel" `
                       -Name "{20D04FE0-3AEA-1069-A2D8-08002B30309D}" -Value 0

        # Taskbar pinned apps layout (Win10/11)
        # ProfileType: default = empty, admin = Explorer+PS+Edge, user = Explorer+Edge
        # Note: TaskbarLayoutModification.xml locks the taskbar temporarily.
        # UnlockStartLayout scheduled task removes the lock 5 min after first boot
        # so users can then customize pins freely.
        # Win11 24H2+ may require ProvisionedLayoutModification.xml format instead.
        Write-Log "  Writing taskbar layout (ProfileType=$ProfileType)" -Level INFO

        $taskbarLayoutDir = "C:\Users\Default\AppData\Local\Microsoft\Windows\Shell"
        if (-not (Test-Path $taskbarLayoutDir)) {
            New-Item -ItemType Directory -Path $taskbarLayoutDir -Force | Out-Null
        }

        $pinList = switch ($ProfileType) {
            "admin" {
@'
        <taskbar:DesktopApp DesktopApplicationLinkPath="%APPDATA%\Microsoft\Windows\Start Menu\Programs\System Tools\File Explorer.lnk"/>
        <taskbar:DesktopApp DesktopApplicationLinkPath="%APPDATA%\Microsoft\Windows\Start Menu\Programs\Windows PowerShell\Windows PowerShell.lnk"/>
        <taskbar:DesktopApp DesktopApplicationLinkPath="%PROGRAMDATA%\Microsoft\Windows\Start Menu\Programs\Microsoft Edge.lnk"/>
'@
            }
            "user" {
@'
        <taskbar:DesktopApp DesktopApplicationLinkPath="%APPDATA%\Microsoft\Windows\Start Menu\Programs\System Tools\File Explorer.lnk"/>
        <taskbar:DesktopApp DesktopApplicationLinkPath="%PROGRAMDATA%\Microsoft\Windows\Start Menu\Programs\Microsoft Edge.lnk"/>
'@
            }
            default { "" }   # empty = clean slate
        }

        $taskbarLayoutXml = @"
<?xml version="1.0" encoding="utf-8"?>
<LayoutModificationTemplate
    xmlns="http://schemas.microsoft.com/Start/2014/LayoutModification"
    xmlns:defaultlayout="http://schemas.microsoft.com/Start/2014/FullDefaultLayout"
    xmlns:start="http://schemas.microsoft.com/Start/2014/StartLayout"
    xmlns:taskbar="http://schemas.microsoft.com/Start/2014/TaskbarLayout"
    Version="1">
  <CustomTaskbarLayoutCollection PinListPlacement="Replace">
    <defaultlayout:TaskbarLayout>
      <taskbar:TaskbarPinList>
$pinList
      </taskbar:TaskbarPinList>
    </defaultlayout:TaskbarLayout>
  </CustomTaskbarLayoutCollection>
</LayoutModificationTemplate>
"@
        $taskbarLayoutXml | Set-Content -Path "$taskbarLayoutDir\LayoutModification.xml" -Encoding UTF8 -Force
        Write-Log "  Taskbar LayoutModification.xml written (profile: $ProfileType)" -Level OK

        # NumLock on startup
        Set-ProfileReg -SubKey "Control Panel\Keyboard" `
                       -Name "InitialKeyboardIndicators" -Value 2 -Type "String"

        # Accent color on title bars
        Set-ProfileReg -SubKey "Software\Microsoft\Windows\DWM" `
                       -Name "ColorPrevalence" -Value 1
    } else {
        Write-Log "taskbarTweaks feature disabled - skipping" -Level INFO
    }

    # -----------------------------------------------------------------------
    # Start menu tweaks (pins, Bing, Copilot, GameDVR)
    # -----------------------------------------------------------------------
    if (Get-Feature $Config "defaultProfile" "startMenuTweaks") {
        Write-Log "Applying Start menu tweaks" -Level STEP

        # Disable Bing search suggestions in Start menu
        Set-ProfileReg -SubKey "Software\Policies\Microsoft\Windows\Explorer" `
                       -Name "DisableSearchBoxSuggestions" -Value 1

        # Win11: empty Start menu pins
        Set-ProfileReg -SubKey "Software\Microsoft\Windows\CurrentVersion\Start" `
                       -Name "ConfigureStartPins" `
                       -Value '{"pinnedList":[]}' `
                       -Type "String"

        # Hide "Recently added" apps in Start menu
        Set-ProfileReg -SubKey "Software\Microsoft\Windows\CurrentVersion\Explorer\Advanced" `
                       -Name "Start_TrackProgs" -Value 0

        # Hide recently opened files/docs from Start menu
        Set-ProfileReg -SubKey "Software\Microsoft\Windows\CurrentVersion\Explorer\Advanced" `
                       -Name "Start_TrackDocs" -Value 0

        # Disable Copilot
        Set-ProfileReg -SubKey "Software\Policies\Microsoft\Windows\WindowsCopilot" `
                       -Name "TurnOffWindowsCopilot" -Value 1

        # Disable GameDVR
        Set-ProfileReg -SubKey "System\GameConfigStore" `
                       -Name "GameDVR_Enabled" -Value 0
        Set-ProfileReg -SubKey "Software\Microsoft\Windows\CurrentVersion\GameDVR" `
                       -Name "AppCaptureEnabled" -Value 0
    } else {
        Write-Log "startMenuTweaks feature disabled - skipping" -Level INFO
    }

    # -----------------------------------------------------------------------
    # Explorer tweaks (file extensions, LaunchTo, ShowRecent, FullPath)
    # -----------------------------------------------------------------------
    if (Get-Feature $Config "defaultProfile" "explorerTweaks") {
        Write-Log "Applying Explorer tweaks" -Level STEP

        $advPath = "Software\Microsoft\Windows\CurrentVersion\Explorer\Advanced"

        # Show file extensions in Explorer
        Set-ProfileReg -SubKey $advPath -Name "HideFileExt" -Value 0

        # Open Explorer to This PC instead of Quick Access
        Set-ProfileReg -SubKey $advPath -Name "LaunchTo" -Value 1

        # Hide Recent files from Quick Access
        Set-ProfileReg -SubKey "Software\Microsoft\Windows\CurrentVersion\Explorer" `
                       -Name "ShowRecent" -Value 0

        # Hide Frequent folders from Quick Access
        Set-ProfileReg -SubKey "Software\Microsoft\Windows\CurrentVersion\Explorer" `
                       -Name "ShowFrequent" -Value 0

        # Show full path in Explorer title bar
        Set-ProfileReg -SubKey "Software\Microsoft\Windows\CurrentVersion\Explorer\CabinetState" `
                       -Name "FullPath" -Value 1
    } else {
        Write-Log "explorerTweaks feature disabled - skipping" -Level INFO
    }
}
finally {
    # -----------------------------------------------------------------------
    # Unload Default hive - always, even on error
    # -----------------------------------------------------------------------
    Write-Log "Unloading Default hive" -Level INFO
    [GC]::Collect()
    [GC]::WaitForPendingFinalizers()
    Start-Sleep -Milliseconds 500

    $unloadResult = & reg unload "HKU\$hiveKey" 2>&1
    if ($LASTEXITCODE -eq 0) {
        Write-Log "Default hive unloaded" -Level OK
    } else {
        Write-Log "Failed to unload Default hive: $unloadResult" -Level ERROR
    }
}

# -----------------------------------------------------------------------
# Restart Explorer to apply taskbar/tray changes to current session
# -----------------------------------------------------------------------
Write-Log "Restarting Explorer to apply taskbar changes" -Level INFO
try {
    Stop-Process -Name explorer -Force -ErrorAction SilentlyContinue
    Start-Sleep -Seconds 2
    Start-Process explorer
    Write-Log "Explorer restarted" -Level OK
}
catch {
    Write-Log "Explorer restart failed (non-fatal): $_" -Level WARN
}

Write-Log "Step 4 complete" -Level OK