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	    $null = New-Item -ItemType Directory -Force -Path (Split-Path $LogFile -Parent) -ErrorAction SilentlyContinue
40	    Add-Content -Path $LogFile -Value $line -Encoding UTF8
41	}
42
43	function Get-Feature {
44	    param([object]$Cfg, [string]$StepID, [string]$FeatureID, [bool]$Default = $true)
45	    try {
46	        if ($null -eq $Cfg) { return $Default }
47	        $stepFeatures = $Cfg.features.$StepID
48	        if ($null -eq $stepFeatures) { return $Default }
49	        $val = $stepFeatures.$FeatureID
50	        if ($null -eq $val) { return $Default }
51	        return [bool]$val
52	    } catch { return $Default }
53	}
54
55	# -----------------------------------------------------------------------
56	# Helper - apply a registry setting to both Default hive and current HKCU
57	# -----------------------------------------------------------------------
58	function Grant-HiveWriteAccess {
59	    param([string]$HivePath)  # full path e.g. "Registry::HKU\DefaultProfile\Software\..."
60	    # Grants Administrators FullControl on a loaded hive key with restricted ACL.
61	    try {
62	        $acl  = Get-Acl -Path $HivePath -ErrorAction Stop
63	        $rule = New-Object System.Security.AccessControl.RegistryAccessRule(
64	            "BUILTIN\Administrators",
65	            [System.Security.AccessControl.RegistryRights]::FullControl,
66	            [System.Security.AccessControl.InheritanceFlags]"ContainerInherit,ObjectInherit",
67	            [System.Security.AccessControl.PropagationFlags]::None,
68	            [System.Security.AccessControl.AccessControlType]::Allow
69	        )
70	        $acl.SetAccessRule($rule)
71	        Set-Acl -Path $HivePath -AclObject $acl -ErrorAction Stop
72	    }
73	    catch {
74	        Write-Log "  Grant-HiveWriteAccess failed for $HivePath - $_" -Level WARN
75	    }
76	}
77
78	function Set-ProfileReg {
79	    param(
80	        [string]$SubKey,   # relative to HKCU (e.g. "Software\Microsoft\...")
81	        [string]$Name,
82	        $Value,
83	        [string]$Type = "DWord"
84	    )
85
86	    # Apply to loaded Default hive
87	    $defPath = "Registry::HKU\DefaultProfile\$SubKey"
88	    try {
89	        if (-not (Test-Path $defPath)) {
90	            New-Item -Path $defPath -Force -ErrorAction Stop | Out-Null
91	        }
92	        Set-ItemProperty -Path $defPath -Name $Name -Value $Value -Type $Type -Force -ErrorAction Stop
93	    }
94	    catch {
95	        # Retry after granting write access to parent key
96	        try {
97	            $parentPath = $defPath -replace '\\[^\\]+$', ''
98	            if (Test-Path $parentPath) { Grant-HiveWriteAccess -HivePath $parentPath }
99	            if (-not (Test-Path $defPath)) {
100	                New-Item -Path $defPath -Force -ErrorAction Stop | Out-Null
101	            }
102	            Set-ItemProperty -Path $defPath -Name $Name -Value $Value -Type $Type -Force -ErrorAction Stop
103	        }
104	        catch {
105	            Write-Log "  DEFAULT HIVE failed $SubKey\$Name - $_" -Level ERROR
106	        }
107	    }
108
109	    # Apply to current user as well
110	    $hkcuPath = "HKCU:\$SubKey"
111	    try {
112	        if (-not (Test-Path $hkcuPath)) {
113	            New-Item -Path $hkcuPath -Force -ErrorAction Stop | Out-Null
114	        }
115	        Set-ItemProperty -Path $hkcuPath -Name $Name -Value $Value -Type $Type -Force -ErrorAction Stop
116	        Write-Log "  SET $SubKey\$Name = $Value" -Level OK
117	    }
118	    catch {
119	        Write-Log "  HKCU failed $SubKey\$Name - $_" -Level ERROR
120	    }
121	}
122
123	function Remove-ProfileReg {
124	    param([string]$SubKey, [string]$Name)
125
126	    $defPath = "Registry::HKU\DefaultProfile\$SubKey"
127	    try {
128	        if (Test-Path $defPath) {
129	            Remove-ItemProperty -Path $defPath -Name $Name -Force -ErrorAction SilentlyContinue
130	        }
131	    }
132	    catch { }
133
134	    $hkcuPath = "HKCU:\$SubKey"
135	    try {
136	        if (Test-Path $hkcuPath) {
137	            Remove-ItemProperty -Path $hkcuPath -Name $Name -Force -ErrorAction SilentlyContinue
138	            Write-Log "  REMOVED $SubKey\$Name" -Level OK
139	        }
140	    }
141	    catch {
142	        Write-Log "  FAILED removing $SubKey\$Name - $_" -Level ERROR
143	    }
144	}
145
146	# -----------------------------------------------------------------------
147	# Load Default profile hive
148	# -----------------------------------------------------------------------
149	$hivePath = "C:\Users\Default\NTUSER.DAT"
150	$hiveKey  = "DefaultProfile"
151
152	Write-Log "Loading Default hive: $hivePath" -Level INFO
153
154	# Unload first in case previous run left it mounted
155	& reg unload "HKU\$hiveKey" 2>&1 | Out-Null
156
157	$loadResult = & reg load "HKU\$hiveKey" $hivePath 2>&1
158	if ($LASTEXITCODE -ne 0) {
159	    Write-Log "Failed to load Default hive: $loadResult" -Level ERROR
160	    exit 1
161	}
162	Write-Log "Default hive loaded" -Level OK
163
164	try {
165	    # -----------------------------------------------------------------------
166	    # Taskbar tweaks (alignment, buttons, tray, layout XML)
167	    # -----------------------------------------------------------------------
168	    if (Get-Feature $Config "defaultProfile" "taskbarTweaks") {
169	        Write-Log "Applying taskbar tweaks" -Level STEP
170
171	        $tbPath = "Software\Microsoft\Windows\CurrentVersion\Explorer\Advanced"
172
173	        # Win11: align taskbar to left (0 = left, 1 = center)
174	        Set-ProfileReg -SubKey $tbPath -Name "TaskbarAl" -Value 0
175
176	        # Hide Search box / button - Win10/11 (0 = hidden, 1 = icon, 2 = full box)
177	        # Note: Win11 uses Search subkey, Win10 uses Explorer\Advanced - set both
178	        Set-ProfileReg -SubKey "Software\Microsoft\Windows\CurrentVersion\Search" `
179	                       -Name "SearchboxTaskbarMode" -Value 0
180	        Set-ProfileReg -SubKey $tbPath -Name "SearchboxTaskbarMode" -Value 0
181
182	        # Hide Task View button
183	        Set-ProfileReg -SubKey $tbPath -Name "ShowTaskViewButton" -Value 0
184
185	        # Hide Widgets button
186	        Set-ProfileReg -SubKey $tbPath -Name "TaskbarDa" -Value 0
187
188	        # Hide Chat / Teams button
189	        Set-ProfileReg -SubKey $tbPath -Name "TaskbarMn" -Value 0
190
191	        # Hide Copilot button
192	        Set-ProfileReg -SubKey $tbPath -Name "ShowCopilotButton" -Value 0
193
194	        # Show all tray icons
195	        # EnableAutoTray = 0 works on Win10; Win11 ignores it but set anyway
196	        Set-ProfileReg -SubKey "Software\Microsoft\Windows\CurrentVersion\Explorer" `
197	                       -Name "EnableAutoTray" -Value 0
198
199	        # Win11 workaround: clear cached tray icon streams so all icons appear on next login
200	        $trayNotifyKey = "HKCU:\Software\Classes\Local Settings\Software\Microsoft\Windows\CurrentVersion\TrayNotify"
201	        if (Test-Path $trayNotifyKey) {
202	            Remove-ItemProperty -Path $trayNotifyKey -Name "IconStreams"     -Force -ErrorAction SilentlyContinue
203	            Remove-ItemProperty -Path $trayNotifyKey -Name "PastIconsStream" -Force -ErrorAction SilentlyContinue
204	            Write-Log "  Cleared TrayNotify icon streams (Win11 systray workaround)" -Level OK
205	        }
206	        $defTrayKey = "Registry::HKU\DefaultProfile\Software\Classes\Local Settings\Software\Microsoft\Windows\CurrentVersion\TrayNotify"
207	        if (Test-Path $defTrayKey) {
208	            Remove-ItemProperty -Path $defTrayKey -Name "IconStreams"     -Force -ErrorAction SilentlyContinue
209	            Remove-ItemProperty -Path $defTrayKey -Name "PastIconsStream" -Force -ErrorAction SilentlyContinue
210	            Write-Log "  Cleared TrayNotify icon streams in Default hive" -Level OK
211	        }
212
213	        # Desktop icons - show This PC
214	        # CLSID {20D04FE0-3AEA-1069-A2D8-08002B30309D} = This PC / Computer
215	        Set-ProfileReg -SubKey "Software\Microsoft\Windows\CurrentVersion\Explorer\HideDesktopIcons\NewStartPanel" `
216	                       -Name "{20D04FE0-3AEA-1069-A2D8-08002B30309D}" -Value 0
217
218	        # Taskbar pinned apps layout (Win10/11)
219	        # ProfileType: default = empty, admin = Explorer+PS+Edge, user = Explorer+Edge
220	        # Note: TaskbarLayoutModification.xml locks the taskbar temporarily.
221	        # UnlockStartLayout scheduled task removes the lock 5 min after first boot
222	        # so users can then customize pins freely.
223	        # Win11 24H2+ may require ProvisionedLayoutModification.xml format instead.
224	        Write-Log "  Writing taskbar layout (ProfileType=$ProfileType)" -Level INFO
225
226	        $taskbarLayoutDir = "C:\Users\Default\AppData\Local\Microsoft\Windows\Shell"
227	        if (-not (Test-Path $taskbarLayoutDir)) {
228	            New-Item -ItemType Directory -Path $taskbarLayoutDir -Force | Out-Null
229	        }
230
231	        $pinList = switch ($ProfileType) {
232	            "admin" {
233	@'
234	        <taskbar:DesktopApp DesktopApplicationLinkPath="%APPDATA%\Microsoft\Windows\Start Menu\Programs\System Tools\File Explorer.lnk"/>
235	        <taskbar:DesktopApp DesktopApplicationLinkPath="%APPDATA%\Microsoft\Windows\Start Menu\Programs\Windows PowerShell\Windows PowerShell.lnk"/>
236	        <taskbar:DesktopApp DesktopApplicationLinkPath="%PROGRAMDATA%\Microsoft\Windows\Start Menu\Programs\Microsoft Edge.lnk"/>
237	'@
238	            }
239	            "user" {
240	@'
241	        <taskbar:DesktopApp DesktopApplicationLinkPath="%APPDATA%\Microsoft\Windows\Start Menu\Programs\System Tools\File Explorer.lnk"/>
242	        <taskbar:DesktopApp DesktopApplicationLinkPath="%PROGRAMDATA%\Microsoft\Windows\Start Menu\Programs\Microsoft Edge.lnk"/>
243	'@
244	            }
245	            default {
246	@'
247	        <taskbar:DesktopApp DesktopApplicationLinkPath="%APPDATA%\Microsoft\Windows\Start Menu\Programs\System Tools\File Explorer.lnk"/>
248	        <taskbar:DesktopApp DesktopApplicationLinkPath="%PROGRAMDATA%\Microsoft\Windows\Start Menu\Programs\Microsoft Edge.lnk"/>
249	'@
250	            }  # explicit pins with Replace = no Store, no other defaults
251	        }
252
253	        $taskbarLayoutXml = @"
254	<?xml version="1.0" encoding="utf-8"?>
255	<LayoutModificationTemplate
256	    xmlns="http://schemas.microsoft.com/Start/2014/LayoutModification"
257	    xmlns:defaultlayout="http://schemas.microsoft.com/Start/2014/FullDefaultLayout"
258	    xmlns:start="http://schemas.microsoft.com/Start/2014/StartLayout"
259	    xmlns:taskbar="http://schemas.microsoft.com/Start/2014/TaskbarLayout"
260	    Version="1">
261	  <CustomTaskbarLayoutCollection PinListPlacement="Replace">
262	    <defaultlayout:TaskbarLayout>
263	      <taskbar:TaskbarPinList>
264	$pinList
265	      </taskbar:TaskbarPinList>
266	    </defaultlayout:TaskbarLayout>
267	  </CustomTaskbarLayoutCollection>
268	</LayoutModificationTemplate>
269	"@
270	        $taskbarLayoutXml | Set-Content -Path "$taskbarLayoutDir\LayoutModification.xml" -Encoding UTF8 -Force
271	        Write-Log "  Taskbar LayoutModification.xml written (profile: $ProfileType)" -Level OK
272
273	        # NumLock on startup
274	        Set-ProfileReg -SubKey "Control Panel\Keyboard" `
275	                       -Name "InitialKeyboardIndicators" -Value 2 -Type "String"
276
277	        # Accent color on title bars
278	        Set-ProfileReg -SubKey "Software\Microsoft\Windows\DWM" `
279	                       -Name "ColorPrevalence" -Value 1
280	    } else {
281	        Write-Log "taskbarTweaks feature disabled - skipping" -Level INFO
282	    }
283
284	    # -----------------------------------------------------------------------
285	    # Start menu tweaks (pins, Bing, Copilot, GameDVR)
286	    # -----------------------------------------------------------------------
287	    if (Get-Feature $Config "defaultProfile" "startMenuTweaks") {
288	        Write-Log "Applying Start menu tweaks" -Level STEP
289
290	        # Disable Bing search suggestions in Start menu
291	        Set-ProfileReg -SubKey "Software\Policies\Microsoft\Windows\Explorer" `
292	                       -Name "DisableSearchBoxSuggestions" -Value 1
293
294	        # Win11: empty Start menu pins
295	        Set-ProfileReg -SubKey "Software\Microsoft\Windows\CurrentVersion\Start" `
296	                       -Name "ConfigureStartPins" `
297	                       -Value '{"pinnedList":[]}' `
298	                       -Type "String"
299
300	        # Hide "Recently added" apps in Start menu
301	        Set-ProfileReg -SubKey "Software\Microsoft\Windows\CurrentVersion\Explorer\Advanced" `
302	                       -Name "Start_TrackProgs" -Value 0
303
304	        # Hide recently opened files/docs from Start menu
305	        Set-ProfileReg -SubKey "Software\Microsoft\Windows\CurrentVersion\Explorer\Advanced" `
306	                       -Name "Start_TrackDocs" -Value 0
307
308	        # Disable Copilot
309	        Set-ProfileReg -SubKey "Software\Policies\Microsoft\Windows\WindowsCopilot" `
310	                       -Name "TurnOffWindowsCopilot" -Value 1
311
312	        # Disable GameDVR
313	        Set-ProfileReg -SubKey "System\GameConfigStore" `
314	                       -Name "GameDVR_Enabled" -Value 0
315	        Set-ProfileReg -SubKey "Software\Microsoft\Windows\CurrentVersion\GameDVR" `
316	                       -Name "AppCaptureEnabled" -Value 0
317	    } else {
318	        Write-Log "startMenuTweaks feature disabled - skipping" -Level INFO
319	    }
320
321	    # -----------------------------------------------------------------------
322	    # Explorer tweaks (file extensions, LaunchTo, ShowRecent, FullPath)
323	    # -----------------------------------------------------------------------
324	    if (Get-Feature $Config "defaultProfile" "explorerTweaks") {
325	        Write-Log "Applying Explorer tweaks" -Level STEP
326
327	        $advPath = "Software\Microsoft\Windows\CurrentVersion\Explorer\Advanced"
328
329	        # Show file extensions in Explorer
330	        Set-ProfileReg -SubKey $advPath -Name "HideFileExt" -Value 0
331
332	        # Open Explorer to This PC instead of Quick Access
333	        Set-ProfileReg -SubKey $advPath -Name "LaunchTo" -Value 1
334
335	        # Hide Recent files from Quick Access
336	        Set-ProfileReg -SubKey "Software\Microsoft\Windows\CurrentVersion\Explorer" `
337	                       -Name "ShowRecent" -Value 0
338
339	        # Hide Frequent folders from Quick Access
340	        Set-ProfileReg -SubKey "Software\Microsoft\Windows\CurrentVersion\Explorer" `
341	                       -Name "ShowFrequent" -Value 0
342
343	        # Show full path in Explorer title bar
344	        Set-ProfileReg -SubKey "Software\Microsoft\Windows\CurrentVersion\Explorer\CabinetState" `
345	                       -Name "FullPath" -Value 1
346	    } else {
347	        Write-Log "explorerTweaks feature disabled - skipping" -Level INFO
348	    }
349	}
350	finally {
351	    # -----------------------------------------------------------------------
352	    # Unload Default hive - always, even on error
353	    # -----------------------------------------------------------------------
354	    Write-Log "Unloading Default hive" -Level INFO
355	    [GC]::Collect()
356	    [GC]::WaitForPendingFinalizers()
357	    Start-Sleep -Milliseconds 500
358
359	    $unloadResult = & reg unload "HKU\$hiveKey" 2>&1
360	    if ($LASTEXITCODE -eq 0) {
361	        Write-Log "Default hive unloaded" -Level OK
362	    } else {
363	        Write-Log "Failed to unload Default hive: $unloadResult" -Level ERROR
364	    }
365	}
366
367	# -----------------------------------------------------------------------
368	# Restart Explorer to apply taskbar/tray changes to current session
369	# -----------------------------------------------------------------------
370	Write-Log "Restarting Explorer to apply taskbar changes" -Level INFO
371	try {
372	    Stop-Process -Name explorer -Force -ErrorAction SilentlyContinue
373	    Start-Sleep -Seconds 2
374	    Start-Process explorer
375	    Write-Log "Explorer restarted" -Level OK
376	}
377	catch {
378	    Write-Log "Explorer restart failed (non-fatal): $_" -Level WARN
379	}
380
381	Write-Log "Step 4 complete" -Level OK
382

<#
.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"
    $null = New-Item -ItemType Directory -Force -Path (Split-Path $LogFile -Parent) -ErrorAction SilentlyContinue
    Add-Content -Path $LogFile -Value $line -Encoding UTF8
}

function Get-Feature {
    param([object]$Cfg, [string]$StepID, [string]$FeatureID, [bool]$Default = $true)
    try {
        if ($null -eq $Cfg) { return $Default }
        $stepFeatures = $Cfg.features.$StepID
        if ($null -eq $stepFeatures) { return $Default }
        $val = $stepFeatures.$FeatureID
        if ($null -eq $val) { return $Default }
        return [bool]$val
    } catch { return $Default }
}

# -----------------------------------------------------------------------
# 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 {
@'
        <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"/>
'@
            }  # explicit pins with Replace = no Store, no other defaults
        }

        $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


Dva podezřelé problémy vidím. Přečtu BackInfo.ini a podívám se na accent klíče:


assets/Backinfo/BackInfo.exe
assets/Backinfo/backinfo_W11.ps1
assets/Backinfo/BackInfo.ini


1	;; This INI file should use the following format
2	;;
3	;; [General]
4	;; BackgroundColor = <COLORREF value>       ; The background color to use (default = 0 (black))
5	;; AutoBackground = [0 | 1]                 ; Use background color of current desktop (default = 0)
6	;; BackgroundBitmap = <path to BMP file>    ; Overrides AutoBackground and BackgroundColor values. Loads background bitmap from BMP file
7	;; XOffset = <horizontal offset in pixels>  ; Horizontal offest of the entire text block from the bitmap's center. Can be negative. Default = 0
8	;; YOffset = <vertical offset in pixels>    ; Vertical offest of the entire text block from the bitmap's center. Can be negative. Default = 0
9	;; Output = <file name>                     ; Name of output bitmap file (default = "", use popup message)
10	;; UpdateDesktop = [0 | 1]                  ; Update background desktop bitmap (default = 0)
11	;; ForceDesktopCenter = [0 | 1]             ; Force the desktop to display the bitmap as cenetered (instead of tiled / streched). Default = 1
12
13	;; LineSpacing = <value>                    ; Line spacing (default = 3)
14	;; SuppressErrors = [0 | 1]                 ; If 1, errors are NOT displayed (default = 0)
15	;;
16	;; [LineN]                                  ; Text settings for line N, where N between [1..20]
17	;; Type = [CompName | UserName | SysVer  |  ; Type of information to display on the line
18	;;         SysInfo  | NetInfo  | FileVer |
19	;;         RegValue | FreeText |
20	           UpdateTime | Unused]
21	;;                                          ; CompName - Computer name
22	;;                                          ; UserName - User name
23	;;                                          ; SysVer   - Operating system version
24	;;                                          ; SysInfo  - Hardware information
25	;;                                          ; NetInfo  - Network information
26	;;                                          ; FileVer  - Version of a file specified in 'FileName' option
27	;;                                          ; RegValue - Registry string value.
28	;;                                          ; Reg root from 'RegRoot' (e.g. HKLM)
29	;;                                          ; Reg path from 'RegPath' (e.g. SOFTWARE\Microsoft\Windows NT\CurrentVersion)
30	;;                                          ; Reg value from 'RegValue' (e.g. CurrentType)
31	;;                                          ; Reg title from 'RegTitle' (e.g. "The value of X is")
32	;;                                          ; FreeText - Text specified in 'Text' will be displayed as is
33	;;                                          ; UpdateTime - The date and time the bitmap was created
34	;;                                          ; Unused   - Line will not be displayed
35	;;
36	;; Font = <Face name>                       ; Font name (default = "Arial")
37	;; Size = <Font size>                       ; Font size (default = 22)
38	;; Color = <COLORREF value>                 ; Font color (default = WHITE)
39	;; Bold = [0 | 1]                           ; Font boldness (default = 0)
40	;; Italic = [0 | 1]                         ; Font italicness (default = 0)
41	;; Alignment = [Left | Right | Center]      ; Font alignment (default = Left)
42	;;
43	;; ShadowX = <X offset value>               ; Shadow X offset (positive only, 0 = No X shadow. Default = 0)
44	;; ShadowY = <Y offset value>               ; Shadow Y offset (positive only, 0 = No Y shadow. Default = 0)
45	;; ShadowColor = <COLORREF value>           ; Shadow Color (default = 0 (black))
46	;;
47	;; RegRoot = [HKLM | HKCU]                  ; Registry root to use for 'Type' = 'RegValue'
48	;; RegPath = <Registry path to read from>   ; Registry path to use for 'Type' = 'RegValue'
49	;; RegValue = <Registry value to read from> ; Registry value to use for 'Type' = 'RegValue'. Must be of type REG_SZ
50	;; RegTitle = <Display title of read value> ; Registry value to use for 'Type' = 'RegValue'
51	;;
52	;; Text = <free text to display>            ; Free text to display. Used if 'Type' = 'FreeText'
53	;;
54	;; FilePath = <full path to file>           ; Path to file to display version for. Used if 'Type' = 'FileVer'
55	;; FileName = <display name of file>        ; Display name of file specified in 'FilePath'. Used if 'Type' = 'FileVer'
56	;;
57
58	[General]
59	BackgroundColor = 2097152
60	AutoBackground = 1
61	Output = %temp%\backinfo.bmp
62	UpdateDesktop = 1
63	LineSpacing = 2
64	ForceDesktopCenter = 1
65	SuppressErrors = 1
66
67	[Line1]
68	Font = Trebuchet MS
69	Size = 42
70	Color = 16777215
71	Bold = 1
72	Italic = 0
73	Alignment = Center
74	ShadowX = 2
75	ShadowY = 2
76	ShadowColor = 4210752
77	Type = CompName
78
79	[Line2]
80	Font = Trebuchet MS
81	Size = 20
82	Color = 10526880
83	Bold = 0
84	Italic = 0
85	Alignment = Center
86	ShadowX = 0
87	ShadowY = 0
88	ShadowColor = 4210752
89	Type = UserName
90
91	[Line3]
92	Font = Trebuchet MS
93	Size = 20
94	Color = 10526880
95	Bold = 1
96	Italic = 0
97	Alignment = Center
98	ShadowX = 0
99	ShadowY = 0
100	ShadowColor = 4210752
101	Type = RegValue
102	RegRoot = HKLM
103	RegPath = SOFTWARE\BackInfo
104	RegValue = OSName
105	RegTitle = OS:
106
107
108	[Line4]
109	Font = Trebuchet MS
110	Size = 20
111	Color = 10526880
112	Bold = 0
113	Italic = 0
114	Alignment = Center
115	ShadowX = 0
116	ShadowY = 0
117	ShadowColor = 4210752
118	Type = SysInfo
119
120	[Line5]
121	Font = Trebuchet MS
122	Size = 20
123	Color = 10526880
124	Bold = 0
125	Italic = 0
126	Alignment = Center
127	ShadowX = 0
128	ShadowY = 0
129	ShadowColor = 4210752
130	Type = NetInfo
131
132
133	;;
134	;; SAMPLE - how to display free text lines
135	;;
136	;  [Line6]
137	;  Font = Trebuchet MS
138	;  Size = 20
139	;  Color = 10526880
140	;  Bold = 0
141	;  Italic = 0
142	;  Alignment = Center
143	;  ShadowX = 0
144	;  ShadowY = 0
145	;  ShadowColor = 4210752
146	;  Type = FreeText
147	;  Text = System path is %windir%
148	;;;
149	;; SAMPLE - how to display file version
150	;;
151	;  [Line7]
152	;  Font = Trebuchet MS
153	;  Size = 20
154	;  Color = 10526880
155	;  Bold = 0
156	;  Italic = 0
157	;  Alignment = Center
158	;  ShadowX = 0
159	;  ShadowY = 0
160	;  ShadowColor = 4210752
161	;  Type = FileVer
162	;  FilePath = %ProgramFiles%\backinfo\backinfo.exe
163	;  FileName = backinfo.exe
164	;;
165	;; SAMPLE - how to display registry value
166	;;
167	;  [Line8]
168	;  Font = Trebuchet MS
169	;  Size = 20
170	;  Color = 10526880
171	;  Bold = 0
172	;  Italic = 0
173	;  Alignment = Center
174	;  ShadowX = 0
175	;  ShadowY = 0
176	;  ShadowColor = 4210752
177	;  Type = RegValue
178	;  RegRoot = HKLM
179	;  RegPath = SOFTWARE\Microsoft\Windows NT\CurrentVersion
180	;  RegValue = CurrentType
181	;  RegTitle = OS type
182
183

;; This INI file should use the following format
;;
;; [General]
;; BackgroundColor = <COLORREF value>       ; The background color to use (default = 0 (black))
;; AutoBackground = [0 | 1]                 ; Use background color of current desktop (default = 0)
;; BackgroundBitmap = <path to BMP file>    ; Overrides AutoBackground and BackgroundColor values. Loads background bitmap from BMP file
;; XOffset = <horizontal offset in pixels>  ; Horizontal offest of the entire text block from the bitmap's center. Can be negative. Default = 0
;; YOffset = <vertical offset in pixels>    ; Vertical offest of the entire text block from the bitmap's center. Can be negative. Default = 0
;; Output = <file name>                     ; Name of output bitmap file (default = "", use popup message)
;; UpdateDesktop = [0 | 1]                  ; Update background desktop bitmap (default = 0)
;; ForceDesktopCenter = [0 | 1]             ; Force the desktop to display the bitmap as cenetered (instead of tiled / streched). Default = 1

;; LineSpacing = <value>                    ; Line spacing (default = 3)
;; SuppressErrors = [0 | 1]                 ; If 1, errors are NOT displayed (default = 0)
;;
;; [LineN]                                  ; Text settings for line N, where N between [1..20]
;; Type = [CompName | UserName | SysVer  |  ; Type of information to display on the line
;;         SysInfo  | NetInfo  | FileVer |
;;         RegValue | FreeText |
           UpdateTime | Unused]
;;                                          ; CompName - Computer name
;;                                          ; UserName - User name
;;                                          ; SysVer   - Operating system version
;;                                          ; SysInfo  - Hardware information
;;                                          ; NetInfo  - Network information
;;                                          ; FileVer  - Version of a file specified in 'FileName' option
;;                                          ; RegValue - Registry string value.
;;                                          ; Reg root from 'RegRoot' (e.g. HKLM)
;;                                          ; Reg path from 'RegPath' (e.g. SOFTWARE\Microsoft\Windows NT\CurrentVersion)
;;                                          ; Reg value from 'RegValue' (e.g. CurrentType)
;;                                          ; Reg title from 'RegTitle' (e.g. "The value of X is")
;;                                          ; FreeText - Text specified in 'Text' will be displayed as is
;;                                          ; UpdateTime - The date and time the bitmap was created
;;                                          ; Unused   - Line will not be displayed
;;
;; Font = <Face name>                       ; Font name (default = "Arial")
;; Size = <Font size>                       ; Font size (default = 22)
;; Color = <COLORREF value>                 ; Font color (default = WHITE)
;; Bold = [0 | 1]                           ; Font boldness (default = 0)
;; Italic = [0 | 1]                         ; Font italicness (default = 0)
;; Alignment = [Left | Right | Center]      ; Font alignment (default = Left)
;;
;; ShadowX = <X offset value>               ; Shadow X offset (positive only, 0 = No X shadow. Default = 0)
;; ShadowY = <Y offset value>               ; Shadow Y offset (positive only, 0 = No Y shadow. Default = 0)
;; ShadowColor = <COLORREF value>           ; Shadow Color (default = 0 (black))
;;
;; RegRoot = [HKLM | HKCU]                  ; Registry root to use for 'Type' = 'RegValue'
;; RegPath = <Registry path to read from>   ; Registry path to use for 'Type' = 'RegValue'
;; RegValue = <Registry value to read from> ; Registry value to use for 'Type' = 'RegValue'. Must be of type REG_SZ
;; RegTitle = <Display title of read value> ; Registry value to use for 'Type' = 'RegValue'
;;
;; Text = <free text to display>            ; Free text to display. Used if 'Type' = 'FreeText'
;;
;; FilePath = <full path to file>           ; Path to file to display version for. Used if 'Type' = 'FileVer'
;; FileName = <display name of file>        ; Display name of file specified in 'FilePath'. Used if 'Type' = 'FileVer'
;;

[General]
BackgroundColor = 2097152
AutoBackground = 1
Output = %temp%\backinfo.bmp
UpdateDesktop = 1
LineSpacing = 2
ForceDesktopCenter = 1
SuppressErrors = 1

[Line1]
Font = Trebuchet MS
Size = 42
Color = 16777215
Bold = 1
Italic = 0
Alignment = Center
ShadowX = 2
ShadowY = 2
ShadowColor = 4210752
Type = CompName

[Line2]
Font = Trebuchet MS
Size = 20
Color = 10526880
Bold = 0
Italic = 0
Alignment = Center
ShadowX = 0
ShadowY = 0
ShadowColor = 4210752
Type = UserName

[Line3]
Font = Trebuchet MS
Size = 20
Color = 10526880
Bold = 1
Italic = 0
Alignment = Center
ShadowX = 0
ShadowY = 0
ShadowColor = 4210752
Type = RegValue
RegRoot = HKLM
RegPath = SOFTWARE\BackInfo
RegValue = OSName
RegTitle = OS:

[Line4]
Font = Trebuchet MS
Size = 20
Color = 10526880
Bold = 0
Italic = 0
Alignment = Center
ShadowX = 0
ShadowY = 0
ShadowColor = 4210752
Type = SysInfo

[Line5]
Font = Trebuchet MS
Size = 20
Color = 10526880
Bold = 0
Italic = 0
Alignment = Center
ShadowX = 0
ShadowY = 0
ShadowColor = 4210752
Type = NetInfo

;;
;; SAMPLE - how to display free text lines
;;
;  [Line6]
;  Font = Trebuchet MS
;  Size = 20
;  Color = 10526880
;  Bold = 0
;  Italic = 0
;  Alignment = Center
;  ShadowX = 0
;  ShadowY = 0
;  ShadowColor = 4210752
;  Type = FreeText
;  Text = System path is %windir%
;;;
;; SAMPLE - how to display file version
;;
;  [Line7]
;  Font = Trebuchet MS
;  Size = 20
;  Color = 10526880
;  Bold = 0
;  Italic = 0
;  Alignment = Center
;  ShadowX = 0
;  ShadowY = 0
;  ShadowColor = 4210752
;  Type = FileVer
;  FilePath = %ProgramFiles%\backinfo\backinfo.exe
;  FileName = backinfo.exe
;;
;; SAMPLE - how to display registry value
;;
;  [Line8]
;  Font = Trebuchet MS
;  Size = 20
;  Color = 10526880
;  Bold = 0
;  Italic = 0
;  Alignment = Center
;  ShadowX = 0
;  ShadowY = 0
;  ShadowColor = 4210752
;  Type = RegValue
;  RegRoot = HKLM
;  RegPath = SOFTWARE\Microsoft\Windows NT\CurrentVersion
;  RegValue = CurrentType
;  RegTitle = OS type


Našel jsem oba bugy:

**Bug 1 — černé pozadí**: `BackInfo.ini` má `AutoBackground = 1` (čte barvu aktuálního desktopu) + `BackgroundColor = 2097152` = `0x200000` = COLORREF pro RGB(0, 0, 32) — skoro černá. Když BackInfo běží uprostřed deploymentu a Windows ještě nestihl propagovat změnu barvy do live session, AutoBackground přečte černou a vygeneruje černé BMP.

**Bug 2 — špatná barva taskbaru**: `05-personalization.ps1` nastavuje `DWM\AccentColor` (pro title bary), ale **nenastavuje** `Explorer\Accent\AccentColorMenu` — to je klíč, ze kterého Windows bere barvu taskbaru při `ColorPrevalence=1`. Bez tohoto klíče Windows použije svůj výchozí accent (= to RGB 130, 232, 253 = Windows 11 default "Steel" blue).

Opravím obojí:


Edit

[General]
BackgroundColor = 2097152
AutoBackground = 1

[General]
; #223B47 in COLORREF (0x00BBGGRR): R=34 G=59 B=71 = 71*65536 + 59*256 + 34 = 4668194
BackgroundColor = 4668194
; AutoBackground=0: do NOT read live desktop color - unreliable during deployment
; (live session may not yet reflect the registry background color change)
AutoBackground = 0


The file /opt/xetup/assets/Backinfo/BackInfo.ini has been updated successfully.

[General]
; #223B47 in COLORREF (0x00BBGGRR): R=34 G=59 B=71 = 71*65536 + 59*256 + 34 = 4668194
BackgroundColor = 4668194
; AutoBackground=0: do NOT read live desktop color - unreliable during deployment
; (live session may not yet reflect the registry background color change)
AutoBackground = 0

;; This INI file should use the following format
;;
;; [General]
;; BackgroundColor = <COLORREF value>       ; The background color to use (default = 0 (black))
;; AutoBackground = [0 | 1]                 ; Use background color of current desktop (default = 0)
;; BackgroundBitmap = <path to BMP file>    ; Overrides AutoBackground and BackgroundColor values. Loads background bitmap from BMP file
;; XOffset = <horizontal offset in pixels>  ; Horizontal offest of the entire text block from the bitmap's center. Can be negative. Default = 0
;; YOffset = <vertical offset in pixels>    ; Vertical offest of the entire text block from the bitmap's center. Can be negative. Default = 0
;; Output = <file name>                     ; Name of output bitmap file (default = "", use popup message)
;; UpdateDesktop = [0 | 1]                  ; Update background desktop bitmap (default = 0)
;; ForceDesktopCenter = [0 | 1]             ; Force the desktop to display the bitmap as cenetered (instead of tiled / streched). Default = 1

;; LineSpacing = <value>                    ; Line spacing (default = 3)
;; SuppressErrors = [0 | 1]                 ; If 1, errors are NOT displayed (default = 0)
;;
;; [LineN]                                  ; Text settings for line N, where N between [1..20]
;; Type = [CompName | UserName | SysVer  |  ; Type of information to display on the line
;;         SysInfo  | NetInfo  | FileVer |
;;         RegValue | FreeText |
           UpdateTime | Unused]
;;                                          ; CompName - Computer name
;;                                          ; UserName - User name
;;                                          ; SysVer   - Operating system version
;;                                          ; SysInfo  - Hardware information
;;                                          ; NetInfo  - Network information
;;                                          ; FileVer  - Version of a file specified in 'FileName' option
;;                                          ; RegValue - Registry string value.
;;                                          ; Reg root from 'RegRoot' (e.g. HKLM)
;;                                          ; Reg path from 'RegPath' (e.g. SOFTWARE\Microsoft\Windows NT\CurrentVersion)
;;                                          ; Reg value from 'RegValue' (e.g. CurrentType)
;;                                          ; Reg title from 'RegTitle' (e.g. "The value of X is")
;;                                          ; FreeText - Text specified in 'Text' will be displayed as is
;;                                          ; UpdateTime - The date and time the bitmap was created
;;                                          ; Unused   - Line will not be displayed
;;
;; Font = <Face name>                       ; Font name (default = "Arial")
;; Size = <Font size>                       ; Font size (default = 22)
;; Color = <COLORREF value>                 ; Font color (default = WHITE)
;; Bold = [0 | 1]                           ; Font boldness (default = 0)
;; Italic = [0 | 1]                         ; Font italicness (default = 0)
;; Alignment = [Left | Right | Center]      ; Font alignment (default = Left)
;;
;; ShadowX = <X offset value>               ; Shadow X offset (positive only, 0 = No X shadow. Default = 0)
;; ShadowY = <Y offset value>               ; Shadow Y offset (positive only, 0 = No Y shadow. Default = 0)
;; ShadowColor = <COLORREF value>           ; Shadow Color (default = 0 (black))
;;
;; RegRoot = [HKLM | HKCU]                  ; Registry root to use for 'Type' = 'RegValue'
;; RegPath = <Registry path to read from>   ; Registry path to use for 'Type' = 'RegValue'
;; RegValue = <Registry value to read from> ; Registry value to use for 'Type' = 'RegValue'. Must be of type REG_SZ
;; RegTitle = <Display title of read value> ; Registry value to use for 'Type' = 'RegValue'
;;
;; Text = <free text to display>            ; Free text to display. Used if 'Type' = 'FreeText'
;;
;; FilePath = <full path to file>           ; Path to file to display version for. Used if 'Type' = 'FileVer'
;; FileName = <display name of file>        ; Display name of file specified in 'FilePath'. Used if 'Type' = 'FileVer'
;;

[General]
BackgroundColor = 2097152
AutoBackground = 1
Output = %temp%\backinfo.bmp
UpdateDesktop = 1
LineSpacing = 2
ForceDesktopCenter = 1
SuppressErrors = 1

[Line1]
Font = Trebuchet MS
Size = 42
Color = 16777215
Bold = 1
Italic = 0
Alignment = Center
ShadowX = 2
ShadowY = 2
ShadowColor = 4210752
Type = CompName

[Line2]
Font = Trebuchet MS
Size = 20
Color = 10526880
Bold = 0
Italic = 0
Alignment = Center
ShadowX = 0
ShadowY = 0
ShadowColor = 4210752
Type = UserName

[Line3]
Font = Trebuchet MS
Size = 20
Color = 10526880
Bold = 1
Italic = 0
Alignment = Center
ShadowX = 0
ShadowY = 0
ShadowColor = 4210752
Type = RegValue
RegRoot = HKLM
RegPath = SOFTWARE\BackInfo
RegValue = OSName
RegTitle = OS:

[Line4]
Font = Trebuchet MS
Size = 20
Color = 10526880
Bold = 0
Italic = 0
Alignment = Center
ShadowX = 0
ShadowY = 0
ShadowColor = 4210752
Type = SysInfo

[Line5]
Font = Trebuchet MS
Size = 20
Color = 10526880
Bold = 0
Italic = 0
Alignment = Center
ShadowX = 0
ShadowY = 0
ShadowColor = 4210752
Type = NetInfo

;;
;; SAMPLE - how to display free text lines
;;
;  [Line6]
;  Font = Trebuchet MS
;  Size = 20
;  Color = 10526880
;  Bold = 0
;  Italic = 0
;  Alignment = Center
;  ShadowX = 0
;  ShadowY = 0
;  ShadowColor = 4210752
;  Type = FreeText
;  Text = System path is %windir%
;;;
;; SAMPLE - how to display file version
;;
;  [Line7]
;  Font = Trebuchet MS
;  Size = 20
;  Color = 10526880
;  Bold = 0
;  Italic = 0
;  Alignment = Center
;  ShadowX = 0
;  ShadowY = 0
;  ShadowColor = 4210752
;  Type = FileVer
;  FilePath = %ProgramFiles%\backinfo\backinfo.exe
;  FileName = backinfo.exe
;;
;; SAMPLE - how to display registry value
;;
;  [Line8]
;  Font = Trebuchet MS
;  Size = 20
;  Color = 10526880
;  Bold = 0
;  Italic = 0
;  Alignment = Center
;  ShadowX = 0
;  ShadowY = 0
;  ShadowColor = 4210752
;  Type = RegValue
;  RegRoot = HKLM
;  RegPath = SOFTWARE\Microsoft\Windows NT\CurrentVersion
;  RegValue = CurrentType
;  RegTitle = OS type

+; AutoBackground=0: do NOT read live desktop color - unreliable during deployment

+; (live session may not yet reflect the registry background color change)


Teď fix accent barvy taskbaru v `05-personalization.ps1`:


    # -----------------------------------------------------------------------
    # Accent color for taskbar
    # Windows taskbar reads AccentColorMenu from Explorer\Accent, NOT DWM\AccentColor.
    # Without this key the taskbar keeps the Windows default accent (light blue).
    # -----------------------------------------------------------------------
    Set-Reg -Path "$HiveRoot\Software\Microsoft\Windows\CurrentVersion\Explorer\Accent" `
            -Name "AccentColorMenu" -Value $AccentColorABGR -Type "DWord"

    Set-Reg -Path "$HiveRoot\Software\Microsoft\Windows\CurrentVersion\Explorer\Accent" `
            -Name "StartColorMenu" -Value $AccentColorABGR -Type "DWord"

    # -----------------------------------------------------------------------
    # Wallpaper - solid color #223B47 (fallback before DesktopInfo runs)
    # -----------------------------------------------------------------------


The file /opt/xetup/scripts/05-personalization.ps1 has been updated successfully.

    # -----------------------------------------------------------------------
    # Accent color for taskbar
    # Windows taskbar reads AccentColorMenu from Explorer\Accent, NOT DWM\AccentColor.
    # Without this key the taskbar keeps the Windows default accent (light blue).
    # -----------------------------------------------------------------------
    Set-Reg -Path "$HiveRoot\Software\Microsoft\Windows\CurrentVersion\Explorer\Accent" `
            -Name "AccentColorMenu" -Value $AccentColorABGR -Type "DWord"

    Set-Reg -Path "$HiveRoot\Software\Microsoft\Windows\CurrentVersion\Explorer\Accent" `
            -Name "StartColorMenu" -Value $AccentColorABGR -Type "DWord"

    # -----------------------------------------------------------------------
    # Wallpaper - solid color #223B47 (fallback before DesktopInfo runs)
    # -----------------------------------------------------------------------

<#
.SYNOPSIS
    Sets system colors, wallpaper, and visual theme.

.DESCRIPTION
    Applies X9.cz visual identity: dark taskbar/Start with accent color #223B47
    (deep blue-gray), light app mode, no transparency. Wallpaper is set to a solid
    color matching the accent. BackInfo.exe (Step 07) overwrites the wallpaper with
    a live system info BMP on every logon - solid color is only the fallback.

.ITEMS
    system-tema-taskbar-start-dark: SystemUsesLightTheme=0 in Themes\Personalize. Dark mode for shell (taskbar, Start menu, Action Center, notification area). Does NOT affect application windows - those stay light. Reduces eye strain in dim environments.
    aplikacni-tema-light: AppsUseLightTheme=1. Application windows (File Explorer, Settings, Calculator, etc.) use white/light backgrounds. Majority of business applications (Office, browsers) also respect this and show light mode.
    accent-barva-223b47-tmave-modroseda: AccentColor DWORD = 0xFF473B22 (stored as ABGR: A=FF, B=47, G=3B, R=22). The deep blue-gray #223B47 is the X9.cz brand color, also used as the solid wallpaper background.
    accent-barva-na-start-a-taskbaru-ano: ColorPrevalence=1. Applies accent color to taskbar background and Start menu surface. The taskbar becomes the brand color instead of default black, creating a distinct recognizable look on X9.cz-deployed machines.
    pruhlednost-vypnuta: EnableTransparency=0. Disables Aero translucency on taskbar and Start. Improves text readability on the taskbar, reduces subtle GPU usage, and looks more professional/consistent on business machines.
    tapeta-jednobarevna-223b47-bez-obrazku: Wallpaper set to solid color #223B47 via SystemParametersInfo(SPI_SETDESKWALLPAPER). BackInfo.exe generates a BMP with hostname, username, OS, network info and sets it as wallpaper on every logon. Solid color = fallback only.
#>
param(
    [object]$Config,
    [string]$LogFile
)

$ErrorActionPreference = "Continue"

function Write-Log {
    param([string]$Message, [string]$Level = "INFO")
    $line = "[$(Get-Date -Format 'HH:mm:ss')] [$Level] $Message"
    $null = New-Item -ItemType Directory -Force -Path (Split-Path $LogFile -Parent) -ErrorAction SilentlyContinue
    Add-Content -Path $LogFile -Value $line -Encoding UTF8
}

# Accent color #223B47 stored as ABGR DWORD: 0xFF473B22
# A=FF B=47 G=3B R=22 -> 0xFF473B22 = 4283612962
$AccentColorABGR = 0xFF473B22

# Gradient colors (Windows generates these automatically but we set them explicitly)
# AccentPalette is 32 bytes - 8 shades of the accent color (BGRA each)
# We use the same color for all shades as a safe default
$AccentColorHex = "#223B47"

function Set-Reg {
    param([string]$Path, [string]$Name, $Value, [string]$Type = "DWord")
    try {
        if (-not (Test-Path $Path)) { New-Item -Path $Path -Force | Out-Null }
        Set-ItemProperty -Path $Path -Name $Name -Value $Value -Type $Type -Force
        Write-Log "  SET $Path\$Name = $Value" -Level OK
    }
    catch {
        Write-Log "  FAILED $Path\$Name - $_" -Level ERROR
    }
}

function Apply-ThemeSettings {
    param([string]$HiveRoot)  # "HKCU:" or "Registry::HKU\DefaultProfile"

    # -----------------------------------------------------------------------
    # System theme - Dark (taskbar, Start, action center)
    # -----------------------------------------------------------------------
    Set-Reg -Path "$HiveRoot\Software\Microsoft\Windows\CurrentVersion\Themes\Personalize" `
            -Name "SystemUsesLightTheme" -Value 0

    # -----------------------------------------------------------------------
    # App theme - Light
    # -----------------------------------------------------------------------
    Set-Reg -Path "$HiveRoot\Software\Microsoft\Windows\CurrentVersion\Themes\Personalize" `
            -Name "AppsUseLightTheme" -Value 1

    # -----------------------------------------------------------------------
    # Accent color on Start and taskbar
    # -----------------------------------------------------------------------
    Set-Reg -Path "$HiveRoot\Software\Microsoft\Windows\CurrentVersion\Themes\Personalize" `
            -Name "ColorPrevalence" -Value 1

    # -----------------------------------------------------------------------
    # Transparency effects - disabled
    # -----------------------------------------------------------------------
    Set-Reg -Path "$HiveRoot\Software\Microsoft\Windows\CurrentVersion\Themes\Personalize" `
            -Name "EnableTransparency" -Value 0

    # -----------------------------------------------------------------------
    # Accent color
    # -----------------------------------------------------------------------
    Set-Reg -Path "$HiveRoot\Software\Microsoft\Windows\DWM" `
            -Name "AccentColor" -Value $AccentColorABGR -Type "DWord"

    Set-Reg -Path "$HiveRoot\Software\Microsoft\Windows\DWM" `
            -Name "ColorizationColor" -Value $AccentColorABGR -Type "DWord"

    Set-Reg -Path "$HiveRoot\Software\Microsoft\Windows\DWM" `
            -Name "ColorizationAfterglow" -Value $AccentColorABGR -Type "DWord"

    # Accent color on title bars and borders
    Set-Reg -Path "$HiveRoot\Software\Microsoft\Windows\DWM" `
            -Name "ColorPrevalence" -Value 1

    # -----------------------------------------------------------------------
    # Wallpaper - solid color #223B47 (fallback before DesktopInfo runs)
    # -----------------------------------------------------------------------
    # Background color as decimal RGB
    Set-Reg -Path "$HiveRoot\Control Panel\Colors" `
            -Name "Background" -Value "34 59 71" -Type "String"

    # Empty Wallpaper path = solid color from Background key above.
    # Without this, new users created from Default hive inherit a broken/missing
    # wallpaper path and Windows falls back to black desktop.
    Set-Reg -Path "$HiveRoot\Control Panel\Desktop" `
            -Name "Wallpaper" -Value "" -Type "String"

    Set-Reg -Path "$HiveRoot\Control Panel\Desktop" `
            -Name "WallpaperStyle" -Value "0" -Type "String"

    Set-Reg -Path "$HiveRoot\Control Panel\Desktop" `
            -Name "TileWallpaper" -Value "0" -Type "String"

    # -----------------------------------------------------------------------
    # Desktop icons - show This PC
    # -----------------------------------------------------------------------
    Set-Reg -Path "$HiveRoot\Software\Microsoft\Windows\CurrentVersion\Explorer\HideDesktopIcons\NewStartPanel" `
            -Name "{20D04FE0-3AEA-1069-A2D8-08002B30309D}" -Value 0
}

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

Write-Log "Loading Default hive for personalization" -Level INFO

& 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
    Write-Log "Applying personalization to current user only" -Level WARN

    Write-Log "Applying theme to current user (HKCU)" -Level STEP
    Apply-ThemeSettings -HiveRoot "HKCU:"

    # Set wallpaper via SystemParametersInfo for current user
    Add-Type -TypeDefinition @"
using System;
using System.Runtime.InteropServices;
public class WallpaperHelper {
    [DllImport("user32.dll", CharSet=CharSet.Auto)]
    public static extern int SystemParametersInfo(int uAction, int uParam, string lpvParam, int fuWinIni);
}
"@ -ErrorAction SilentlyContinue
    [WallpaperHelper]::SystemParametersInfo(20, 0, "", 3) | Out-Null
    exit 0
}

try {
    Write-Log "Applying theme to Default hive" -Level STEP
    Apply-ThemeSettings -HiveRoot "Registry::HKU\DefaultProfile"

    Write-Log "Applying theme to current user (HKCU)" -Level STEP
    Apply-ThemeSettings -HiveRoot "HKCU:"
}
finally {
    [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
    }
}

# -----------------------------------------------------------------------
# Apply wallpaper (solid color) to current desktop session
# -----------------------------------------------------------------------
Write-Log "Setting desktop wallpaper to solid color" -Level INFO

try {
    Add-Type -TypeDefinition @"
using System;
using System.Runtime.InteropServices;
public class WallpaperHelper {
    [DllImport("user32.dll", CharSet=CharSet.Auto)]
    public static extern int SystemParametersInfo(int uAction, int uParam, string lpvParam, int fuWinIni);
}
"@ -ErrorAction SilentlyContinue

    # SPI_SETDESKTOPWALLPAPER=20, SPIF_UPDATEINIFILE|SPIF_SENDCHANGE=3
    # Empty string = solid color defined in Control Panel\Colors\Background
    [WallpaperHelper]::SystemParametersInfo(20, 0, "", 3) | Out-Null
    Write-Log "  Desktop wallpaper updated" -Level OK
}
catch {
    Write-Log "  Failed to update wallpaper: $_" -Level WARN
}

Write-Log "Step 5 complete" -Level OK

+    # Windows taskbar reads AccentColorMenu from Explorer\Accent, NOT DWM\AccentColor.

+    # Without this key the taskbar keeps the Windows default accent (light blue).

+    Set-Reg -Path "$HiveRoot\Software\Microsoft\Windows\CurrentVersion\Explorer\Accent" `

+            -Name "AccentColorMenu" -Value $AccentColorABGR -Type "DWord"

+            -Name "StartColorMenu" -Value $AccentColorABGR -Type "DWord"


Bash

GOOS=windows GOARCH=amd64 go build ./... 2>&1

Build check (assets embed changed)


(Bash completed with no output)


git add assets/Backinfo/BackInfo.ini scripts/05-personalization.ps1 && git commit -m "$(cat <<'EOF'
fix: black BackInfo bg + wrong taskbar accent color

BackInfo.ini:
- AutoBackground=0: don't read live desktop color during deployment;
  Windows hasn't propagated the registry background color to the
  live session yet, so AutoBackground reads black
- BackgroundColor=4668194: explicit COLORREF for #223B47
  (was 2097152 = 0x200000 = RGB(0,0,32), near-black)

05-personalization.ps1:
- Add Explorer\Accent\AccentColorMenu = 0xFF473B22
- Add Explorer\Accent\StartColorMenu = 0xFF473B22
  Windows taskbar reads AccentColorMenu for its color when
  ColorPrevalence=1; DWM\AccentColor only controls title bars.
  Without these keys the taskbar shows Windows default blue
  (RGB 130, 232, 253 = Windows 11 "Steel" default accent).

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
EOF
)"

Commit both fixes


[main b58441d] fix: black BackInfo bg + wrong taskbar accent color
 2 files changed, 16 insertions(+), 2 deletions(-)


TOKEN=$(sudo docker exec -u git xetup-forgejo forgejo admin user generate-access-token --username x9 --token-name "push-$(date +%s)" --raw --scopes "write:repository" 2>/dev/null | tail -1) && git push "https://x9:${TOKEN}@git.xetup.x9.cz/x9/xetup.git" main 2>&1

Push to Forgejo


To https://git.xetup.x9.cz/x9/xetup.git
   9027718..b58441d  main -> main


Pushnuté, CI se spouští.

**Shrnutí bugů:**

| Symptom | Příčina | Oprava |
|---|---|---|
| Černé pozadí | `AutoBackground=1` — BackInfo čte barvu desktopu ze živé session, která během deploymentu ještě nereflektuje změnu barvy z registru. Fallback `BackgroundColor=2097152` = RGB(0,0,32) = skoro černá. | `AutoBackground=0` + `BackgroundColor=4668194` (#223B47 v COLORREF) |
| Taskbar RGB(130,232,253) | Script nastavoval `DWM\AccentColor` (= barvení title barů), ale chyběl `Explorer\Accent\AccentColorMenu` — ten Windows čte pro barvu taskbaru při `ColorPrevalence=1`. Bez klíče Windows použije svůj výchozí accent. | Přidat `AccentColorMenu` + `StartColorMenu = 0xFF473B22` do `05-personalization.ps1` |


ještě mi na tu landing page napiš pod ten download link "Pokud ve stažení brání antivirus, použijte curl". Curl stačí spustit v normálním příkazovém řádku, není potřeba administrator.


<tool_use_error>InputValidationError: Grep failed due to the following issue:
An unexpected parameter `file_path` was provided</tool_use_error>

InputValidationError: [
  {
    "code": "unrecognized_keys",
    "keys": [
      "file_path"
    ],
    "path": [],
    "message": "Unrecognized key: \"file_path\""
  }
]


126-    color: var(--blue); text-decoration: none; font-weight: 600;
127-    display: flex; align-items: center; gap: .35rem;
128-  }
129-  .download-strip a:hover { text-decoration: underline; }
130:  .download-strip .dl-meta { color: var(--muted); font-size: .78rem; }
131:  .download-strip .dl-sep  { color: var(--border); }
132-
133-  /* ---- CARDS ---- */
134-  .cards {
135-    display: grid; grid-template-columns: repeat(auto-fit, minmax(200px, 1fr));
--
177-    Git repozitar
178-

179-
180-

181:    curl -Lo xetup.exe https://xetup.x9.cz/dl
182-    <button id="copy-btn" onclick="copyCmd()">Kopirovat</button>
183-

184-
185-
186:

187:
188-      ⬇ xetup.exe
189-
190:    ·
191:    nacitam...
192:    ·
193-
194-      vsechny verze
195-
196-

--
208-

209-

210-      📄
211-
Per-client config

212:
config.json vedle .exe pro opakovatelne nasazeni u stejneho klienta.

213-

214-

215-      🚀
216-
Go TUI launcher

--
239-      const rel = releases[0];
240-      const asset = (rel.assets || []).find(a => a.name === 'xetup.exe');
241-      if (!asset) return;
242-
243:      const strip  = document.getElementById('dl-strip');
244:      const link   = document.getElementById('dl-link');
245:      const meta   = document.getElementById('dl-meta');
246-      const sizeMB = (asset.size / 1048576).toFixed(1);
247-
248-      link.href        = asset.browser_download_url;
249-      link.textContent = '\u2b15 xetup.exe';


Edit

    curl -Lo xetup.exe https://xetup.x9.cz/dl
    <button id="copy-btn" onclick="copyCmd()">Kopirovat</button>

    curl -Lo xetup.exe https://xetup.x9.cz/dl
    <button id="copy-btn" onclick="copyCmd()">Kopirovat</button>

    Pokud ve stazeni brani antivirus, pouzijte curl – staci bezny prikazovy radek, neni potreba administrator.


<tool_use_error>File has not been read yet. Read it first before writing to it.</tool_use_error>

Error: File has not been read yet. Read it first before writing to it.


179
180

181	    curl -Lo xetup.exe https://xetup.x9.cz/dl
182	    <button id="copy-btn" onclick="copyCmd()">Kopirovat</button>
183

184
185
186

187
188	      ⬇ xetup.exe

    curl -Lo xetup.exe https://xetup.x9.cz/dl
    <button id="copy-btn" onclick="copyCmd()">Kopirovat</button>

      ⬇ xetup.exe


    curl -Lo xetup.exe https://xetup.x9.cz/dl
    <button id="copy-btn" onclick="copyCmd()">Kopirovat</button>

    curl -Lo xetup.exe https://xetup.x9.cz/dl
    <button id="copy-btn" onclick="copyCmd()">Kopirovat</button>

    Pokud ve stazeni brani antivirus, pouzijte curl – staci bezny prikazovy radek, neni potreba administrator.


The file /opt/xetup/web/index.html has been updated successfully.

    curl -Lo xetup.exe https://xetup.x9.cz/dl
    <button id="copy-btn" onclick="copyCmd()">Kopirovat</button>

    Pokud ve stazeni brani antivirus, pouzijte curl – staci bezny prikazovy radek, neni potreba administrator.

<!DOCTYPE html>

<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Xetup - Windows deployment pro X9.cz</title>
<link rel="icon" type="image/x-icon" href="/favicon.ico">

    xetupby X9.cz

    Specifikace
    Git
    Issues

MSP deployment tool — X9.cz

Automaticky nastavene Windows za 20 minut

    Nahrazuje 3 hodiny rucniho nastavovani jednim skriptem.
    Win10 + Win11, OEM i cisty install, funguje offline.

    Zobrazit specifikaci
    Git repozitar

    curl -Lo xetup.exe https://xetup.x9.cz/dl
    <button id="copy-btn" onclick="copyCmd()">Kopirovat</button>

      ⬇ xetup.exe

    ·
    nacitam...
    ·

      vsechny verze

      ⚙

~20 stroju / mesic

Ruzni klienti, Win10 i Win11, vcetne nepodporovaneho HW.

      🔒

Offline provoz

Scripty + assets jsou soucasti balicku. Site jen pro winget a Atera.

      📄

Per-client config

config.json vedle .exe pro opakovatelne nasazeni u stejneho klienta.

      🚀

Go TUI launcher

xetup.exe — jednotny binarni spoustec s TUI formularom a live logem.

  © 2026 X9.cz s.r.o.
   ·
  Forgejo
   ·
  Specifikace

+  <p style="color:var(--muted);font-size:.78rem;margin-top:.5rem">

+    Pokud ve stazeni brani antivirus, pouzijte curl – staci bezny prikazovy radek, neni potreba administrator.

<!-- Dynamic download strip – filled by JS from Forgejo releases API -->

<div class="download-strip" id="dl-strip" style="display:none">


Bash

git add web/index.html && git commit -m "$(cat <<'EOF'
docs: add antivirus/curl note under download link

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
EOF
)" && TOKEN=$(sudo docker exec -u git xetup-forgejo forgejo admin user generate-access-token --username x9 --token-name "push-$(date +%s)" --raw --scopes "write:repository" 2>/dev/null | tail -1) && git push "https://x9:${TOKEN}@git.xetup.x9.cz/x9/xetup.git" main 2>&1

Commit and push


[main 1c7678c] docs: add antivirus/curl note under download link
 1 file changed, 3 insertions(+)
To https://git.xetup.x9.cz/x9/xetup.git
   b58441d..1c7678c  main -> main


Hotovo — heal.sh to za chvíli nasadí automaticky na web.


hm - tak ještě by si to v rámci toho scheduled tasku mohlo na tu dobu udělat autologon. Je tam adminx9 bez hesla.... Myslím kvůli těm windows updateům


Dobrý nápad. Přečtu aktuální Windows Update skript:


1	<#
2	.SYNOPSIS
3	    Installs all available Windows Updates via PSWindowsUpdate module.
4
5	.DESCRIPTION
6	    First pass: installs all currently available updates without rebooting.
7	    Then registers a scheduled task "X9-WindowsUpdate" that runs on every
8	    logon (as SYSTEM) until no more updates are found - handles the typical
9	    2-3 reboot cycles required on a fresh Windows installation.
10
11	    Operator workflow:
12	      1. xetup completes all steps
13	      2. Operator reboots manually
14	      3. On each subsequent logon the scheduled task runs another update pass
15	      4. Task removes itself automatically when system is fully up to date
16
17	.ITEMS
18	    nainstalovat-pswindowsupdate-modul: Installs NuGet provider and PSWindowsUpdate module from PSGallery.
19	    spustit-prvni-kolo-windows-update: First update pass without reboot - installs all currently available updates.
20	    registrovat-scheduled-task-pro-dalsi-kola: Registers X9-WindowsUpdate scheduled task that runs on logon, handles post-reboot update rounds, and self-deletes when no more updates are found.
21	#>
22	param(
23	    [object]$Config,
24	    [string]$LogFile
25	)
26
27	$ErrorActionPreference = "Continue"
28
29	function Write-Log {
30	    param([string]$Message, [string]$Level = "INFO")
31	    $line = "[$(Get-Date -Format 'HH:mm:ss')] [$Level] $Message"
32	    $null = New-Item -ItemType Directory -Force -Path (Split-Path $LogFile -Parent) -ErrorAction SilentlyContinue
33	    Add-Content -Path $LogFile -Value $line -Encoding UTF8
34	    Write-Output $line
35	}
36
37	Write-Log "=== Step 12 - Windows Update ===" -Level STEP
38
39	# -----------------------------------------------------------------------
40	# 1. NuGet provider + PSWindowsUpdate module
41	# -----------------------------------------------------------------------
42	Write-Log "Setting up PSWindowsUpdate module..." -Level INFO
43	try {
44	    Install-PackageProvider -Name NuGet -MinimumVersion 2.8.5.201 -Force -Scope AllUsers | Out-Null
45	    $existing = Get-Module -ListAvailable -Name PSWindowsUpdate | Select-Object -First 1
46	    if ($existing) {
47	        Write-Log "  PSWindowsUpdate $($existing.Version) already installed" -Level INFO
48	    } else {
49	        Install-Module -Name PSWindowsUpdate -Force -Scope AllUsers -AllowClobber | Out-Null
50	        Write-Log "  PSWindowsUpdate installed" -Level OK
51	    }
52	    Import-Module PSWindowsUpdate -Force
53	} catch {
54	    Write-Log "  Module setup failed: $_" -Level ERROR
55	    exit 1
56	}
57
58	# -----------------------------------------------------------------------
59	# 2. First update pass (no reboot)
60	# -----------------------------------------------------------------------
61	Write-Log "Running first Windows Update pass..." -Level INFO
62	try {
63	    $result = Install-WindowsUpdate -AcceptAll -IgnoreReboot -Verbose 2>&1
64	    $installed = @($result | Where-Object { $_ -match 'KB\d+|Downloaded|Installed' })
65	    if ($installed.Count -gt 0) {
66	        $result | Where-Object { "$_" -match '\S' } | ForEach-Object { Write-Log "  $_" -Level INFO }
67	        Write-Log "  First pass complete - reboot required for remaining rounds" -Level OK
68	    } else {
69	        Write-Log "  System already up to date" -Level OK
70	    }
71	} catch {
72	    Write-Log "  First pass failed: $_" -Level ERROR
73	}
74
75	# -----------------------------------------------------------------------
76	# 3. Scheduled task for post-reboot update rounds (self-deleting)
77	# -----------------------------------------------------------------------
78	Write-Log "Registering post-reboot update task..." -Level INFO
79
80	$taskName = "X9-WindowsUpdate"
81
82	# PowerShell block that runs on each logon until no more updates found
83	$updateScript = @'
84	Import-Module PSWindowsUpdate -Force -ErrorAction Stop
85	$updates = Get-WindowsUpdate -AcceptAll -IgnoreReboot
86	if ($updates) {
87	    Install-WindowsUpdate -AcceptAll -IgnoreReboot | Out-File "C:\Windows\Setup\Scripts\wu-pass-$(Get-Date -Format 'yyyyMMdd-HHmmss').log" -Encoding UTF8
88	} else {
89	    # No more updates - remove this task
90	    Unregister-ScheduledTask -TaskName "X9-WindowsUpdate" -Confirm:$false
91	}
92	'@
93
94	try {
95	    $action  = New-ScheduledTaskAction -Execute "powershell.exe" `
96	                 -Argument "-NonInteractive -WindowStyle Hidden -ExecutionPolicy Bypass -Command `"$updateScript`""
97	    $trigger = New-ScheduledTaskTrigger -AtLogOn
98	    $settings = New-ScheduledTaskSettingsSet -ExecutionTimeLimit (New-TimeSpan -Hours 2) `
99	                  -MultipleInstances IgnoreNew
100	    $principal = New-ScheduledTaskPrincipal -UserId "SYSTEM" -RunLevel Highest
101
102	    # Remove existing task first (idempotent)
103	    Unregister-ScheduledTask -TaskName $taskName -Confirm:$false -ErrorAction SilentlyContinue
104
105	    Register-ScheduledTask -TaskName $taskName -Action $action -Trigger $trigger `
106	      -Settings $settings -Principal $principal -Force | Out-Null
107
108	    Write-Log "  Task '$taskName' registered - runs on each logon until fully updated" -Level OK
109	} catch {
110	    Write-Log "  Failed to register scheduled task: $_" -Level WARN
111	    Write-Log "  Manual Windows Update rounds will be needed after reboot" -Level WARN
112	}
113
114	Write-Log "Step 12 - Windows Update complete" -Level OK
115	Write-Log "  ACTION REQUIRED: Reboot the machine to complete remaining update rounds" -Level WARN
116

<#
.SYNOPSIS
    Installs all available Windows Updates via PSWindowsUpdate module.

.DESCRIPTION
    First pass: installs all currently available updates without rebooting.
    Then registers a scheduled task "X9-WindowsUpdate" that runs on every
    logon (as SYSTEM) until no more updates are found - handles the typical
    2-3 reboot cycles required on a fresh Windows installation.

    Operator workflow:
      1. xetup completes all steps
      2. Operator reboots manually
      3. On each subsequent logon the scheduled task runs another update pass
      4. Task removes itself automatically when system is fully up to date

.ITEMS
    nainstalovat-pswindowsupdate-modul: Installs NuGet provider and PSWindowsUpdate module from PSGallery.
    spustit-prvni-kolo-windows-update: First update pass without reboot - installs all currently available updates.
    registrovat-scheduled-task-pro-dalsi-kola: Registers X9-WindowsUpdate scheduled task that runs on logon, handles post-reboot update rounds, and self-deletes when no more updates are found.
#>
param(
    [object]$Config,
    [string]$LogFile
)

$ErrorActionPreference = "Continue"

function Write-Log {
    param([string]$Message, [string]$Level = "INFO")
    $line = "[$(Get-Date -Format 'HH:mm:ss')] [$Level] $Message"
    $null = New-Item -ItemType Directory -Force -Path (Split-Path $LogFile -Parent) -ErrorAction SilentlyContinue
    Add-Content -Path $LogFile -Value $line -Encoding UTF8
    Write-Output $line
}

Write-Log "=== Step 12 - Windows Update ===" -Level STEP

# -----------------------------------------------------------------------
# 1. NuGet provider + PSWindowsUpdate module
# -----------------------------------------------------------------------
Write-Log "Setting up PSWindowsUpdate module..." -Level INFO
try {
    Install-PackageProvider -Name NuGet -MinimumVersion 2.8.5.201 -Force -Scope AllUsers | Out-Null
    $existing = Get-Module -ListAvailable -Name PSWindowsUpdate | Select-Object -First 1
    if ($existing) {
        Write-Log "  PSWindowsUpdate $($existing.Version) already installed" -Level INFO
    } else {
        Install-Module -Name PSWindowsUpdate -Force -Scope AllUsers -AllowClobber | Out-Null
        Write-Log "  PSWindowsUpdate installed" -Level OK
    }
    Import-Module PSWindowsUpdate -Force
} catch {
    Write-Log "  Module setup failed: $_" -Level ERROR
    exit 1
}

# -----------------------------------------------------------------------
# 2. First update pass (no reboot)
# -----------------------------------------------------------------------
Write-Log "Running first Windows Update pass..." -Level INFO
try {
    $result = Install-WindowsUpdate -AcceptAll -IgnoreReboot -Verbose 2>&1
    $installed = @($result | Where-Object { $_ -match 'KB\d+|Downloaded|Installed' })
    if ($installed.Count -gt 0) {
        $result | Where-Object { "$_" -match '\S' } | ForEach-Object { Write-Log "  $_" -Level INFO }
        Write-Log "  First pass complete - reboot required for remaining rounds" -Level OK
    } else {
        Write-Log "  System already up to date" -Level OK
    }
} catch {
    Write-Log "  First pass failed: $_" -Level ERROR
}

# -----------------------------------------------------------------------
# 3. Scheduled task for post-reboot update rounds (self-deleting)
# -----------------------------------------------------------------------
Write-Log "Registering post-reboot update task..." -Level INFO

$taskName = "X9-WindowsUpdate"

# PowerShell block that runs on each logon until no more updates found
$updateScript = @'
Import-Module PSWindowsUpdate -Force -ErrorAction Stop
$updates = Get-WindowsUpdate -AcceptAll -IgnoreReboot
if ($updates) {
    Install-WindowsUpdate -AcceptAll -IgnoreReboot | Out-File "C:\Windows\Setup\Scripts\wu-pass-$(Get-Date -Format 'yyyyMMdd-HHmmss').log" -Encoding UTF8
} else {
    # No more updates - remove this task
    Unregister-ScheduledTask -TaskName "X9-WindowsUpdate" -Confirm:$false
}
'@

try {
    $action  = New-ScheduledTaskAction -Execute "powershell.exe" `
                 -Argument "-NonInteractive -WindowStyle Hidden -ExecutionPolicy Bypass -Command `"$updateScript`""
    $trigger = New-ScheduledTaskTrigger -AtLogOn
    $settings = New-ScheduledTaskSettingsSet -ExecutionTimeLimit (New-TimeSpan -Hours 2) `
                  -MultipleInstances IgnoreNew
    $principal = New-ScheduledTaskPrincipal -UserId "SYSTEM" -RunLevel Highest

    # Remove existing task first (idempotent)
    Unregister-ScheduledTask -TaskName $taskName -Confirm:$false -ErrorAction SilentlyContinue

    Register-ScheduledTask -TaskName $taskName -Action $action -Trigger $trigger `
      -Settings $settings -Principal $principal -Force | Out-Null

    Write-Log "  Task '$taskName' registered - runs on each logon until fully updated" -Level OK
} catch {
    Write-Log "  Failed to register scheduled task: $_" -Level WARN
    Write-Log "  Manual Windows Update rounds will be needed after reboot" -Level WARN
}

Write-Log "Step 12 - Windows Update complete" -Level OK
Write-Log "  ACTION REQUIRED: Reboot the machine to complete remaining update rounds" -Level WARN


Plán je jasný: před registrací scheduled tasku zapnout autologon pro adminx9 (bez hesla), a v bloku "žádné další updaty" ho zase vypnout. Windows má pro tohle přímo `AutoLogonCount` jako pojistku — nastavím ho na 10 (strop kol), aby se to nezacyklilo navěky pokud se task nespustí.


Edit

# -----------------------------------------------------------------------
# 3. Scheduled task for post-reboot update rounds (self-deleting)
# -----------------------------------------------------------------------
Write-Log "Registering post-reboot update task..." -Level INFO

$taskName = "X9-WindowsUpdate"

# PowerShell block that runs on each logon until no more updates found
$updateScript = @'
Import-Module PSWindowsUpdate -Force -ErrorAction Stop
$updates = Get-WindowsUpdate -AcceptAll -IgnoreReboot
if ($updates) {
    Install-WindowsUpdate -AcceptAll -IgnoreReboot | Out-File "C:\Windows\Setup\Scripts\wu-pass-$(Get-Date -Format 'yyyyMMdd-HHmmss').log" -Encoding UTF8
} else {
    # No more updates - remove this task
    Unregister-ScheduledTask -TaskName "X9-WindowsUpdate" -Confirm:$false
}
'@

try {
    $action  = New-ScheduledTaskAction -Execute "powershell.exe" `
                 -Argument "-NonInteractive -WindowStyle Hidden -ExecutionPolicy Bypass -Command `"$updateScript`""
    $trigger = New-ScheduledTaskTrigger -AtLogOn
    $settings = New-ScheduledTaskSettingsSet -ExecutionTimeLimit (New-TimeSpan -Hours 2) `
                  -MultipleInstances IgnoreNew
    $principal = New-ScheduledTaskPrincipal -UserId "SYSTEM" -RunLevel Highest

    # Remove existing task first (idempotent)
    Unregister-ScheduledTask -TaskName $taskName -Confirm:$false -ErrorAction SilentlyContinue

    Register-ScheduledTask -TaskName $taskName -Action $action -Trigger $trigger `
      -Settings $settings -Principal $principal -Force | Out-Null

    Write-Log "  Task '$taskName' registered - runs on each logon until fully updated" -Level OK
} catch {
    Write-Log "  Failed to register scheduled task: $_" -Level WARN
    Write-Log "  Manual Windows Update rounds will be needed after reboot" -Level WARN
}

Write-Log "Step 12 - Windows Update complete" -Level OK
Write-Log "  ACTION REQUIRED: Reboot the machine to complete remaining update rounds" -Level WARN

# -----------------------------------------------------------------------
# 3. Enable autologon for adminx9 (temporary - disabled when updates complete)
# -----------------------------------------------------------------------
Write-Log "Enabling temporary autologon for adminx9..." -Level INFO

$winlogonPath = "HKLM:\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Winlogon"
try {
    Set-ItemProperty -Path $winlogonPath -Name "AutoAdminLogon"  -Value "1"  -Type String -Force
    Set-ItemProperty -Path $winlogonPath -Name "DefaultUserName" -Value "adminx9" -Type String -Force
    Set-ItemProperty -Path $winlogonPath -Name "DefaultPassword" -Value "" -Type String -Force
    Set-ItemProperty -Path $winlogonPath -Name "DefaultDomainName" -Value "." -Type String -Force
    # Safety cap: max 10 automatic logons in case the task fails to clean up
    Set-ItemProperty -Path $winlogonPath -Name "AutoLogonCount"  -Value 10 -Type DWord -Force
    Write-Log "  Autologon enabled (adminx9, max 10 rounds)" -Level OK
} catch {
    Write-Log "  Failed to enable autologon: $_" -Level WARN
    Write-Log "  Windows Update rounds will require manual login after each reboot" -Level WARN
}

# -----------------------------------------------------------------------
# 4. Scheduled task for post-reboot update rounds (self-deleting)
# -----------------------------------------------------------------------
Write-Log "Registering post-reboot update task..." -Level INFO

$taskName = "X9-WindowsUpdate"

# PowerShell block that runs on each logon until no more updates found.
# When done: disables autologon and removes itself.
$updateScript = @'
Import-Module PSWindowsUpdate -Force -ErrorAction Stop
$updates = Get-WindowsUpdate -AcceptAll -IgnoreReboot
if ($updates) {
    Install-WindowsUpdate -AcceptAll -IgnoreReboot | Out-File "C:\Windows\Setup\Scripts\wu-pass-$(Get-Date -Format 'yyyyMMdd-HHmmss').log" -Encoding UTF8
} else {
    # No more updates - disable autologon and remove this task
    $wl = "HKLM:\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Winlogon"
    Set-ItemProperty -Path $wl -Name "AutoAdminLogon" -Value "0" -Type String -Force
    Remove-ItemProperty -Path $wl -Name "DefaultPassword"   -ErrorAction SilentlyContinue
    Remove-ItemProperty -Path $wl -Name "AutoLogonCount"    -ErrorAction SilentlyContinue
    Unregister-ScheduledTask -TaskName "X9-WindowsUpdate" -Confirm:$false
}
'@

try {
    $action  = New-ScheduledTaskAction -Execute "powershell.exe" `
                 -Argument "-NonInteractive -WindowStyle Hidden -ExecutionPolicy Bypass -Command `"$updateScript`""
    $trigger = New-ScheduledTaskTrigger -AtLogOn
    $settings = New-ScheduledTaskSettingsSet -ExecutionTimeLimit (New-TimeSpan -Hours 2) `
                  -MultipleInstances IgnoreNew
    $principal = New-ScheduledTaskPrincipal -UserId "SYSTEM" -RunLevel Highest

    # Remove existing task first (idempotent)
    Unregister-ScheduledTask -TaskName $taskName -Confirm:$false -ErrorAction SilentlyContinue

    Register-ScheduledTask -TaskName $taskName -Action $action -Trigger $trigger `
      -Settings $settings -Principal $principal -Force | Out-Null

    Write-Log "  Task '$taskName' registered - runs on each logon until fully updated" -Level OK
} catch {
    Write-Log "  Failed to register scheduled task: $_" -Level WARN
    Write-Log "  Manual Windows Update rounds will be needed after reboot" -Level WARN
}

Write-Log "Step 12 - Windows Update complete" -Level OK