Compare commits

...

3 commits

Author SHA1 Message Date
X9 Dev
133fc1e408 docs(web): reflect field fixes + code signing
Some checks failed
release / build-and-release (push) Failing after 36s
- spec: document --source winget (msstore cert bypass), Atera service
  detection, UCPD stop -> WARN on Win11 24H2, CZ+US keyboard layout,
  Network Discovery resource string, clean Windows Update log output, and
  the Trusted Signing step in the architecture section.
- descriptions.json: update 02-software (winget source, Atera) and
  10-network (Network Discovery resource string); add the keyboard layout
  item to 04-default-profile.
- navod + index: note that xetup.exe is now digitally signed (publisher
  X9.cz s.r.o.), so SmartScreen/UAC show a verified publisher.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-05-29 15:00:20 +02:00
X9 Dev
853908bedd ci: sign xetup.exe via Azure Trusted Signing (jsign)
Add a signing step after the build that authenticates the Entra service
principal (client_credentials), fetches a Trusted Signing access token, and
signs xetup.exe with jsign using the X9.cz s.r.o. certificate profile plus an
RFC3161 timestamp (timestamp.acs.microsoft.com). jsign is pinned by version
and sha256. Trusted Signing certs are short-lived (~3 days); the timestamp
keeps the signature valid past expiry, so timestamping must succeed and the
step fails hard otherwise.

Only AZURE_CLIENT_SECRET needs to be set as a Forgejo Actions secret; the
non-secret identifiers are inlined in the workflow.

gitignore the local manual-signing helpers (sign*.sh) and the *.unsigned
build backup.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-05-29 15:00:12 +02:00
X9 Dev
94b7786aa8 fix: field fixes from fresh Win11 deployment (Dell Latitude / GLBNTB63)
- 02/11 winget: add --source winget to every install; fresh Win11 ISOs
  ship an App Installer with a stale pinned cert, so the msstore source
  fails with 0x8a15005e and aborts the install. Forcing the winget source
  bypasses msstore entirely.
- 10 network: enable Network Discovery by -Group "@FirewallAPI.dll,-32752"
  (resource string) instead of -DisplayGroup "Network Discovery", which is
  localized and failed on Czech Windows.
- 04 profile: set keyboard layout CZ primary + US secondary via
  Set-WinUserLanguageList (current user) and Preload in the Default hive
  and HKU\.DEFAULT (welcome screen / system accounts). Always applied.
- 02 software: verify Atera via the AteraAgent service (Get-Service) with a
  path fallback incl. C:\ProgramData, since Atera no longer installs to a
  fixed location.
- 12 windows-update: format Install-WindowsUpdate output via $_.Result/$_.Title
  instead of logging the raw object (was spamming "System.__ComObject").

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-05-29 15:00:05 +02:00
11 changed files with 153 additions and 21 deletions

View file

@ -46,6 +46,56 @@ jobs:
go build -ldflags="-s -w -H windowsgui" -o xetup.exe ./cmd/xetup/
echo "Built: $(ls -lh xetup.exe | awk '{print $5}')"
- name: Sign xetup.exe (Azure Trusted Signing)
env:
# Non-secret identifiers (Entra app + signing account) - safe to inline.
# Only the client secret is a Forgejo secret (Settings > Actions > Secrets).
AZURE_TENANT_ID: 7d36c38a-f04e-49b4-b500-b1677a7fe62f
AZURE_CLIENT_ID: a96e36b5-2661-497a-9d16-b70a6096e78b
AZURE_CLIENT_SECRET: ${{ secrets.AZURE_CLIENT_SECRET }}
TS_ENDPOINT: weu.codesigning.azure.net
TS_ACCOUNT: x9-signing
TS_PROFILE: x9-public
TS_TSA: http://timestamp.acs.microsoft.com
JSIGN_VERSION: "7.4"
JSIGN_SHA256: 2abf2ade9ea322acc2d60c24794eadc465ff9380938fca4c932d09e0b25f1c28
run: |
if [ -z "$AZURE_CLIENT_SECRET" ]; then
echo "ERROR: AZURE_CLIENT_SECRET not set (Forgejo > repo Settings > Actions > Secrets)" >&2
exit 1
fi
apk add --no-cache openjdk17-jre-headless
# Fetch jsign - pinned version, sha256-verified (supply-chain guard)
curl -fsSL -o /tmp/jsign.jar \
"https://github.com/ebourg/jsign/releases/download/${JSIGN_VERSION}/jsign-${JSIGN_VERSION}.jar"
echo "${JSIGN_SHA256} /tmp/jsign.jar" | sha256sum -c -
# Acquire short-lived Trusted Signing access token from the service principal
TOKEN=$(curl -fsS -X POST \
"https://login.microsoftonline.com/${AZURE_TENANT_ID}/oauth2/v2.0/token" \
-d grant_type=client_credentials \
-d "client_id=${AZURE_CLIENT_ID}" \
--data-urlencode "client_secret=${AZURE_CLIENT_SECRET}" \
--data-urlencode "scope=https://codesigning.azure.net/.default" \
| jq -r '.access_token')
[ -n "$TOKEN" ] && [ "$TOKEN" != "null" ] || { echo "ERROR: token acquisition failed" >&2; exit 1; }
echo "Trusted Signing token acquired (length ${#TOKEN})"
# Sign + RFC3161 timestamp. The signing cert is short-lived (~3 days);
# the timestamp is what keeps the signature valid after it expires, so
# timestamping must succeed - the step fails hard if it does not.
java -jar /tmp/jsign.jar \
--storetype TRUSTEDSIGNING \
--keystore "${TS_ENDPOINT}" \
--storepass "${TOKEN}" \
--alias "${TS_ACCOUNT}/${TS_PROFILE}" \
--tsaurl "${TS_TSA}" \
--tsmode RFC3161 \
--alg SHA-256 \
xetup.exe
echo "Signed and timestamped xetup.exe"
- name: Publish latest release
env:
TOKEN: ${{ secrets.FORGEJO_TOKEN }}

5
.gitignore vendored
View file

@ -19,6 +19,11 @@ Desktop.ini
# Build artifacts
flash.zip
# Signing (local manual-signing helpers + unsigned build backup)
sign.sh
sign-azlogin.sh
*.unsigned
# Large reference files
W11.pdf

View file

@ -73,7 +73,12 @@ if (Get-Feature $Config "software" "wingetInstalls") {
Write-Log " Starting: $($pkg.name) ($($pkg.wingetId))" -Level INFO
$jobs += Start-Job -ArgumentList $pkg.wingetId, $pkg.name, $wingetExe -ScriptBlock {
param($wingetId, $name, $wingetExe)
# --source winget forces the winget community repo and bypasses the
# msstore source, which fails on fresh Win11 ISOs whose App Installer
# ships a stale pinned cert (0x8a15005e: server certificate did not
# match any expected values), aborting the install.
$output = & $wingetExe install --id $wingetId `
--source winget `
--silent `
--accept-package-agreements `
--accept-source-agreements `
@ -226,13 +231,24 @@ if (Get-Feature $Config "software" "ateraAgent") {
Write-Log " Atera agent install exit code: $($msiProc.ExitCode)" -Level WARN
}
# Verify binary exists
$ateraExe = "$env:ProgramFiles\ATERA Networks\AteraAgent\AteraAgent.exe"
$ateraExe86 = "${env:ProgramFiles(x86)}\ATERA Networks\AteraAgent\AteraAgent.exe"
if ((Test-Path $ateraExe) -or (Test-Path $ateraExe86)) {
Write-Log " Atera agent binary verified" -Level OK
# Verify install. The AteraAgent service is the most reliable signal -
# the agent registers it regardless of install path (Atera now sometimes
# lands under C:\ProgramData instead of Program Files). Fall back to the
# known binary locations if the service query is inconclusive.
$ateraSvc = Get-Service -Name "AteraAgent" -ErrorAction SilentlyContinue
if ($ateraSvc) {
Write-Log " Atera agent verified (service AteraAgent present, status $($ateraSvc.Status))" -Level OK
} else {
Write-Log " Atera agent binary not found at expected paths" -Level WARN
$ateraPaths = @(
"$env:ProgramFiles\ATERA Networks\AteraAgent\AteraAgent.exe"
"${env:ProgramFiles(x86)}\ATERA Networks\AteraAgent\AteraAgent.exe"
"$env:ProgramData\ATERA Networks\AteraAgent\AteraAgent.exe"
)
if ($ateraPaths | Where-Object { Test-Path $_ }) {
Write-Log " Atera agent binary verified" -Level OK
} else {
Write-Log " Atera agent service and binary not found at expected paths" -Level WARN
}
}
}
catch {

View file

@ -344,6 +344,47 @@ $pinList
-Name "WallpaperStyle" -Value "0" -Type "String"
Set-ProfileReg -SubKey "Control Panel\Desktop" `
-Name "TileWallpaper" -Value "0" -Type "String"
# ===================================================================
# KEYBOARD LAYOUTS - Czech primary, US secondary
# ===================================================================
# CZ stays the primary input language; US English is added as a harmless
# secondary so programmer/special chars are reachable. Applied in three
# places so every account type gets it:
# - current user (adminx9) via Set-WinUserLanguageList
# - Default profile hive -> every newly created user inherits it
# - HKU\.DEFAULT -> welcome screen and system/service accounts
# KLIDs: 00000405 = Czech, 00000409 = US English.
Write-Log "Configuring keyboard layouts (CZ primary, US secondary)" -Level STEP
function Set-PreloadLayouts {
param([string]$KeyPath) # full Registry:: path to the "...\Keyboard Layout\Preload" key
try {
if (-not (Test-Path $KeyPath)) { New-Item -Path $KeyPath -Force -ErrorAction Stop | Out-Null }
Set-ItemProperty -Path $KeyPath -Name "1" -Value "00000405" -Type String -Force -ErrorAction Stop
Set-ItemProperty -Path $KeyPath -Name "2" -Value "00000409" -Type String -Force -ErrorAction Stop
Write-Log " Preload set (1=CZ, 2=US): $KeyPath" -Level OK
}
catch {
Write-Log " Failed to set Preload at $KeyPath - $_" -Level WARN
}
}
# Current user: use the language-list API so the secondary layout shows up
# in the language bar, not just the raw Preload key.
try {
$langs = New-WinUserLanguageList -Language "cs-CZ"
$langs.Add("en-US")
Set-WinUserLanguageList -LanguageList $langs -Force -ErrorAction Stop
Write-Log " Current user language list set (cs-CZ + en-US)" -Level OK
}
catch {
Write-Log " Set-WinUserLanguageList failed - $_" -Level WARN
}
# New users (Default profile hive) and welcome screen / system accounts (.DEFAULT)
Set-PreloadLayouts -KeyPath "Registry::HKU\DefaultProfile\Keyboard Layout\Preload"
Set-PreloadLayouts -KeyPath "Registry::HKU\.DEFAULT\Keyboard Layout\Preload"
}
finally {
# -----------------------------------------------------------------------

View file

@ -85,8 +85,11 @@ catch {
Write-Log "Enabling Network Discovery" -Level INFO
try {
# Enable all Network Discovery rules for Private profile
Get-NetFirewallRule -DisplayGroup "Network Discovery" -ErrorAction Stop |
# Enable all Network Discovery rules for Private profile.
# Match by -Group resource string ("@FirewallAPI.dll,-32752") rather than
# -DisplayGroup: the display name is localized (e.g. "Zjistovani site" on
# Czech Win11), so DisplayGroup matching fails on non-English installs.
Get-NetFirewallRule -Group "@FirewallAPI.dll,-32752" -ErrorAction Stop |
Where-Object { $_.Profile -match "Private|Any" } |
Enable-NetFirewallRule -ErrorAction SilentlyContinue
Write-Log " Network Discovery rules enabled (Private)" -Level OK

View file

@ -52,9 +52,13 @@ Write-Log "Dell confirmed: $model" -Level OK
# -----------------------------------------------------------------------
Write-Log "Installing Dell Command | Update (Universal)..." -Level STEP
# --source winget forces the winget community repo and bypasses the msstore
# source, which fails on fresh Win11 ISOs whose App Installer ships a stale
# pinned cert (0x8a15005e), aborting the install.
$wingetArgs = @(
"install",
"--id", "Dell.CommandUpdate.Universal",
"--source", "winget",
"--silent",
"--accept-package-agreements",
"--accept-source-agreements"

View file

@ -65,8 +65,15 @@ if (-not $available -or @($available).Count -eq 0) {
Write-Log " Found $($available.Count) update(s) - installing..." -Level INFO
try {
$result = Install-WindowsUpdate -AcceptAll -IgnoreReboot -Verbose 2>&1
$result | Where-Object { "$_" -match '\S' } | ForEach-Object { Write-Log " $_" -Level INFO }
# Format each update via its properties. Logging the raw object ($_) renders
# as "System.__ComObject" because the WUApiLib result objects have no useful
# ToString(); -Verbose 2>&1 also merged verbose-stream noise into the log.
$result = Install-WindowsUpdate -AcceptAll -IgnoreReboot
foreach ($u in $result) {
if ($u.Title) {
Write-Log (" {0} - {1}" -f $u.Result, $u.Title) -Level INFO
}
}
Write-Log " Update pass complete - reboot required for next round" -Level OK
} catch {
Write-Log " Update install failed: $_" -Level ERROR

View file

@ -23,12 +23,12 @@
},
"02-software": {
"synopsis": "Installs standard business software via winget, sets Adobe PDF default, and installs Atera RMM agent.",
"description": "Uses winget to install the standard X9.cz MSP software bundle. Checks winget\navailability before running. Each install is logged. After Adobe Acrobat Reader,\ntemporarily stops the UCPD driver (User Choice Protection Driver, present since\nWin11 23H2 / Win10 22H2 update) to allow the HKCR file association write, sets\n.pdf -> AcroRd32, then restarts UCPD. Atera RMM agent is installed for MSP\nmonitoring, remote access, and ticketing integration.",
"description": "Uses winget to install the standard X9.cz MSP software bundle. Checks winget\navailability before running. Each install is logged. After Adobe Acrobat Reader,\ntemporarily stops the UCPD driver (User Choice Protection Driver, present since\nWin11 23H2 / Win10 22H2 update) to allow the HKCR file association write, sets\n.pdf -> AcroRd32, then restarts UCPD. Atera RMM agent is installed for MSP\nmonitoring, remote access, and ticketing integration.\n\nEvery winget install uses --source winget to bypass the msstore source: on fresh Win11 ISOs the bundled App Installer ships a stale pinned certificate and msstore fails with 0x8a15005e (server certificate did not match), which aborts the install. The same flag is applied in step 11 (Dell Command Update).",
"items": {
"7-zip-7zip-7zip": "Installs 7-Zip (winget ID: 7zip.7zip). Used for archive management. Silent install with --accept-package-agreements --accept-source-agreements flags required for unattended deployment.",
"adobe-acrobat-reader-64-bit-adobe-acroba": "Installs Adobe Acrobat Reader DC 64-bit (Adobe.Acrobat.Reader.64-bit). Required as the default PDF viewer to prevent Edge from handling PDFs in browser mode, which limits functionality.",
"openvpn-connect-openvpntechnologies-open": "Installs OpenVPN Connect client. Used for client VPN access when the client network requires a VPN. The ovpn profile and credentials are configured separately per client.",
"atera-agent-install": "Downloads Atera MSI from x9.servicedesk.atera.com and installs via msiexec /qn. During install the Atera MSI shows an interactive MFA window - the technician enters the 2FA code to complete agent registration. Agent enables MSP monitoring, remote access, and ticketing integration with the Atera dashboard.",
"atera-agent-install": "Atera RMM agent downloaded from x9.servicedesk.atera.com and installed via msiexec /qb. During install, Atera MSI shows an interactive MFA window - technician enters the code to complete registration. Install is verified primarily via the AteraAgent service (Get-Service AteraAgent), which is reliable regardless of install path - Atera now sometimes lands under C:\\ProgramData instead of Program Files; a path check (incl. ProgramData) is the fallback. Agent enables MSP monitoring, remote access, and ticketing integration.",
"adobe-pdf-default-pdf-acrord32-po-instal": "Sets .pdf -> AcroRd32 file association after Acrobat install via HKCR (system-wide, no UserChoice hash issue). UCPD driver is stopped immediately before the write and restarted after to ensure the association persists across Edge updates.",
"ucpd-sys-kernel-driver-od-feb-2024-bloku": "UCPD.sys (User Choice Protection Driver) is stopped before the PDF association write and restarted after. Pattern: Stop-Service ucpd -> set HKCR\\.pdf -> Start-Service ucpd. Implemented in this script."
}
@ -71,7 +71,8 @@
"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."
"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.",
"klavesnice-cz-primarni-us-sekundarni": "Sets the keyboard/input layout to Czech primary + US English secondary. Applied via Set-WinUserLanguageList (cs-CZ + en-US) for the current user, plus the Preload key (1=00000405 Czech, 2=00000409 US) written into both the Default profile hive (so every new user inherits it) and HKU\\.DEFAULT (welcome screen and system/service accounts). Applied unconditionally - the US secondary layout is harmless and CZ stays primary."
}
},
"07-backinfo": {
@ -123,7 +124,7 @@
"items": {
"nastavit-sitovy-profil-private": "Sets all connected network profiles to Private via Set-NetConnectionProfile. Public profile blocks most LAN features. Private is required for file sharing, printer sharing, and network discovery. Applied to all currently connected adapters.",
"povolit-ping-icmp-firewall": "Enables \"File and Printer Sharing (Echo Request)\" firewall rules for ICMPv4 and ICMPv6. ICMP echo is disabled by default on clean Windows. Required for network diagnostics, monitoring tools, and basic connectivity verification.",
"zapnout-network-discovery": "Enables the Network Discovery firewall rule group (FPS-NB_Name-In-UDP, LLMNR, etc.) for Private and Domain profiles via Set-NetFirewallRule. Allows this PC to appear in Network Neighborhood and browse other machines."
"zapnout-network-discovery": "Enables the Network Discovery firewall rule group via Set-NetFirewallRule -Group \"@FirewallAPI.dll,-32752\" (a language-independent resource string) for Private/Any profiles, with a netsh fallback. The resource string is used instead of -DisplayGroup \"Network Discovery\" because the display name is localized (e.g. \"Zjistovani site\" on Czech Windows), which made the old DisplayGroup match fail on non-English installs."
}
},
"11-dell-update": {
@ -136,4 +137,4 @@
"bios-firmware-staging-reboot": "BIOS and firmware updates are staged by DCU and finalize on the next system restart. The deployment already ends with a restart (step 09 - computer rename), so no extra reboot is needed."
}
}
}
}

View file

@ -192,7 +192,7 @@
<button id="copy-btn" onclick="copyCmd()">Kopirovat</button>
</div>
<p style="color:var(--muted);font-size:.78rem;margin-top:.5rem">
Pokud ve stazeni brani antivirus, pouzijte curl &ndash; staci bezny prikazovy radek, neni potreba administrator.
Binarka je digitalne podepsana (vydavatel X9.cz s.r.o.). Pokud ve stazeni presto brani antivirus, pouzijte curl &ndash; staci bezny prikazovy radek, neni potreba administrator.
</p>
<!-- Dynamic download strip filled by JS from Forgejo releases API -->

View file

@ -137,7 +137,8 @@
<h2>Stahni xetup.exe</h2>
</div>
<p>Stahni <a href="https://xetup.x9.cz/dl" style="color:var(--blue)">xetup.x9.cz/dl</a> na cilovy pocitac.</p>
<p>Antivirus (hlavne Windows Defender) <code>xetup.exe</code> casto smazne nebo zablokuje. V tom pripade otevri <strong>prikazovy radek</strong> (cmd) a stahni pres curl:</p>
<p><code>xetup.exe</code> je digitalne podepsany (Azure Trusted Signing, vydavatel <strong>X9.cz s.r.o.</strong>) &ndash; SmartScreen i UAC ukazuji overeneho vydavatele a Defender by mel blokovat min nez drive.</p>
<p>Pokud ho antivirus presto smazne nebo zablokuje, otevri <strong>prikazovy radek</strong> (cmd) a stahni pres curl:</p>
<p><code>curl -Lo xetup.exe https://xetup.x9.cz/dl</code></p>
<p>Curl soubor jenom stahne &ndash; pak je treba spustit rucne:</p>
<p><code>xetup</code> + Enter</p>

View file

@ -601,9 +601,11 @@
<tr class="flag-done"><td>OpenVPN Connect (<code>OpenVPNTechnologies.OpenVPNConnect</code>)</td><td>OK</td></tr>
<tr class="flag-done"><td>Atera Agent install</td><td>Invoke-WebRequest + <code>msiexec /i /qb</code> &ndash; /qb umozni zobrazeni MFA okna</td></tr>
<tr class="flag-done"><td>Adobe PDF default: .pdf -&gt; AcroRd32 po instalaci</td><td>OK &ndash; UCPD stop/start kolem zapisu asociace</td></tr>
<tr class="flag-done"><td>UCPD.sys (kernel driver, od Feb 2024) blokuje UserChoice</td><td>Stop-Service ucpd + 2s sleep + overeni zastaveni pred HKCR zapisem</td></tr>
<tr class="flag-done"><td>UCPD.sys (kernel driver, od Feb 2024) blokuje UserChoice</td><td>Stop-Service ucpd + 2s sleep + overeni zastaveni pred HKCR zapisem. Na Win11 24H2 je UCPD chranena sluzba a stop selze &ndash; logovano jako WARN (ne ERROR); HKCR zapis (system-wide) projde i tak.</td></tr>
<tr class="flag-done"><td>Winget parallel joby: timeout 600s + kill zavislych</td><td>Wait-Job -Timeout 600; po vyprseni Kill + Remove zavislych jobu</td></tr>
<tr class="flag-done"><td>Winget cesta explicitne predavana do parallel jobu</td><td>Opraveno &ndash; Start-Job nezdedi PATH; winget.exe fullpath preda jako argument. Exit 3010 (success+reboot) nyni vyhodnocen jako OK.</td></tr>
<tr class="flag-done"><td>Winget: <code>--source winget</code> u kazde instalace</td><td>Field fix &ndash; fresh Win11 ISO ma App Installer se starym pinned certem, msstore source padá na <code>0x8a15005e</code> a instalaci prerusi. <code>--source winget</code> msstore obejde. Plati i pro krok 11 (Dell).</td></tr>
<tr class="flag-done"><td>Atera: detekce pres sluzbu <code>Get-Service AteraAgent</code></td><td>Field fix &ndash; agent se obcas instaluje do <code>C:\ProgramData\</code>; existence sluzby je spolehlivejsi nez kontrola souboru. Fallback na cesty vc. ProgramData.</td></tr>
</table>
<div class="note">
<strong>Atera Agent URL:</strong><br>
@ -668,6 +670,7 @@
<tr class="flag-done"><td>Start menu: zakaz Bing vyhledavani</td><td>DisableSearchBoxSuggestions = 1</td></tr>
<tr class="flag-done"><td>Copilot: zakaz (TurnOffWindowsCopilot = 1)</td><td>OK</td></tr>
<tr class="flag-done"><td>NumLock zapnout pri startu (InitialKeyboardIndicators = 2)</td><td>OK</td></tr>
<tr class="flag-done"><td>Klavesnice: CZ primarni + US sekundarni</td><td>Field fix &ndash; Set-WinUserLanguageList (cs-CZ + en-US) pro aktualniho uzivatele; Preload (<code>1=00000405</code> CZ, <code>2=00000409</code> US) do Default hive i <code>HKU\.DEFAULT</code> (welcome screen + systemove ucty). Aplikuje se vzdy automaticky.</td></tr>
<tr class="flag-done"><td>System tema (taskbar, Start): Dark</td><td>OK</td></tr>
<tr class="flag-done"><td>Aplikacni tema: Light</td><td>OK</td></tr>
<tr class="flag-done"><td>Accent barva: #223B47 (tmave modroseda)</td><td>AccentColor DWORD = 0xFF473B22 (ABGR)</td></tr>
@ -776,7 +779,7 @@
<table class="items">
<tr class="flag-done"><td>Nastavit sitovy profil jako Private (ne Public)</td><td>Set-NetConnectionProfile pro vsechny pripojene adaptery</td></tr>
<tr class="flag-done"><td>Povolit ping (ICMP) pro diagnostiku</td><td>Enable-NetFirewallRule: FPS-ICMP4-ERQ-In + FPS-ICMP6-ERQ-In</td></tr>
<tr class="flag-done"><td>Zapnout Network Discovery pro Private profil</td><td>Set-NetFirewallRule + netsh advfirewall jako fallback</td></tr>
<tr class="flag-done"><td>Zapnout Network Discovery pro Private profil</td><td>Set-NetFirewallRule <code>-Group "@FirewallAPI.dll,-32752"</code> (resource string, nezavisly na jazyku) + netsh fallback. Field fix: drivejsi <code>-DisplayGroup "Network Discovery"</code> selhalo na ceske lokalizaci Win11.</td></tr>
</table>
</div>
<div class="step-footer">
@ -821,7 +824,7 @@
<div class="step-body">
<table class="items">
<tr class="flag-done"><td>Instalace NuGet providera + PSWindowsUpdate modulu ze PSGallery</td><td>Install-PackageProvider + Install-Module PSWindowsUpdate -Force</td></tr>
<tr class="flag-done"><td>Prvni pruchod aktualizaci (bez rebootu)</td><td>Install-WindowsUpdate -AcceptAll -IgnoreReboot</td></tr>
<tr class="flag-done"><td>Prvni pruchod aktualizaci (bez rebootu)</td><td>Install-WindowsUpdate -AcceptAll -IgnoreReboot. Vystup formatovan pres <code>$_.Result</code> + <code>$_.Title</code> (drive log zaplaval radky "System.__ComObject").</td></tr>
<tr class="flag-done"><td>Reboot cyklus (exit 9) &ndash; pokracovani pres xetup resume</td><td>Exit 9 = reboot needed; xetup ulozi stav, nastavi autologon + X9-Resume task, restartuje</td></tr>
<tr class="flag-done"><td>Automaticky restart po skonceni deploymetu (GUI odpocet)</td><td>xetup.exe zobrazi 60s odpocet + tlacitka "Restartovat ted" / "Zrusit restart"</td></tr>
</table>
@ -888,6 +891,7 @@
<tr class="flag-done"><td>E-mail report: 3 pokusy + lokalni HTML fallback</td><td>Backoff 0/1/5s; vzdy ulozi <code>C:\X9\report.html</code> bez ohledu na SMTP</td></tr>
<tr class="flag-done"><td>Hive unload retry (5 pokusu, GC pred kazdym)</td><td>Prevence "hive in use" chyby pri reg unload ntuser.dat</td></tr>
<tr class="flag-done"><td>Resume fix: StepsByIDs nyni nastavuje Enabled=true</td><td>Opravena kriticka chyba &ndash; resume mode preskakoval vsechny kroky</td></tr>
<tr class="flag-done"><td>Code signing: Azure Trusted Signing (jsign)</td><td>CI podepise <code>xetup.exe</code> certem <strong>X9.cz s.r.o.</strong> + RFC3161 timestamp. Trusted Signing cert je kratkodoby (~3 dny) &ndash; timestamp udrzi podpis platny i po expiraci. SmartScreen/UAC pak ukaze overeneho vydavatele.</td></tr>
<tr class="flag-todo"><td>Self-update: stahnout novou verzi z xetup.x9.cz/dl</td><td>Overit hash pred spustenim</td></tr>
<tr class="flag-future"><td>config.json: per-klient preset na USB</td><td>Jmeno PC prefix, SW seznam, klic &ndash; lezi vedle .exe</td></tr>
</table>
@ -895,7 +899,7 @@
<strong>Struktura:</strong> <code>cmd/xetup/</code>, <code>internal/config/</code>, <code>internal/gui/</code>, <code>internal/runner/</code><br><br>
<strong>Go zavislosti:</strong> github.com/lxn/walk (Win32 GUI), golang.org/x/sys<br><br>
<strong>Build:</strong> <code>CGO_ENABLED=1 CC=x86_64-w64-mingw32-gcc GOOS=windows GOARCH=amd64 go build -ldflags="-s -w -H windowsgui" ./cmd/xetup/</code><br>
CI (Forgejo Actions) sestavi a publikuje automaticky pri kazdem push na main.<br><br>
CI (Forgejo Actions) sestavi, <strong>podepise</strong> (Azure Trusted Signing, cert X9.cz s.r.o. + RFC3161 timestamp pres jsign) a publikuje automaticky pri kazdem push na main.<br><br>
<strong>Spolehlivost (v0.6):</strong> Watchdog zabiji zavisle skripty po 30 min ticha. Reboot-loop ochrana omezi opakovani kazdeho kroku na 5 restartu.
State file se zapisuje atomicky (tmp+rename). E-mail report se zkusi 3x s backoff a vzdy ulozi lokalni HTML kopii.
</div>