fix: workflow audit - config parsing, step ordering, cleanup

Root cause fix: runner.go passed config as unevaluated PS expression
via -File mode - scripts received a literal string instead of parsed
object. Changed to -ConfigPath; scripts load JSON themselves via
shared common.ps1 (Write-Log, Get-Feature, Load-Config).

GUI now regenerates runtime config before run so user selections
actually reach the scripts.

Merged 04-default-profile + 05-personalization into single script
(one hive load/unload, no Explorer restart, no hive contention).

Deleted Deploy-Windows.ps1 (xetup.exe is sole entry point),
06-scheduled-tasks.ps1 (tasks caused more harm than good),
07-desktop-info.ps1 (replaced by BackInfo long ago).

Step ordering: activation moved early, pcIdentity before WU
(exit 9 on rename only when rename actually happened).

Edge policies split into mandatory (telemetry, first-run) vs
recommended (UI preferences user can override).

Atera install uses Start-Process -Wait instead of fragile sleep.
Updated config.json, tests, DefaultConfig to match current state.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
X9 Dev 2026-04-17 12:21:41 +02:00
parent 8b795547d3
commit af41dde33c
21 changed files with 378 additions and 1346 deletions

View file

@ -1,276 +0,0 @@
#Requires -RunAsAdministrator
[CmdletBinding()]
param(
[switch]$SkipBloatware,
[switch]$SkipSoftware,
[switch]$SkipDefaultProfile,
[switch]$DryRun,
[ValidateSet("default","admin","user")]
[string]$ProfileType = "default"
)
$ErrorActionPreference = "Continue"
# -----------------------------------------------------------------------
# Paths
# -----------------------------------------------------------------------
$ScriptRoot = $PSScriptRoot
$LogDir = "C:\Windows\Setup\Scripts"
$LogFile = "$LogDir\Deploy.log"
$ConfigFile = "$ScriptRoot\config\config.json"
# -----------------------------------------------------------------------
# Logging
# -----------------------------------------------------------------------
function Write-Log {
param(
[string]$Message,
[ValidateSet("INFO","OK","ERROR","WARN","STEP")]
[string]$Level = "INFO"
)
$timestamp = Get-Date -Format "HH:mm:ss"
$line = "[$timestamp] [$Level] $Message"
Add-Content -Path $LogFile -Value $line -Encoding UTF8
switch ($Level) {
"OK" { Write-Host $line -ForegroundColor Green }
"ERROR" { Write-Host $line -ForegroundColor Red }
"WARN" { Write-Host $line -ForegroundColor Yellow }
"STEP" { Write-Host $line -ForegroundColor Cyan }
default { Write-Host $line }
}
}
# -----------------------------------------------------------------------
# Step runner - catches errors, logs, always continues
# -----------------------------------------------------------------------
$StepResults = [System.Collections.Generic.List[hashtable]]::new()
function Invoke-Step {
param(
[string]$Name,
[scriptblock]$Action
)
Write-Log "---- $Name ----" -Level STEP
if ($DryRun) {
Write-Log "DryRun - skipping execution" -Level WARN
$StepResults.Add(@{ Name = $Name; Status = "DRYRUN" })
return
}
try {
& $Action
Write-Log "$Name - OK" -Level OK
$StepResults.Add(@{ Name = $Name; Status = "OK" })
}
catch {
Write-Log "$Name - ERROR: $_" -Level ERROR
$StepResults.Add(@{ Name = $Name; Status = "ERROR" })
}
}
# -----------------------------------------------------------------------
# Init
# -----------------------------------------------------------------------
if (-not (Test-Path $LogDir)) {
New-Item -ItemType Directory -Path $LogDir -Force | Out-Null
}
Write-Log "========================================" -Level INFO
Write-Log "Deploy-Windows.ps1 started" -Level INFO
Write-Log "Computer: $env:COMPUTERNAME" -Level INFO
Write-Log "User: $env:USERNAME" -Level INFO
Write-Log "Date: $(Get-Date -Format 'yyyy-MM-dd HH:mm:ss')" -Level INFO
if ($DryRun) { Write-Log "Mode: DRY RUN" -Level WARN }
Write-Log "========================================" -Level INFO
# -----------------------------------------------------------------------
# Load config
# -----------------------------------------------------------------------
$Config = $null
Invoke-Step -Name "Load config.json" -Action {
if (-not (Test-Path $ConfigFile)) {
throw "config.json not found: $ConfigFile"
}
$script:Config = Get-Content $ConfigFile -Raw -Encoding UTF8 | ConvertFrom-Json
Write-Log "Config loaded from $ConfigFile" -Level INFO
}
# -----------------------------------------------------------------------
# Build step enable/disable map from config + CLI overrides
# -----------------------------------------------------------------------
$stepsEnabled = @{
adminAccount = $true
bloatware = $true
software = $true
systemRegistry = $true
defaultProfile = $true
personalization = $true
scheduledTasks = $true
backinfo = $true
network = $true
pcIdentity = $true
activation = $true
dellUpdate = $true
}
if ($Config -and $Config.steps) {
foreach ($key in @($stepsEnabled.Keys)) {
$val = $Config.steps.$key
if ($null -ne $val) { $stepsEnabled[$key] = [bool]$val }
}
}
# CLI switches override config.steps
if ($SkipBloatware) { $stepsEnabled['bloatware'] = $false }
if ($SkipSoftware) { $stepsEnabled['software'] = $false }
if ($SkipDefaultProfile) { $stepsEnabled['defaultProfile'] = $false }
function Skip-Step {
param([string]$Name)
Write-Log "$Name - SKIPPED (disabled in config)" -Level WARN
$StepResults.Add(@{ Name = $Name; Status = "SKIPPED" })
}
# -----------------------------------------------------------------------
# Step 0a - Admin account
# -----------------------------------------------------------------------
if ($stepsEnabled['adminAccount']) {
Invoke-Step -Name "Step 0a - Admin account" -Action {
& "$ScriptRoot\scripts\00-admin-account.ps1" -Config $Config -LogFile $LogFile
}
} else { Skip-Step "Step 0a - Admin account" }
# -----------------------------------------------------------------------
# Step 0b - Windows activation
# -----------------------------------------------------------------------
if ($stepsEnabled['activation']) {
Invoke-Step -Name "Step 0b - Windows activation" -Action {
& "$ScriptRoot\scripts\08-activation.ps1" -Config $Config -LogFile $LogFile
}
} else { Skip-Step "Step 0b - Windows activation" }
# -----------------------------------------------------------------------
# Step 1 - Bloatware removal
# -----------------------------------------------------------------------
if ($stepsEnabled['bloatware']) {
Invoke-Step -Name "Step 1 - Bloatware removal" -Action {
& "$ScriptRoot\scripts\01-bloatware.ps1" -Config $Config -LogFile $LogFile
}
} else { Skip-Step "Step 1 - Bloatware removal" }
# -----------------------------------------------------------------------
# Step 2 - Software installation
# -----------------------------------------------------------------------
if ($stepsEnabled['software']) {
Invoke-Step -Name "Step 2 - Software installation" -Action {
& "$ScriptRoot\scripts\02-software.ps1" -Config $Config -LogFile $LogFile
}
} else { Skip-Step "Step 2 - Software installation" }
# -----------------------------------------------------------------------
# Step 3 - System registry (HKLM)
# -----------------------------------------------------------------------
if ($stepsEnabled['systemRegistry']) {
Invoke-Step -Name "Step 3 - System registry" -Action {
& "$ScriptRoot\scripts\03-system-registry.ps1" -Config $Config -LogFile $LogFile
}
} else { Skip-Step "Step 3 - System registry" }
# -----------------------------------------------------------------------
# Step 4 - Default profile (NTUSER.DAT)
# -----------------------------------------------------------------------
if ($stepsEnabled['defaultProfile']) {
Invoke-Step -Name "Step 4 - Default profile" -Action {
& "$ScriptRoot\scripts\04-default-profile.ps1" -Config $Config -LogFile $LogFile -ProfileType $ProfileType
}
} else { Skip-Step "Step 4 - Default profile" }
# -----------------------------------------------------------------------
# Step 5 - Personalization
# -----------------------------------------------------------------------
if ($stepsEnabled['personalization']) {
Invoke-Step -Name "Step 5 - Personalization" -Action {
& "$ScriptRoot\scripts\05-personalization.ps1" -Config $Config -LogFile $LogFile
}
} else { Skip-Step "Step 5 - Personalization" }
# -----------------------------------------------------------------------
# Step 6 - Scheduled tasks
# -----------------------------------------------------------------------
if ($stepsEnabled['scheduledTasks']) {
Invoke-Step -Name "Step 6 - Scheduled tasks" -Action {
& "$ScriptRoot\scripts\06-scheduled-tasks.ps1" -Config $Config -LogFile $LogFile
}
} else { Skip-Step "Step 6 - Scheduled tasks" }
# -----------------------------------------------------------------------
# Step 7 - BackInfo
# -----------------------------------------------------------------------
if ($stepsEnabled['backinfo']) {
Invoke-Step -Name "Step 7 - BackInfo" -Action {
& "$ScriptRoot\scripts\07-backinfo.ps1" -Config $Config -LogFile $LogFile
}
} else { Skip-Step "Step 7 - BackInfo" }
# -----------------------------------------------------------------------
# Step 9 - Network
# -----------------------------------------------------------------------
if ($stepsEnabled['network']) {
Invoke-Step -Name "Step 9 - Network" -Action {
& "$ScriptRoot\scripts\10-network.ps1" -Config $Config -LogFile $LogFile
}
} else { Skip-Step "Step 9 - Network" }
# -----------------------------------------------------------------------
# Step 11 - Dell Command | Update (auto-skipped on non-Dell hardware)
# -----------------------------------------------------------------------
if ($stepsEnabled['dellUpdate']) {
Invoke-Step -Name "Step 11 - Dell Command | Update" -Action {
& "$ScriptRoot\scripts\11-dell-update.ps1" -Config $Config -LogFile $LogFile
}
} else { Skip-Step "Step 11 - Dell Command | Update" }
# -----------------------------------------------------------------------
# Step 10 - PC identity (rename + C:\X9) - runs last, rename needs restart
# -----------------------------------------------------------------------
if ($stepsEnabled['pcIdentity']) {
Invoke-Step -Name "Step 10 - PC identity" -Action {
& "$ScriptRoot\scripts\09-pc-identity.ps1" -Config $Config -LogFile $LogFile
}
} else { Skip-Step "Step 10 - PC identity" }
# -----------------------------------------------------------------------
# Summary
# -----------------------------------------------------------------------
Write-Log "========================================" -Level INFO
Write-Log "SUMMARY" -Level INFO
Write-Log "========================================" -Level INFO
$countOK = ($StepResults | Where-Object { $_.Status -eq "OK" }).Count
$countError = ($StepResults | Where-Object { $_.Status -eq "ERROR" }).Count
$countSkipped = ($StepResults | Where-Object { $_.Status -eq "SKIPPED" }).Count
$countDryRun = ($StepResults | Where-Object { $_.Status -eq "DRYRUN" }).Count
foreach ($r in $StepResults) {
$lvl = switch ($r.Status) {
"OK" { "OK" }
"ERROR" { "ERROR" }
"SKIPPED" { "WARN" }
"DRYRUN" { "WARN" }
}
Write-Log "$($r.Status.PadRight(8)) $($r.Name)" -Level $lvl
}
Write-Log "----------------------------------------" -Level INFO
Write-Log "OK: $countOK ERROR: $countError SKIPPED: $countSkipped DRYRUN: $countDryRun" -Level INFO
Write-Log "Log saved to: $LogFile" -Level INFO
Write-Log "========================================" -Level INFO
if ($countError -gt 0) {
Write-Log "Deployment finished with errors. Review log: $LogFile" -Level ERROR
exit 1
} else {
Write-Log "Deployment finished successfully." -Level OK
exit 0
}

View file

@ -1,49 +1,62 @@
{ {
"steps": {
"adminAccount": true,
"bloatware": true,
"software": true,
"systemRegistry": true,
"defaultProfile": true,
"personalization": true,
"scheduledTasks": true,
"desktopInfo": true,
"activation": true
},
"deployment": { "deployment": {
"pcName": "",
"pcDescription": "",
"timezone": "Central Europe Standard Time", "timezone": "Central Europe Standard Time",
"locale": "cs-CZ" "profileType": "default"
}, },
"adminAccount": { "adminAccount": {
"username": "adminx9", "username": "adminx9"
"password": "AdminX9.AdminX9",
"description": "X9 MSP admin account"
}, },
"activation": { "activation": {
"productKey": "XXXXX-XXXXX-XXXXX-XXXXX-XXXXX", "productKey": ""
"kmsServer": ""
}, },
"software": { "software": {
"install": [ "install": [
{ "name": "7-Zip", "wingetId": "7zip.7zip" }, { "name": "7-Zip", "wingetId": "7zip.7zip" },
{ "name": "Adobe Acrobat Reader","wingetId": "Adobe.Acrobat.Reader.64-bit" }, { "name": "Adobe Acrobat Reader", "wingetId": "Adobe.Acrobat.Reader.64-bit" },
{ "name": "OpenVPN Connect", "wingetId": "OpenVPNTechnologies.OpenVPNConnect" } { "name": "OpenVPN Connect", "wingetId": "OpenVPNTechnologies.OpenVPNConnect" }
] ]
}, },
"steps": {
"adminAccount": true,
"activation": true,
"bloatware": true,
"software": true,
"systemRegistry": true,
"defaultProfile": true,
"backinfo": true,
"network": true,
"dellUpdate": true,
"pcIdentity": true,
"windowsUpdate": true
},
"features": {
"software": {
"wingetInstalls": true,
"pdfDefault": true,
"ateraAgent": true
},
"systemRegistry": {
"systemTweaks": true,
"edgePolicies": true,
"oneDriveUninstall": true,
"powercfg": true,
"proxyDisable": true
},
"defaultProfile": {
"taskbarTweaks": true,
"startMenuTweaks": true,
"explorerTweaks": true
},
"dellUpdate": {
"drivers": true,
"bios": true
}
},
"bloatware": { "bloatware": {
"keepPackages": [ "keepPackages": [
"Microsoft.WindowsCalculator" "Microsoft.WindowsCalculator"
] ]
},
"desktopInfo": {
"enabled": true,
"position": "bottomRight",
"fontSize": 12,
"fontColor": "#FFFFFF",
"backgroundColor": "transparent"
},
"pdfDefault": {
"forceAdobeReader": true,
"scheduledTaskEnabled": true
} }
} }

View file

@ -67,19 +67,17 @@ func DefaultConfig() Config {
}, },
}, },
Steps: map[string]bool{ Steps: map[string]bool{
"adminAccount": true, "adminAccount": true,
"bloatware": true, "activation": true,
"software": true, "bloatware": true,
"systemRegistry": true, "software": true,
"defaultProfile": true, "systemRegistry": true,
"personalization": true, "defaultProfile": true,
"scheduledTasks": true, "backinfo": true,
"backinfo": true, "network": true,
"activation": true, "dellUpdate": true,
"dellUpdate": true, "pcIdentity": true,
"windowsUpdate": true, "windowsUpdate": true,
"network": true,
"pcIdentity": true,
}, },
Features: Features{ Features: Features{
"software": { "software": {

View file

@ -51,6 +51,8 @@ func Run(cfg config.Config, runCfg runner.RunConfig, cfgPath string) {
cfgPath = res.cfgPath cfgPath = res.cfgPath
case "run": case "run":
runCfg.ProfileType = res.cfg.Deployment.ProfileType runCfg.ProfileType = res.cfg.Deployment.ProfileType
// Update runtime config so scripts see the user's GUI selections
_ = config.Save(res.cfg, runCfg.ConfigPath)
results, needsReboot := runPhase(runCfg, res.steps, false) results, needsReboot := runPhase(runCfg, res.steps, false)
if needsReboot { if needsReboot {
prepareRebootAndRestart(res.cfg, res.steps, results, cfgPath, runCfg) prepareRebootAndRestart(res.cfg, res.steps, results, cfgPath, runCfg)

View file

@ -30,21 +30,21 @@ type Step struct {
} }
// AllSteps returns the ordered list of deployment steps. // AllSteps returns the ordered list of deployment steps.
// Order matters: activation early (unlocks features), pcIdentity late (rename
// needs reboot), windowsUpdate last (reboot cycle).
func AllSteps() []Step { func AllSteps() []Step {
return []Step{ return []Step{
{ID: "adminAccount", Num: "00", Name: "Admin ucet", ScriptName: "00-admin-account.ps1"}, {ID: "adminAccount", Num: "00", Name: "Admin ucet", ScriptName: "00-admin-account.ps1"},
{ID: "bloatware", Num: "01", Name: "Bloatware removal", ScriptName: "01-bloatware.ps1"}, {ID: "activation", Num: "08", Name: "Windows aktivace", ScriptName: "08-activation.ps1"},
{ID: "software", Num: "02", Name: "Software (winget)", ScriptName: "02-software.ps1"}, {ID: "bloatware", Num: "01", Name: "Bloatware removal", ScriptName: "01-bloatware.ps1"},
{ID: "systemRegistry", Num: "03", Name: "System Registry (HKLM)", ScriptName: "03-system-registry.ps1"}, {ID: "software", Num: "02", Name: "Software (winget)", ScriptName: "02-software.ps1"},
{ID: "defaultProfile", Num: "04", Name: "Default Profile", ScriptName: "04-default-profile.ps1"}, {ID: "systemRegistry", Num: "03", Name: "System Registry (HKLM)", ScriptName: "03-system-registry.ps1"},
{ID: "personalization", Num: "05", Name: "Personalizace", ScriptName: "05-personalization.ps1"}, {ID: "defaultProfile", Num: "04", Name: "Profil + personalizace", ScriptName: "04-default-profile.ps1"},
{ID: "scheduledTasks", Num: "06", Name: "Scheduled Tasks", ScriptName: "06-scheduled-tasks.ps1"}, {ID: "backinfo", Num: "07", Name: "BackInfo", ScriptName: "07-backinfo.ps1"},
{ID: "backinfo", Num: "07", Name: "BackInfo", ScriptName: "07-backinfo.ps1"}, {ID: "network", Num: "10", Name: "Network discovery", ScriptName: "10-network.ps1"},
{ID: "activation", Num: "08", Name: "Windows aktivace", ScriptName: "08-activation.ps1"}, {ID: "dellUpdate", Num: "11", Name: "Dell Command | Update", ScriptName: "11-dell-update.ps1"},
{ID: "pcIdentity", Num: "09", Name: "PC identita", ScriptName: "09-pc-identity.ps1"}, {ID: "pcIdentity", Num: "09", Name: "PC identita", ScriptName: "09-pc-identity.ps1"},
{ID: "network", Num: "10", Name: "Network discovery", ScriptName: "10-network.ps1"}, {ID: "windowsUpdate", Num: "12", Name: "Windows Update", ScriptName: "12-windows-update.ps1"},
{ID: "dellUpdate", Num: "11", Name: "Dell Command | Update", ScriptName: "11-dell-update.ps1"},
{ID: "windowsUpdate", Num: "12", Name: "Windows Update", ScriptName: "12-windows-update.ps1"},
} }
} }
@ -228,9 +228,9 @@ func (r *Runner) runScript(ctx context.Context, step Step, cfgArg string) error
"-LogFile", r.cfg.LogFile, "-LogFile", r.cfg.LogFile,
} }
// Pass config object as JSON string (script reads it inline) // Pass config path - script loads JSON itself via common.ps1 Load-Config
if cfgArg != "" { if cfgArg != "" {
args = append(args, "-Config", fmt.Sprintf("(Get-Content '%s' | ConvertFrom-Json)", cfgArg)) args = append(args, "-ConfigPath", cfgArg)
} }
// ProfileType for step 04 // ProfileType for step 04

View file

@ -18,18 +18,12 @@
fullname-x9-cz-s-r-o-via-adsi: Sets FullName property via [ADSI] so the account shows as "X9.cz s.r.o." in User Accounts panel, Event Viewer, and audit logs. fullname-x9-cz-s-r-o-via-adsi: Sets FullName property via [ADSI] so the account shows as "X9.cz s.r.o." in User Accounts panel, Event Viewer, and audit logs.
#> #>
param( param(
[object]$Config, [string]$ConfigPath,
[string]$LogFile [string]$LogFile
) )
$ErrorActionPreference = "Continue" . "$PSScriptRoot\common.ps1"
$Config = Load-Config $ConfigPath
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
}
# ----------------------------------------------------------------------- # -----------------------------------------------------------------------
# Account config - no password by design # Account config - no password by design

View file

@ -14,18 +14,12 @@
windows-optional-features-ps-2-0-mediapl: Disabled via Disable-WindowsOptionalFeature: PowerShell 2.0 (security risk - allows unsigned script execution bypass on older hosts), MediaPlayback, Windows Recall (AI screenshot surveillance), Snipping Tool optional component. windows-optional-features-ps-2-0-mediapl: Disabled via Disable-WindowsOptionalFeature: PowerShell 2.0 (security risk - allows unsigned script execution bypass on older hosts), MediaPlayback, Windows Recall (AI screenshot surveillance), Snipping Tool optional component.
#> #>
param( param(
[object]$Config, [string]$ConfigPath,
[string]$LogFile [string]$LogFile
) )
$ErrorActionPreference = "Continue" . "$PSScriptRoot\common.ps1"
$Config = Load-Config $ConfigPath
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
}
# ----------------------------------------------------------------------- # -----------------------------------------------------------------------
# 1a - AppX packages # 1a - AppX packages

View file

@ -19,30 +19,12 @@
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. 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.
#> #>
param( param(
[object]$Config, [string]$ConfigPath,
[string]$LogFile [string]$LogFile
) )
$ErrorActionPreference = "Continue" . "$PSScriptRoot\common.ps1"
$Config = Load-Config $ConfigPath
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 }
}
# ----------------------------------------------------------------------- # -----------------------------------------------------------------------
# Check winget availability # Check winget availability
@ -195,15 +177,20 @@ if (Get-Feature $Config "software" "ateraAgent") {
Invoke-WebRequest -Uri $ateraUrl -OutFile $ateraMsi -UseBasicParsing -ErrorAction Stop Invoke-WebRequest -Uri $ateraUrl -OutFile $ateraMsi -UseBasicParsing -ErrorAction Stop
Write-Log " Download complete" -Level OK Write-Log " Download complete" -Level OK
$msiResult = & msiexec /i $ateraMsi /qn 2>&1 $msiProc = Start-Process msiexec -ArgumentList "/i `"$ateraMsi`" /qn" -Wait -PassThru
Start-Sleep -Seconds 5 if ($msiProc.ExitCode -eq 0) {
Write-Log " Atera agent installed (msiexec exit 0)" -Level OK
$ateraExe = "$env:ProgramFiles\ATERA Networks\AteraAgent\AteraAgent.exe"
if (Test-Path $ateraExe) {
Write-Log " Atera agent installed" -Level OK
} else { } else {
Write-Log " Atera agent install may have failed - binary not found at expected path" -Level WARN Write-Log " Atera agent install exit code: $($msiProc.ExitCode)" -Level WARN
Write-Log " msiexec output: $($msiResult -join ' ')" -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
} else {
Write-Log " Atera agent binary not found at expected paths" -Level WARN
} }
} }
catch { catch {

View file

@ -28,30 +28,12 @@
proxy-auto-detect-zakaz-autodetect-0: HKLM\SOFTWARE\Policies\Microsoft\Windows\CurrentVersion\Internet Settings\AutoDetect = 0. Disables WPAD (Web Proxy Auto-Discovery). Eliminates startup delays from WPAD DNS lookup and prevents MITM via rogue WPAD on untrusted networks. proxy-auto-detect-zakaz-autodetect-0: HKLM\SOFTWARE\Policies\Microsoft\Windows\CurrentVersion\Internet Settings\AutoDetect = 0. Disables WPAD (Web Proxy Auto-Discovery). Eliminates startup delays from WPAD DNS lookup and prevents MITM via rogue WPAD on untrusted networks.
#> #>
param( param(
[object]$Config, [string]$ConfigPath,
[string]$LogFile [string]$LogFile
) )
$ErrorActionPreference = "Continue" . "$PSScriptRoot\common.ps1"
$Config = Load-Config $ConfigPath
function Write-Log {
param([string]$Message, [string]$Level = "INFO")
$line = "[$(Get-Date -Format 'HH:mm:ss')] [$Level] $Message"
$null = New-Item -ItemType Directory -Force -Path (Split-Path $LogFile -Parent) -ErrorAction SilentlyContinue
Add-Content -Path $LogFile -Value $line -Encoding UTF8
}
function Get-Feature {
param([object]$Cfg, [string]$StepID, [string]$FeatureID, [bool]$Default = $true)
try {
if ($null -eq $Cfg) { return $Default }
$stepFeatures = $Cfg.features.$StepID
if ($null -eq $stepFeatures) { return $Default }
$val = $stepFeatures.$FeatureID
if ($null -eq $val) { return $Default }
return [bool]$val
} catch { return $Default }
}
Add-Type -TypeDefinition @" Add-Type -TypeDefinition @"
using System; using System;
@ -310,62 +292,60 @@ if (Get-Feature $Config "systemRegistry" "systemTweaks") {
# ----------------------------------------------------------------------- # -----------------------------------------------------------------------
if (Get-Feature $Config "systemRegistry" "edgePolicies") { if (Get-Feature $Config "systemRegistry" "edgePolicies") {
Write-Log " Applying Edge policies" -Level INFO Write-Log " Applying Edge policies" -Level INFO
$edgePath = "HKLM:\SOFTWARE\Policies\Microsoft\Edge" $edgeMandatory = "HKLM:\SOFTWARE\Policies\Microsoft\Edge"
$edgeRecommended = "HKLM:\SOFTWARE\Policies\Microsoft\Edge\Recommended"
# UI / first run # --- Mandatory (user cannot override, locked in Edge UI) ---
Set-Reg -Path $edgePath -Name "HideFirstRunExperience" -Value 1 # First run / default browser nag
Set-Reg -Path $edgePath -Name "DefaultBrowserSettingEnabled" -Value 0 Set-Reg -Path $edgeMandatory -Name "HideFirstRunExperience" -Value 1
Set-Reg -Path $edgeMandatory -Name "DefaultBrowserSettingEnabled" -Value 0
# New tab page - disable all visual clutter # Telemetry / feedback - always off
Set-Reg -Path $edgePath -Name "NewTabPageContentEnabled" -Value 0 # feed / obsah Set-Reg -Path $edgeMandatory -Name "DiagnosticData" -Value 0
Set-Reg -Path $edgePath -Name "NewTabPageQuickLinksEnabled" -Value 0 # rychle odkazy Set-Reg -Path $edgeMandatory -Name "FeedbackSurveysEnabled" -Value 0
Set-Reg -Path $edgePath -Name "NewTabPageBackgroundEnabled" -Value 0 # pozadi
Set-Reg -Path $edgePath -Name "NewTabPageAllowedBackgroundTypes" -Value 3 # 3 = only solid color
Set-Reg -Path $edgePath -Name "ShowRecommendationsEnabled" -Value 0
Set-Reg -Path $edgePath -Name "SpotlightExperiencesAndRecommendationsEnabled" -Value 0
Set-Reg -Path $edgePath -Name "PersonalizationReportingEnabled" -Value 0
# Shopping / rewards / sidebar
Set-Reg -Path $edgePath -Name "EdgeShoppingAssistantEnabled" -Value 0
Set-Reg -Path $edgePath -Name "ShowMicrosoftRewards" -Value 0
Set-Reg -Path $edgePath -Name "HubsSidebarEnabled" -Value 0
# Search suggestions
Set-Reg -Path $edgePath -Name "SearchSuggestEnabled" -Value 0
Set-Reg -Path $edgePath -Name "ImportOnEachLaunch" -Value 0
# Telemetry / feedback
Set-Reg -Path $edgePath -Name "DiagnosticData" -Value 0
Set-Reg -Path $edgePath -Name "FeedbackSurveysEnabled" -Value 0
Set-Reg -Path $edgePath -Name "EdgeCollectionsEnabled" -Value 0
# Toolbar buttons - show
Set-Reg -Path $edgePath -Name "FavoritesBarEnabled" -Value 1 # Favorites bar always visible
Set-Reg -Path $edgePath -Name "DownloadsButtonEnabled" -Value 1
Set-Reg -Path $edgePath -Name "HistoryButtonEnabled" -Value 1
Set-Reg -Path $edgePath -Name "PerformanceButtonEnabled" -Value 1 # Sleeping Tabs / Performance
# Toolbar buttons - hide
Set-Reg -Path $edgePath -Name "HomeButtonEnabled" -Value 0
Set-Reg -Path $edgePath -Name "SplitScreenEnabled" -Value 0
Set-Reg -Path $edgePath -Name "EdgeEDropEnabled" -Value 0 # Drop
Set-Reg -Path $edgePath -Name "WebCaptureEnabled" -Value 0 # Screenshot
Set-Reg -Path $edgePath -Name "ShareAllowed" -Value 0 # Share
# Default search engine: Google
# SearchProviderEnabled must be 1, SearchProviderName + URL set the provider
Set-Reg -Path $edgePath -Name "DefaultSearchProviderEnabled" -Value 1 -Type "DWord"
Set-Reg -Path $edgePath -Name "DefaultSearchProviderName" -Value "Google" -Type "String"
Set-Reg -Path $edgePath -Name "DefaultSearchProviderSearchURL" `
-Value "https://www.google.com/search?q={searchTerms}" -Type "String"
# Remove other search engines (empty list = no other providers besides default)
Set-Reg -Path $edgePath -Name "ManagedSearchEngines" `
-Value '[{"is_default":true,"name":"Google","search_url":"https://www.google.com/search?q={searchTerms}","keyword":"google.com"}]' `
-Type "String"
# Disable desktop shortcut on install/update # Disable desktop shortcut on install/update
Set-Reg -Path "HKLM:\SOFTWARE\Policies\Microsoft\EdgeUpdate" ` Set-Reg -Path "HKLM:\SOFTWARE\Policies\Microsoft\EdgeUpdate" `
-Name "CreateDesktopShortcutDefault" -Value 0 -Name "CreateDesktopShortcutDefault" -Value 0
# --- Recommended (sets default, user can change in Edge settings) ---
# New tab page - clean defaults
Set-Reg -Path $edgeRecommended -Name "NewTabPageContentEnabled" -Value 0
Set-Reg -Path $edgeRecommended -Name "NewTabPageQuickLinksEnabled" -Value 0
Set-Reg -Path $edgeRecommended -Name "NewTabPageBackgroundEnabled" -Value 0
Set-Reg -Path $edgeRecommended -Name "NewTabPageAllowedBackgroundTypes" -Value 3
Set-Reg -Path $edgeRecommended -Name "ShowRecommendationsEnabled" -Value 0
Set-Reg -Path $edgeRecommended -Name "SpotlightExperiencesAndRecommendationsEnabled" -Value 0
Set-Reg -Path $edgeRecommended -Name "PersonalizationReportingEnabled" -Value 0
# Shopping / rewards / sidebar
Set-Reg -Path $edgeRecommended -Name "EdgeShoppingAssistantEnabled" -Value 0
Set-Reg -Path $edgeRecommended -Name "ShowMicrosoftRewards" -Value 0
Set-Reg -Path $edgeRecommended -Name "HubsSidebarEnabled" -Value 0
Set-Reg -Path $edgeRecommended -Name "EdgeCollectionsEnabled" -Value 0
# Search suggestions / import
Set-Reg -Path $edgeRecommended -Name "SearchSuggestEnabled" -Value 0
Set-Reg -Path $edgeRecommended -Name "ImportOnEachLaunch" -Value 0
# Toolbar buttons - show
Set-Reg -Path $edgeRecommended -Name "FavoritesBarEnabled" -Value 1
Set-Reg -Path $edgeRecommended -Name "DownloadsButtonEnabled" -Value 1
Set-Reg -Path $edgeRecommended -Name "HistoryButtonEnabled" -Value 1
Set-Reg -Path $edgeRecommended -Name "PerformanceButtonEnabled" -Value 1
# Toolbar buttons - hide
Set-Reg -Path $edgeRecommended -Name "HomeButtonEnabled" -Value 0
Set-Reg -Path $edgeRecommended -Name "SplitScreenEnabled" -Value 0
Set-Reg -Path $edgeRecommended -Name "EdgeEDropEnabled" -Value 0
Set-Reg -Path $edgeRecommended -Name "WebCaptureEnabled" -Value 0
Set-Reg -Path $edgeRecommended -Name "ShareAllowed" -Value 0
# Default search engine: Google
Set-Reg -Path $edgeRecommended -Name "DefaultSearchProviderEnabled" -Value 1 -Type "DWord"
Set-Reg -Path $edgeRecommended -Name "DefaultSearchProviderName" -Value "Google" -Type "String"
Set-Reg -Path $edgeRecommended -Name "DefaultSearchProviderSearchURL" `
-Value "https://www.google.com/search?q={searchTerms}" -Type "String"
} else { } else {
Write-Log "edgePolicies feature disabled - skipping" -Level INFO Write-Log "edgePolicies feature disabled - skipping" -Level INFO
} }

View file

@ -1,63 +1,48 @@
<# <#
.SYNOPSIS .SYNOPSIS
Applies registry settings to the Default User profile and the current logged-in user. Applies registry settings to the Default User profile, current user, and sets visual theme.
.DESCRIPTION .DESCRIPTION
Loads C:\Users\Default\NTUSER.DAT as a temporary hive (HKU\DefaultProfile), applies 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 all taskbar, Start menu, Explorer, and personalization settings, then unloads it.
these settings on first logon. The same settings are applied directly to the current Every new user account inherits these settings on first logon. The same settings are
user's HKCU. Does NOT block OneDrive re-launch - the Explorer namespace CLSID and RunOnce entries have been removed. applied directly to the current user's HKCU. 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 overwrites it on every logon.
.ITEMS .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-zarovnat-vlevo-taskbaral-0: TaskbarAl = 0 in Explorer\Advanced. Left alignment matches Windows 10 muscle memory.
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-skryt-search-copilot-task-view-w: Hides Search box, Copilot, Task View, Widgets, Chat/Teams buttons.
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-zobrazit-vsechny-ikonky-v-tray: EnableAutoTray=0 and TrayNotify icon streams cleared.
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. taskbar-vyprazdnit-pinlist-taskbarlayout: Deploys TaskbarLayoutModification.xml per ProfileType.
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-zobrazovat-pripony-souboru-hide: HideFileExt = 0. Shows file extensions in Explorer.
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. explorer-otevrit-na-this-pc-launchto-1: LaunchTo = 1. Explorer opens to This PC.
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. explorer-showrecent-0-showfrequent-0: ShowRecent=0, ShowFrequent=0. Hides recent/frequent from Quick Access.
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. explorer-fullpath-1-cabinetstate: FullPath=1 in CabinetState. Full path in Explorer title bar.
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). start-menu-vyprazdnit-piny-win11: ConfigureStartPins = {"pinnedList":[]}. Empty Start menu grid.
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. start-menu-zakaz-bing-vyhledavani: DisableSearchBoxSuggestions = 1. Local search only.
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. copilot-zakaz-turnoffwindowscopilot-1: TurnOffWindowsCopilot = 1. Disables Copilot sidebar.
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. numlock-zapnout-pri-startu: InitialKeyboardIndicators = 2.
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. system-tema-taskbar-start-dark: SystemUsesLightTheme=0. Dark shell, light apps.
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. accent-barva-223b47: AccentColor 0xFF473B22, ColorPrevalence=1, taskbar/Start branded.
pruhlednost-vypnuta: EnableTransparency=0.
tapeta-jednobarevna-223b47: Solid color #223B47 via SystemParametersInfo. BackInfo overwrites on logon.
#> #>
param( param(
[object]$Config, [string]$ConfigPath,
[string]$LogFile, [string]$LogFile,
[ValidateSet("default","admin","user")] [ValidateSet("default","admin","user")]
[string]$ProfileType = "default" [string]$ProfileType = "default"
) )
$ErrorActionPreference = "Continue" . "$PSScriptRoot\common.ps1"
$Config = Load-Config $ConfigPath
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 # Helpers - apply registry to both Default hive and current HKCU
# ----------------------------------------------------------------------- # -----------------------------------------------------------------------
function Grant-HiveWriteAccess { function Grant-HiveWriteAccess {
param([string]$HivePath) # full path e.g. "Registry::HKU\DefaultProfile\Software\..." param([string]$HivePath)
# Grants Administrators FullControl on a loaded hive key with restricted ACL.
try { try {
$acl = Get-Acl -Path $HivePath -ErrorAction Stop $acl = Get-Acl -Path $HivePath -ErrorAction Stop
$rule = New-Object System.Security.AccessControl.RegistryAccessRule( $rule = New-Object System.Security.AccessControl.RegistryAccessRule(
@ -77,7 +62,7 @@ function Grant-HiveWriteAccess {
function Set-ProfileReg { function Set-ProfileReg {
param( param(
[string]$SubKey, # relative to HKCU (e.g. "Software\Microsoft\...") [string]$SubKey,
[string]$Name, [string]$Name,
$Value, $Value,
[string]$Type = "DWord" [string]$Type = "DWord"
@ -92,7 +77,6 @@ function Set-ProfileReg {
Set-ItemProperty -Path $defPath -Name $Name -Value $Value -Type $Type -Force -ErrorAction Stop Set-ItemProperty -Path $defPath -Name $Name -Value $Value -Type $Type -Force -ErrorAction Stop
} }
catch { catch {
# Retry after granting write access to parent key
try { try {
$parentPath = $defPath -replace '\\[^\\]+$', '' $parentPath = $defPath -replace '\\[^\\]+$', ''
if (Test-Path $parentPath) { Grant-HiveWriteAccess -HivePath $parentPath } if (Test-Path $parentPath) { Grant-HiveWriteAccess -HivePath $parentPath }
@ -120,28 +104,8 @@ function Set-ProfileReg {
} }
} }
function Remove-ProfileReg { # Accent color #223B47 stored as ABGR DWORD: 0xFF473B22
param([string]$SubKey, [string]$Name) $AccentColorABGR = 0xFF473B22
$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 # Load Default profile hive
@ -162,41 +126,33 @@ if ($LASTEXITCODE -ne 0) {
Write-Log "Default hive loaded" -Level OK Write-Log "Default hive loaded" -Level OK
try { try {
# ----------------------------------------------------------------------- # ===================================================================
# Taskbar tweaks (alignment, buttons, tray, layout XML) # TASKBAR TWEAKS
# ----------------------------------------------------------------------- # ===================================================================
if (Get-Feature $Config "defaultProfile" "taskbarTweaks") { if (Get-Feature $Config "defaultProfile" "taskbarTweaks") {
Write-Log "Applying taskbar tweaks" -Level STEP Write-Log "Applying taskbar tweaks" -Level STEP
$tbPath = "Software\Microsoft\Windows\CurrentVersion\Explorer\Advanced" $tbPath = "Software\Microsoft\Windows\CurrentVersion\Explorer\Advanced"
# Win11: align taskbar to left (0 = left, 1 = center) # Win11: align taskbar to left
Set-ProfileReg -SubKey $tbPath -Name "TaskbarAl" -Value 0 Set-ProfileReg -SubKey $tbPath -Name "TaskbarAl" -Value 0
# Hide Search box / button - Win10/11 (0 = hidden, 1 = icon, 2 = full box) # Hide Search box - set both Win10 and Win11 locations
# Note: Win11 uses Search subkey, Win10 uses Explorer\Advanced - set both
Set-ProfileReg -SubKey "Software\Microsoft\Windows\CurrentVersion\Search" ` Set-ProfileReg -SubKey "Software\Microsoft\Windows\CurrentVersion\Search" `
-Name "SearchboxTaskbarMode" -Value 0 -Name "SearchboxTaskbarMode" -Value 0
Set-ProfileReg -SubKey $tbPath -Name "SearchboxTaskbarMode" -Value 0 Set-ProfileReg -SubKey $tbPath -Name "SearchboxTaskbarMode" -Value 0
# Hide Task View button # Hide Task View, Widgets, Chat/Teams, Copilot buttons
Set-ProfileReg -SubKey $tbPath -Name "ShowTaskViewButton" -Value 0 Set-ProfileReg -SubKey $tbPath -Name "ShowTaskViewButton" -Value 0
# Hide Widgets button
Set-ProfileReg -SubKey $tbPath -Name "TaskbarDa" -Value 0 Set-ProfileReg -SubKey $tbPath -Name "TaskbarDa" -Value 0
# Hide Chat / Teams button
Set-ProfileReg -SubKey $tbPath -Name "TaskbarMn" -Value 0 Set-ProfileReg -SubKey $tbPath -Name "TaskbarMn" -Value 0
# Hide Copilot button
Set-ProfileReg -SubKey $tbPath -Name "ShowCopilotButton" -Value 0 Set-ProfileReg -SubKey $tbPath -Name "ShowCopilotButton" -Value 0
# Show all tray icons # Show all tray icons
# EnableAutoTray = 0 works on Win10; Win11 ignores it but set anyway
Set-ProfileReg -SubKey "Software\Microsoft\Windows\CurrentVersion\Explorer" ` Set-ProfileReg -SubKey "Software\Microsoft\Windows\CurrentVersion\Explorer" `
-Name "EnableAutoTray" -Value 0 -Name "EnableAutoTray" -Value 0
# Win11 workaround: clear cached tray icon streams so all icons appear on next login # Win11: clear cached tray icon streams
$trayNotifyKey = "HKCU:\Software\Classes\Local Settings\Software\Microsoft\Windows\CurrentVersion\TrayNotify" $trayNotifyKey = "HKCU:\Software\Classes\Local Settings\Software\Microsoft\Windows\CurrentVersion\TrayNotify"
if (Test-Path $trayNotifyKey) { if (Test-Path $trayNotifyKey) {
Remove-ItemProperty -Path $trayNotifyKey -Name "IconStreams" -Force -ErrorAction SilentlyContinue Remove-ItemProperty -Path $trayNotifyKey -Name "IconStreams" -Force -ErrorAction SilentlyContinue
@ -211,21 +167,12 @@ try {
} }
# Desktop icons - show This PC # Desktop icons - show This PC
# CLSID {20D04FE0-3AEA-1069-A2D8-08002B30309D} = This PC / Computer
Set-ProfileReg -SubKey "Software\Microsoft\Windows\CurrentVersion\Explorer\HideDesktopIcons\NewStartPanel" ` Set-ProfileReg -SubKey "Software\Microsoft\Windows\CurrentVersion\Explorer\HideDesktopIcons\NewStartPanel" `
-Name "{20D04FE0-3AEA-1069-A2D8-08002B30309D}" -Value 0 -Name "{20D04FE0-3AEA-1069-A2D8-08002B30309D}" -Value 0
# Taskbar pinned apps layout (Win10/11) # Taskbar pinned apps layout
# 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 Write-Log " Writing taskbar layout (ProfileType=$ProfileType)" -Level INFO
# Ensure File Explorer shortcut exists in Default profile's Start Menu.
# On a clean Windows 11 install the System Tools folder may be missing
# from C:\Users\Default\AppData\Roaming - without it the XML pin is silently skipped.
$wsh = New-Object -ComObject WScript.Shell $wsh = New-Object -ComObject WScript.Shell
$defRoaming = "C:\Users\Default\AppData\Roaming\Microsoft\Windows\Start Menu\Programs" $defRoaming = "C:\Users\Default\AppData\Roaming\Microsoft\Windows\Start Menu\Programs"
@ -239,7 +186,6 @@ try {
Write-Log " Created File Explorer.lnk in Default profile Start Menu" -Level OK Write-Log " Created File Explorer.lnk in Default profile Start Menu" -Level OK
} }
# Same for PowerShell (admin profile)
if ($ProfileType -eq "admin") { if ($ProfileType -eq "admin") {
$psLnkDir = "$defRoaming\Windows PowerShell" $psLnkDir = "$defRoaming\Windows PowerShell"
$psLnk = "$psLnkDir\Windows PowerShell.lnk" $psLnk = "$psLnkDir\Windows PowerShell.lnk"
@ -263,12 +209,6 @@ try {
<taskbar:DesktopApp DesktopApplicationLinkPath="%APPDATA%\Microsoft\Windows\Start Menu\Programs\System Tools\File Explorer.lnk"/> <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="%APPDATA%\Microsoft\Windows\Start Menu\Programs\Windows PowerShell\Windows PowerShell.lnk"/>
<taskbar:DesktopApp DesktopApplicationLinkPath="%PROGRAMDATA%\Microsoft\Windows\Start Menu\Programs\Microsoft Edge.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 { default {
@ -276,7 +216,7 @@ try {
<taskbar:DesktopApp DesktopApplicationLinkPath="%APPDATA%\Microsoft\Windows\Start Menu\Programs\System Tools\File Explorer.lnk"/> <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"/> <taskbar:DesktopApp DesktopApplicationLinkPath="%PROGRAMDATA%\Microsoft\Windows\Start Menu\Programs\Microsoft Edge.lnk"/>
'@ '@
} # explicit pins with Replace = no Store, no other defaults }
} }
$taskbarLayoutXml = @" $taskbarLayoutXml = @"
@ -302,43 +242,33 @@ $pinList
# NumLock on startup # NumLock on startup
Set-ProfileReg -SubKey "Control Panel\Keyboard" ` Set-ProfileReg -SubKey "Control Panel\Keyboard" `
-Name "InitialKeyboardIndicators" -Value 2 -Type "String" -Name "InitialKeyboardIndicators" -Value 2 -Type "String"
# Accent color on title bars
Set-ProfileReg -SubKey "Software\Microsoft\Windows\DWM" `
-Name "ColorPrevalence" -Value 1
} else { } else {
Write-Log "taskbarTweaks feature disabled - skipping" -Level INFO Write-Log "taskbarTweaks feature disabled - skipping" -Level INFO
} }
# ----------------------------------------------------------------------- # ===================================================================
# Start menu tweaks (pins, Bing, Copilot, GameDVR) # START MENU TWEAKS
# ----------------------------------------------------------------------- # ===================================================================
if (Get-Feature $Config "defaultProfile" "startMenuTweaks") { if (Get-Feature $Config "defaultProfile" "startMenuTweaks") {
Write-Log "Applying Start menu tweaks" -Level STEP Write-Log "Applying Start menu tweaks" -Level STEP
# Disable Bing search suggestions in Start menu
Set-ProfileReg -SubKey "Software\Policies\Microsoft\Windows\Explorer" ` Set-ProfileReg -SubKey "Software\Policies\Microsoft\Windows\Explorer" `
-Name "DisableSearchBoxSuggestions" -Value 1 -Name "DisableSearchBoxSuggestions" -Value 1
# Win11: empty Start menu pins
Set-ProfileReg -SubKey "Software\Microsoft\Windows\CurrentVersion\Start" ` Set-ProfileReg -SubKey "Software\Microsoft\Windows\CurrentVersion\Start" `
-Name "ConfigureStartPins" ` -Name "ConfigureStartPins" `
-Value '{"pinnedList":[]}' ` -Value '{"pinnedList":[]}' `
-Type "String" -Type "String"
# Hide "Recently added" apps in Start menu
Set-ProfileReg -SubKey "Software\Microsoft\Windows\CurrentVersion\Explorer\Advanced" ` Set-ProfileReg -SubKey "Software\Microsoft\Windows\CurrentVersion\Explorer\Advanced" `
-Name "Start_TrackProgs" -Value 0 -Name "Start_TrackProgs" -Value 0
# Hide recently opened files/docs from Start menu
Set-ProfileReg -SubKey "Software\Microsoft\Windows\CurrentVersion\Explorer\Advanced" ` Set-ProfileReg -SubKey "Software\Microsoft\Windows\CurrentVersion\Explorer\Advanced" `
-Name "Start_TrackDocs" -Value 0 -Name "Start_TrackDocs" -Value 0
# Disable Copilot
Set-ProfileReg -SubKey "Software\Policies\Microsoft\Windows\WindowsCopilot" ` Set-ProfileReg -SubKey "Software\Policies\Microsoft\Windows\WindowsCopilot" `
-Name "TurnOffWindowsCopilot" -Value 1 -Name "TurnOffWindowsCopilot" -Value 1
# Disable GameDVR
Set-ProfileReg -SubKey "System\GameConfigStore" ` Set-ProfileReg -SubKey "System\GameConfigStore" `
-Name "GameDVR_Enabled" -Value 0 -Name "GameDVR_Enabled" -Value 0
Set-ProfileReg -SubKey "Software\Microsoft\Windows\CurrentVersion\GameDVR" ` Set-ProfileReg -SubKey "Software\Microsoft\Windows\CurrentVersion\GameDVR" `
@ -347,34 +277,72 @@ $pinList
Write-Log "startMenuTweaks feature disabled - skipping" -Level INFO Write-Log "startMenuTweaks feature disabled - skipping" -Level INFO
} }
# ----------------------------------------------------------------------- # ===================================================================
# Explorer tweaks (file extensions, LaunchTo, ShowRecent, FullPath) # EXPLORER TWEAKS
# ----------------------------------------------------------------------- # ===================================================================
if (Get-Feature $Config "defaultProfile" "explorerTweaks") { if (Get-Feature $Config "defaultProfile" "explorerTweaks") {
Write-Log "Applying Explorer tweaks" -Level STEP Write-Log "Applying Explorer tweaks" -Level STEP
$advPath = "Software\Microsoft\Windows\CurrentVersion\Explorer\Advanced" $advPath = "Software\Microsoft\Windows\CurrentVersion\Explorer\Advanced"
# Show file extensions in Explorer
Set-ProfileReg -SubKey $advPath -Name "HideFileExt" -Value 0 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 Set-ProfileReg -SubKey $advPath -Name "LaunchTo" -Value 1
# Hide Recent files from Quick Access
Set-ProfileReg -SubKey "Software\Microsoft\Windows\CurrentVersion\Explorer" ` Set-ProfileReg -SubKey "Software\Microsoft\Windows\CurrentVersion\Explorer" `
-Name "ShowRecent" -Value 0 -Name "ShowRecent" -Value 0
# Hide Frequent folders from Quick Access
Set-ProfileReg -SubKey "Software\Microsoft\Windows\CurrentVersion\Explorer" ` Set-ProfileReg -SubKey "Software\Microsoft\Windows\CurrentVersion\Explorer" `
-Name "ShowFrequent" -Value 0 -Name "ShowFrequent" -Value 0
# Show full path in Explorer title bar
Set-ProfileReg -SubKey "Software\Microsoft\Windows\CurrentVersion\Explorer\CabinetState" ` Set-ProfileReg -SubKey "Software\Microsoft\Windows\CurrentVersion\Explorer\CabinetState" `
-Name "FullPath" -Value 1 -Name "FullPath" -Value 1
} else { } else {
Write-Log "explorerTweaks feature disabled - skipping" -Level INFO Write-Log "explorerTweaks feature disabled - skipping" -Level INFO
} }
# ===================================================================
# PERSONALIZATION (theme, accent color, wallpaper)
# ===================================================================
Write-Log "Applying personalization (theme, accent, wallpaper)" -Level STEP
# Dark shell (taskbar, Start), light apps
Set-ProfileReg -SubKey "Software\Microsoft\Windows\CurrentVersion\Themes\Personalize" `
-Name "SystemUsesLightTheme" -Value 0
Set-ProfileReg -SubKey "Software\Microsoft\Windows\CurrentVersion\Themes\Personalize" `
-Name "AppsUseLightTheme" -Value 1
# Accent color on Start and taskbar
Set-ProfileReg -SubKey "Software\Microsoft\Windows\CurrentVersion\Themes\Personalize" `
-Name "ColorPrevalence" -Value 1
# Transparency disabled
Set-ProfileReg -SubKey "Software\Microsoft\Windows\CurrentVersion\Themes\Personalize" `
-Name "EnableTransparency" -Value 0
# Accent color #223B47
Set-ProfileReg -SubKey "Software\Microsoft\Windows\DWM" `
-Name "AccentColor" -Value $AccentColorABGR -Type "DWord"
Set-ProfileReg -SubKey "Software\Microsoft\Windows\DWM" `
-Name "ColorizationColor" -Value $AccentColorABGR -Type "DWord"
Set-ProfileReg -SubKey "Software\Microsoft\Windows\DWM" `
-Name "ColorizationAfterglow" -Value $AccentColorABGR -Type "DWord"
Set-ProfileReg -SubKey "Software\Microsoft\Windows\DWM" `
-Name "ColorPrevalence" -Value 1
# Taskbar accent color (Explorer\Accent, not DWM)
Set-ProfileReg -SubKey "Software\Microsoft\Windows\CurrentVersion\Explorer\Accent" `
-Name "AccentColorMenu" -Value $AccentColorABGR -Type "DWord"
Set-ProfileReg -SubKey "Software\Microsoft\Windows\CurrentVersion\Explorer\Accent" `
-Name "StartColorMenu" -Value $AccentColorABGR -Type "DWord"
# Wallpaper - solid color #223B47 (BackInfo overwrites on logon)
Set-ProfileReg -SubKey "Control Panel\Colors" `
-Name "Background" -Value "34 59 71" -Type "String"
Set-ProfileReg -SubKey "Control Panel\Desktop" `
-Name "Wallpaper" -Value "" -Type "String"
Set-ProfileReg -SubKey "Control Panel\Desktop" `
-Name "WallpaperStyle" -Value "0" -Type "String"
Set-ProfileReg -SubKey "Control Panel\Desktop" `
-Name "TileWallpaper" -Value "0" -Type "String"
} }
finally { finally {
# ----------------------------------------------------------------------- # -----------------------------------------------------------------------
@ -394,17 +362,23 @@ finally {
} }
# ----------------------------------------------------------------------- # -----------------------------------------------------------------------
# Restart Explorer to apply taskbar/tray changes to current session # Apply wallpaper (solid color) to current desktop session
# ----------------------------------------------------------------------- # -----------------------------------------------------------------------
Write-Log "Restarting Explorer to apply taskbar changes" -Level INFO Write-Log "Setting desktop wallpaper to solid color" -Level INFO
try { try {
Stop-Process -Name explorer -Force -ErrorAction SilentlyContinue Add-Type -TypeDefinition @"
Start-Sleep -Seconds 2 using System;
Start-Process explorer using System.Runtime.InteropServices;
Write-Log "Explorer restarted" -Level OK 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
Write-Log " Desktop wallpaper updated" -Level OK
} }
catch { catch {
Write-Log "Explorer restart failed (non-fatal): $_" -Level WARN Write-Log " Failed to update wallpaper: $_" -Level WARN
} }
Write-Log "Step 4 complete" -Level OK Write-Log "Step 4 complete" -Level OK

View file

@ -1,208 +0,0 @@
<#
.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
# -----------------------------------------------------------------------
# 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)
# -----------------------------------------------------------------------
# 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

View file

@ -1,206 +0,0 @@
<#
.SYNOPSIS
Registers logon scheduled tasks to maintain per-user settings that Windows resets.
.DESCRIPTION
Creates scheduled tasks under Task Scheduler that run at user logon (and optionally
on a timer) to enforce settings that Windows tends to revert. Tasks are registered
in the Default profile task store so new user accounts inherit them automatically.
Note: PDF-DefaultApp task has been removed - PDF default is set once during deployment.
.ITEMS
showalltrayicons-pri-logonu-kazdou-1-min: Task 'ShowAllTrayIcons': runs at logon, repeats every 1 minute. Sets HKCU\Software\Microsoft\Windows\CurrentVersion\Explorer\EnableAutoTray=0. Windows 11 re-enables auto-hiding of tray icons after updates and sometimes after logon - the 1-min repeat ensures permanent override.
unlockstartlayout-jednou-po-aplikaci-lay: Task 'UnlockStartLayout': runs once, 30 seconds after logon. Clears the Start menu layout lock bit that is set when ConfigureStartPins is applied. Without this, users cannot pin or unpin apps from Start after deployment.
pdf-defaultapp-pri-kazdem-logonu: REMOVED. PDF default is set once during deployment (step 02) with UCPD service stopped. The scheduled task is no longer needed.
#>
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
}
$ScriptDir = "C:\Windows\Setup\Scripts"
if (-not (Test-Path $ScriptDir)) {
New-Item -ItemType Directory -Path $ScriptDir -Force | Out-Null
}
function Register-Task {
param(
[string]$TaskName,
[string]$Description,
[object]$Action,
[object[]]$Triggers,
[string]$RunLevel = "Highest"
)
try {
# Remove existing task with same name
Unregister-ScheduledTask -TaskName $TaskName -Confirm:$false -ErrorAction SilentlyContinue
$settings = New-ScheduledTaskSettingsSet -ExecutionTimeLimit (New-TimeSpan -Minutes 5) `
-MultipleInstances IgnoreNew `
-StartWhenAvailable
$principal = New-ScheduledTaskPrincipal -GroupId "Users" `
-RunLevel $RunLevel
$task = New-ScheduledTask -Action $Action `
-Trigger $Triggers `
-Settings $settings `
-Principal $principal `
-Description $Description
Register-ScheduledTask -TaskName $TaskName -InputObject $task -Force | Out-Null
Write-Log " Registered task: $TaskName" -Level OK
}
catch {
Write-Log " Failed to register task $TaskName - $_" -Level ERROR
}
}
# -----------------------------------------------------------------------
# Task: ShowAllTrayIcons
# Runs on logon: clears TrayNotify icon cache and restarts Explorer so all
# tray icons are visible on first login (Win10: EnableAutoTray=0, Win11: cache clear)
# -----------------------------------------------------------------------
Write-Log "Registering task: ShowAllTrayIcons" -Level STEP
$showTrayScript = "$ScriptDir\ShowAllTrayIcons.ps1"
@'
# Win10: disable auto-hiding of tray icons
$regPath = "HKCU:\Software\Microsoft\Windows\CurrentVersion\Explorer"
Set-ItemProperty -Path $regPath -Name "EnableAutoTray" -Value 0 -Force -ErrorAction SilentlyContinue
# Win11: clear icon stream cache so all icons become visible after Explorer restart
$trayPath = "HKCU:\Software\Classes\Local Settings\Software\Microsoft\Windows\CurrentVersion\TrayNotify"
if (Test-Path $trayPath) {
Remove-ItemProperty -Path $trayPath -Name "IconStreams" -Force -ErrorAction SilentlyContinue
Remove-ItemProperty -Path $trayPath -Name "PastIconsStream" -Force -ErrorAction SilentlyContinue
}
# Restart Explorer to apply changes
Stop-Process -Name explorer -Force -ErrorAction SilentlyContinue
Start-Sleep -Milliseconds 1500
if (-not (Get-Process explorer -ErrorAction SilentlyContinue)) {
Start-Process explorer
}
'@ | Set-Content -Path $showTrayScript -Encoding UTF8 -Force
$showTrayAction = New-ScheduledTaskAction -Execute "powershell.exe" `
-Argument "-NonInteractive -WindowStyle Hidden -ExecutionPolicy Bypass -File `"$showTrayScript`""
$showTrayTrigger = New-ScheduledTaskTrigger -AtLogOn
Register-Task -TaskName "ShowAllTrayIcons" `
-Description "Show all system tray icons for current user" `
-Action $showTrayAction `
-Triggers $showTrayTrigger
# -----------------------------------------------------------------------
Write-Log "Registering task: PDF-DefaultApp" -Level STEP
$pdfScript = "$ScriptDir\PDF-DefaultApp.ps1"
@'
# Restore .pdf -> Adobe Reader HKCR association (system-wide).
# Runs as SYSTEM so it can write to HKCR regardless of Edge updates.
# Note: HKCU UserChoice requires Windows Hash validation and cannot be
# set reliably via registry; HKCR provides the system-wide fallback.
$acroPaths = @(
"$env:ProgramFiles\Adobe\Acrobat DC\Acrobat\Acrobat.exe"
"${env:ProgramFiles(x86)}\Adobe\Acrobat DC\Acrobat\Acrobat.exe"
"${env:ProgramFiles(x86)}\Adobe\Acrobat Reader DC\Reader\AcroRd32.exe"
"$env:ProgramFiles\Adobe\Acrobat Reader DC\Reader\AcroRd32.exe"
"${env:ProgramFiles(x86)}\Adobe\Reader\Reader\AcroRd32.exe"
)
$acroExe = $acroPaths | Where-Object { Test-Path $_ } | Select-Object -First 1
if (-not $acroExe) { exit 0 }
$progId = "AcroExch.Document.DC"
$openCmd = "`"$acroExe`" `"%1`""
# HKCR\.pdf
if (-not (Test-Path "HKCR:\.pdf")) { New-Item -Path "HKCR:\.pdf" -Force | Out-Null }
$current = (Get-ItemProperty -Path "HKCR:\.pdf" -Name "(Default)" -ErrorAction SilentlyContinue)."(Default)"
if ($current -ne $progId) {
Set-ItemProperty -Path "HKCR:\.pdf" -Name "(Default)" -Value $progId -Force
}
# HKCR\AcroExch.Document.DC\shell\open\command
$cmdPath = "HKCR:\$progId\shell\open\command"
if (-not (Test-Path $cmdPath)) { New-Item -Path $cmdPath -Force | Out-Null }
Set-ItemProperty -Path $cmdPath -Name "(Default)" -Value $openCmd -Force
'@ | Set-Content -Path $pdfScript -Encoding UTF8 -Force
$pdfAction = New-ScheduledTaskAction -Execute "powershell.exe" `
-Argument "-NonInteractive -WindowStyle Hidden -ExecutionPolicy Bypass -File `"$pdfScript`""
$pdfTrigger = New-ScheduledTaskTrigger -AtLogOn
# Runs as SYSTEM to allow HKCR writes (system-wide file association)
$pdfPrincipal = New-ScheduledTaskPrincipal -UserId "SYSTEM" -RunLevel Highest
$pdfSettings = New-ScheduledTaskSettingsSet -ExecutionTimeLimit (New-TimeSpan -Minutes 2) `
-MultipleInstances IgnoreNew `
-StartWhenAvailable
$pdfTask = New-ScheduledTask -Action $pdfAction `
-Trigger $pdfTrigger `
-Settings $pdfSettings `
-Principal $pdfPrincipal `
-Description "Restore Adobe Reader as default PDF app on logon"
try {
Unregister-ScheduledTask -TaskName "PDF-DefaultApp" -Confirm:$false -ErrorAction SilentlyContinue
Register-ScheduledTask -TaskName "PDF-DefaultApp" -InputObject $pdfTask -Force | Out-Null
Write-Log " Registered task: PDF-DefaultApp" -Level OK
}
catch {
Write-Log " Failed to register task PDF-DefaultApp - $_" -Level ERROR
}
# -----------------------------------------------------------------------
# Task: UnlockStartLayout
# Runs once after deployment to unlock the Start menu layout
# so users can still customize it later
# -----------------------------------------------------------------------
Write-Log "Registering task: UnlockStartLayout" -Level STEP
$unlockScript = "$ScriptDir\UnlockStartLayout.ps1"
@'
# Remove Start layout lock so users can modify it
$layoutXml = "C:\Users\Default\AppData\Local\Microsoft\Windows\Shell\LayoutModification.xml"
if (Test-Path $layoutXml) {
Remove-Item $layoutXml -Force -ErrorAction SilentlyContinue
}
# Unregister self after running once
Unregister-ScheduledTask -TaskName "UnlockStartLayout" -Confirm:$false -ErrorAction SilentlyContinue
'@ | Set-Content -Path $unlockScript -Encoding UTF8 -Force
$unlockAction = New-ScheduledTaskAction -Execute "powershell.exe" `
-Argument "-NonInteractive -WindowStyle Hidden -ExecutionPolicy Bypass -File `"$unlockScript`""
# Trigger: 5 minutes after system startup, once
$unlockTrigger = New-ScheduledTaskTrigger -AtStartup
$unlockTrigger.Delay = "PT5M"
$unlockPrincipal = New-ScheduledTaskPrincipal -UserId "SYSTEM" -RunLevel Highest
$unlockSettings = New-ScheduledTaskSettingsSet -ExecutionTimeLimit (New-TimeSpan -Minutes 10) `
-StartWhenAvailable
$unlockTask = New-ScheduledTask -Action $unlockAction `
-Trigger $unlockTrigger `
-Settings $unlockSettings `
-Principal $unlockPrincipal `
-Description "Unlock Start menu layout 5 min after first boot"
try {
Unregister-ScheduledTask -TaskName "UnlockStartLayout" -Confirm:$false -ErrorAction SilentlyContinue
Register-ScheduledTask -TaskName "UnlockStartLayout" -InputObject $unlockTask -Force | Out-Null
Write-Log " Registered task: UnlockStartLayout" -Level OK
}
catch {
Write-Log " Failed to register task UnlockStartLayout - $_" -Level ERROR
}
Write-Log "Step 6 complete" -Level OK

View file

@ -16,18 +16,12 @@
07-desktop-info-ps1-smazat-nahrazeno: 07-desktop-info.ps1 is superseded by this script. BackInfo.exe is the preferred approach - stable on Win10 and Win11, configurable via INI, already present in assets. 07-desktop-info-ps1-smazat-nahrazeno: 07-desktop-info.ps1 is superseded by this script. BackInfo.exe is the preferred approach - stable on Win10 and Win11, configurable via INI, already present in assets.
#> #>
param( param(
[object]$Config, [string]$ConfigPath,
[string]$LogFile [string]$LogFile
) )
$ErrorActionPreference = "Continue" . "$PSScriptRoot\common.ps1"
$Config = Load-Config $ConfigPath
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
}
# ----------------------------------------------------------------------- # -----------------------------------------------------------------------
# Copy BackInfo assets to Program Files # Copy BackInfo assets to Program Files

View file

@ -1,253 +0,0 @@
<#
.SYNOPSIS
DEPRECATED - delete this script. Replaced by BackInfo.exe.
.DESCRIPTION
Original custom PowerShell approach to render system info onto the desktop wallpaper
using WPF (System.Windows.Media / System.Drawing). Superseded by BackInfo.exe which
is already present in assets/Backinfo/ and handles Win10/Win11 natively.
ACTION REQUIRED: Delete this file. Add a BackInfo deployment step to the master script.
.ITEMS
07-desktop-info-ps1-smazat-stary-pristup: DELETE THIS FILE. The WPF rendering approach had compatibility issues on some Windows editions and required maintaining complex PS rendering code. BackInfo.exe is a mature, stable replacement already bundled in assets/Backinfo/.
zkopirovat-assets-backinfo-do-c-program-: NEW STEP (in master script): Copy assets/Backinfo/ to C:\Program Files\Backinfo\ on the target machine. Includes BackInfo.exe, BackInfo.ini (display config), and backinfo_W11.ps1 (setup helper).
spustit-backinfo-w11-ps1-detekce-os-regi: Run backinfo_W11.ps1 after file copy. Detects Win10 vs Win11, writes the required registry key for wallpaper rendering compatibility, and creates a Startup shortcut in the All Users Startup folder.
backinfo-exe-v-assets-backinfo-k-dispozi: BackInfo.exe reads BackInfo.ini on each run. INI configures: font size and family, position of each info block, which data sources to show (hostname, username, OS version, CPU, RAM, disk, IP address, domain).
backinfo-auto-start-pri-kazdem-logonu-vi: The Startup shortcut created by backinfo_W11.ps1 ensures BackInfo.exe runs on every user logon. It re-reads live system data each time, so the wallpaper BMP always shows current information (username changes, IP changes, etc.).
#>
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
}
$ScriptDir = "C:\Windows\Setup\Scripts"
$RenderScript = "$ScriptDir\DesktopInfo-Render.ps1"
$BmpPath = "$ScriptDir\desktopinfo.bmp"
if (-not (Test-Path $ScriptDir)) {
New-Item -ItemType Directory -Path $ScriptDir -Force | Out-Null
}
# -----------------------------------------------------------------------
# Write the rendering script (runs on every logon as the user)
# Layout: hostname (large bold, centered), then detail lines centered
# -----------------------------------------------------------------------
Write-Log "Writing DesktopInfo render script to $RenderScript" -Level INFO
$renderContent = @'
# DesktopInfo-Render.ps1
# Collects system info and renders it centered on the desktop wallpaper.
# Runs on every user logon via Scheduled Task.
$ErrorActionPreference = "Continue"
$LogFile = "C:\Windows\Setup\Scripts\desktopinfo.log"
function Write-Log {
param([string]$Message, [string]$Level = "INFO")
Add-Content -Path $LogFile -Value "[$(Get-Date -Format 'HH:mm:ss')] [$Level] $Message" -Encoding UTF8
}
Write-Log "DesktopInfo render started" -Level INFO
Add-Type -AssemblyName System.Drawing
Add-Type -AssemblyName System.Windows.Forms
Add-Type -TypeDefinition @"
using System;
using System.Runtime.InteropServices;
public class WallpaperApi {
[DllImport("user32.dll", CharSet=CharSet.Auto)]
public static extern int SystemParametersInfo(int uAction, int uParam, string lpvParam, int fuWinIni);
}
"@ -ErrorAction SilentlyContinue
# -----------------------------------------------------------------------
# Collect system info
# -----------------------------------------------------------------------
Write-Log "Collecting system info"
$hostname = $env:COMPUTERNAME
$userDomain = $env:USERDOMAIN
$userName = $env:USERNAME
$loggedUser = if ($userDomain -and $userDomain -ne $hostname) { "$userDomain\$userName" } else { "$hostname\$userName" }
$osInfo = Get-CimInstance Win32_OperatingSystem -ErrorAction SilentlyContinue
$osName = if ($osInfo) { $osInfo.Caption -replace "^Microsoft\s*", "" } else { "Windows" }
$ramGB = if ($osInfo) { [math]::Round($osInfo.TotalVisibleMemorySize / 1024 / 1024, 1) } else { "?" }
$cpuInfo = Get-CimInstance Win32_Processor -ErrorAction SilentlyContinue | Select-Object -First 1
$cpuCount = if ($cpuInfo) { $cpuInfo.NumberOfLogicalProcessors } else { "?" }
$cpuSpeed = if ($cpuInfo) { $cpuInfo.MaxClockSpeed } else { "?" }
$ips = (Get-NetIPAddress -AddressFamily IPv4 -ErrorAction SilentlyContinue |
Where-Object { $_.IPAddress -ne "127.0.0.1" -and $_.PrefixOrigin -ne "WellKnown" } |
Select-Object -ExpandProperty IPAddress) -join ", "
if (-not $ips) { $ips = "N/A" }
$csInfo = Get-CimInstance Win32_ComputerSystem -ErrorAction SilentlyContinue
$domain = if ($csInfo -and $csInfo.PartOfDomain) { $csInfo.Domain } `
elseif ($csInfo -and $csInfo.Workgroup) { $csInfo.Workgroup.ToLower() } `
else { "N/A" }
Write-Log "hostname=$hostname user=$loggedUser os=$osName ram=$($ramGB)GB cpu=${cpuCount}x${cpuSpeed}MHz ips=$ips domain=$domain"
# -----------------------------------------------------------------------
# Screen dimensions
# -----------------------------------------------------------------------
$screen = [System.Windows.Forms.Screen]::PrimaryScreen
$width = if ($screen) { $screen.Bounds.Width } else { 1920 }
$height = if ($screen) { $screen.Bounds.Height } else { 1080 }
Write-Log "screen=${width}x${height}"
# -----------------------------------------------------------------------
# Create bitmap and graphics context
# -----------------------------------------------------------------------
$bmp = New-Object System.Drawing.Bitmap($width, $height)
$g = [System.Drawing.Graphics]::FromImage($bmp)
$g.TextRenderingHint = [System.Drawing.Text.TextRenderingHint]::AntiAlias
$g.Clear([System.Drawing.ColorTranslator]::FromHtml("#556364"))
# -----------------------------------------------------------------------
# Fonts and brushes
# -----------------------------------------------------------------------
$fontName = "Segoe UI"
$fontTitle = New-Object System.Drawing.Font($fontName, 36, [System.Drawing.FontStyle]::Bold)
$fontBold = New-Object System.Drawing.Font($fontName, 14, [System.Drawing.FontStyle]::Bold)
$fontReg = New-Object System.Drawing.Font($fontName, 14, [System.Drawing.FontStyle]::Regular)
$brushWhite = New-Object System.Drawing.SolidBrush([System.Drawing.Color]::White)
$brushGray = New-Object System.Drawing.SolidBrush([System.Drawing.ColorTranslator]::FromHtml("#C8D2D2"))
# -----------------------------------------------------------------------
# Lines: text, font, brush
# -----------------------------------------------------------------------
$texts = @(
$hostname
"Logged on user: $loggedUser"
"OS: $osName"
"CPU: $cpuCount at $cpuSpeed MHz RAM: $($ramGB)GB"
"IPv4 address: $ips Machine domain: $domain"
)
$fonts = @( $fontTitle, $fontReg, $fontBold, $fontReg, $fontReg )
$brushes = @( $brushWhite, $brushGray, $brushGray, $brushGray, $brushGray )
# -----------------------------------------------------------------------
# Measure total block height, then center vertically
# -----------------------------------------------------------------------
$lineSpacing = 8
$heights = @()
for ($i = 0; $i -lt $texts.Count; $i++) {
$heights += [int]($g.MeasureString($texts[$i], $fonts[$i]).Height)
}
$totalH = ($heights | Measure-Object -Sum).Sum + $lineSpacing * ($texts.Count - 1)
$currentY = [int](($height - $totalH) / 2)
# -----------------------------------------------------------------------
# Draw each line centered horizontally
# -----------------------------------------------------------------------
for ($i = 0; $i -lt $texts.Count; $i++) {
$sz = $g.MeasureString($texts[$i], $fonts[$i])
$x = [int](($width - $sz.Width) / 2)
$g.DrawString($texts[$i], $fonts[$i], $brushes[$i], [float]$x, [float]$currentY)
$currentY += $heights[$i] + $lineSpacing
}
$g.Dispose()
# -----------------------------------------------------------------------
# Save and set as wallpaper
# -----------------------------------------------------------------------
$bmpPath = "C:\Windows\Setup\Scripts\desktopinfo.bmp"
Write-Log "Saving BMP: $bmpPath"
$bmp.Save($bmpPath, [System.Drawing.Imaging.ImageFormat]::Bmp)
$bmp.Dispose()
# Clear Windows wallpaper cache so it reloads from our BMP
# Without this, Windows reuses TranscodedWallpaper and ignores the updated file
$transcodedPath = "$env:APPDATA\Microsoft\Windows\Themes\TranscodedWallpaper"
if (Test-Path $transcodedPath) {
Remove-Item $transcodedPath -Force -ErrorAction SilentlyContinue
Write-Log "Cleared TranscodedWallpaper cache"
}
# SPI_SETDESKTOPWALLPAPER=20, SPIF_UPDATEINIFILE|SPIF_SENDCHANGE=3
$result = [WallpaperApi]::SystemParametersInfo(20, 0, $bmpPath, 3)
Write-Log "SystemParametersInfo result: $result"
Write-Log "DesktopInfo render complete" -Level INFO
'@
$renderContent | Set-Content -Path $RenderScript -Encoding UTF8 -Force
Write-Log "Render script written" -Level OK
# -----------------------------------------------------------------------
# Store deployment date in registry (used for reference)
# -----------------------------------------------------------------------
Write-Log "Storing deployment date in registry" -Level INFO
try {
if (-not (Test-Path "HKLM:\SOFTWARE\X9\Deployment")) {
New-Item -Path "HKLM:\SOFTWARE\X9\Deployment" -Force | Out-Null
}
$existingDate = (Get-ItemProperty -Path "HKLM:\SOFTWARE\X9\Deployment" `
-Name "DeployDate" -ErrorAction SilentlyContinue).DeployDate
if (-not $existingDate) {
Set-ItemProperty -Path "HKLM:\SOFTWARE\X9\Deployment" `
-Name "DeployDate" `
-Value (Get-Date -Format "yyyy-MM-dd") `
-Force
Write-Log " DeployDate set: $(Get-Date -Format 'yyyy-MM-dd')" -Level OK
} else {
Write-Log " DeployDate already set: $existingDate" -Level INFO
}
}
catch {
Write-Log " Failed to set DeployDate: $_" -Level ERROR
}
# -----------------------------------------------------------------------
# Register scheduled task: DesktopInfo
# Runs the render script on every user logon
# -----------------------------------------------------------------------
Write-Log "Registering task: DesktopInfo" -Level STEP
try {
Unregister-ScheduledTask -TaskName "DesktopInfo" -Confirm:$false -ErrorAction SilentlyContinue
$action = New-ScheduledTaskAction -Execute "powershell.exe" `
-Argument "-NonInteractive -WindowStyle Hidden -ExecutionPolicy Bypass -File `"$RenderScript`""
$trigger = New-ScheduledTaskTrigger -AtLogOn
$trigger.Delay = "PT20S" # wait for network to be available
$settings = New-ScheduledTaskSettingsSet -ExecutionTimeLimit (New-TimeSpan -Minutes 2) `
-MultipleInstances IgnoreNew `
-StartWhenAvailable
$principal = New-ScheduledTaskPrincipal -GroupId "Users" -RunLevel Limited
$task = New-ScheduledTask -Action $action `
-Trigger $trigger `
-Settings $settings `
-Principal $principal `
-Description "Render system info onto desktop wallpaper on logon"
Register-ScheduledTask -TaskName "DesktopInfo" -InputObject $task -Force | Out-Null
Write-Log "Task DesktopInfo registered" -Level OK
}
catch {
Write-Log "Failed to register DesktopInfo task: $_" -Level ERROR
}
# -----------------------------------------------------------------------
# Run once immediately for current user
# -----------------------------------------------------------------------
Write-Log "Running DesktopInfo render now for current user" -Level INFO
try {
& powershell.exe -NonInteractive -WindowStyle Hidden -ExecutionPolicy Bypass -File $RenderScript
Write-Log "DesktopInfo rendered" -Level OK
}
catch {
Write-Log "DesktopInfo render failed: $_" -Level WARN
}
Write-Log "Step 7 complete" -Level OK

View file

@ -17,18 +17,12 @@
typ-klice-mak-vs-kms-vs-retail: Key type selection depends on client's Microsoft licensing: MAK = volume license key activates online against Microsoft (limited activations), KMS = requires KMS server on network (VLSC subscription), Retail = individual license from Microsoft Store or OEM. typ-klice-mak-vs-kms-vs-retail: Key type selection depends on client's Microsoft licensing: MAK = volume license key activates online against Microsoft (limited activations), KMS = requires KMS server on network (VLSC subscription), Retail = individual license from Microsoft Store or OEM.
#> #>
param( param(
[object]$Config, [string]$ConfigPath,
[string]$LogFile [string]$LogFile
) )
$ErrorActionPreference = "Continue" . "$PSScriptRoot\common.ps1"
$Config = Load-Config $ConfigPath
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
}
# ----------------------------------------------------------------------- # -----------------------------------------------------------------------
# KMS Generic Volume License Keys (GVLK) # KMS Generic Volume License Keys (GVLK)

View file

@ -17,18 +17,12 @@
cx9-vlastni-ikonka-desktop-ini: Copies X9-ikona.ico to C:\X9\ and creates Desktop.ini with IconResource entry. Sets System+Hidden attributes on Desktop.ini and ReadOnly on C:\X9\ so Explorer displays the custom folder icon. cx9-vlastni-ikonka-desktop-ini: Copies X9-ikona.ico to C:\X9\ and creates Desktop.ini with IconResource entry. Sets System+Hidden attributes on Desktop.ini and ReadOnly on C:\X9\ so Explorer displays the custom folder icon.
#> #>
param( param(
[object]$Config, [string]$ConfigPath,
[string]$LogFile [string]$LogFile
) )
$ErrorActionPreference = "Continue" . "$PSScriptRoot\common.ps1"
$Config = Load-Config $ConfigPath
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
}
# ----------------------------------------------------------------------- # -----------------------------------------------------------------------
# C:\X9 directory structure # C:\X9 directory structure
@ -117,6 +111,7 @@ if ($Config -and $Config.deployment -and $Config.deployment.pcName) {
$pcName = $Config.deployment.pcName.Trim() $pcName = $Config.deployment.pcName.Trim()
} }
$renamed = $false
if ($pcName -and $pcName -ne "") { if ($pcName -and $pcName -ne "") {
$currentName = $env:COMPUTERNAME $currentName = $env:COMPUTERNAME
if ($currentName -eq $pcName) { if ($currentName -eq $pcName) {
@ -126,6 +121,7 @@ if ($pcName -and $pcName -ne "") {
try { try {
Rename-Computer -NewName $pcName -Force -ErrorAction Stop Rename-Computer -NewName $pcName -Force -ErrorAction Stop
Write-Log " Computer renamed to '$pcName' (restart required)" -Level OK Write-Log " Computer renamed to '$pcName' (restart required)" -Level OK
$renamed = $true
} }
catch { catch {
Write-Log " Failed to rename computer: $_" -Level ERROR Write-Log " Failed to rename computer: $_" -Level ERROR
@ -136,3 +132,9 @@ if ($pcName -and $pcName -ne "") {
} }
Write-Log "Step 9 complete" -Level OK Write-Log "Step 9 complete" -Level OK
# Signal reboot only when rename actually happened
if ($renamed) {
Write-Log "Step 9 - reboot required for rename (exit 9)" -Level OK
exit 9
}

View file

@ -15,18 +15,12 @@
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 (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.
#> #>
param( param(
[object]$Config, [string]$ConfigPath,
[string]$LogFile [string]$LogFile
) )
$ErrorActionPreference = "Continue" . "$PSScriptRoot\common.ps1"
$Config = Load-Config $ConfigPath
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
}
# ----------------------------------------------------------------------- # -----------------------------------------------------------------------
# Set network profiles to Private # Set network profiles to Private

View file

@ -17,37 +17,12 @@
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. 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.
#> #>
param( param(
[object]$Config, [string]$ConfigPath,
[string]$LogFile [string]$LogFile
) )
$ErrorActionPreference = "Continue" . "$PSScriptRoot\common.ps1"
$Config = Load-Config $ConfigPath
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
switch ($Level) {
"OK" { Write-Host $line -ForegroundColor Green }
"ERROR" { Write-Host $line -ForegroundColor Red }
"WARN" { Write-Host $line -ForegroundColor Yellow }
"STEP" { Write-Host $line -ForegroundColor Cyan }
default { Write-Host $line }
}
}
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 }
}
# ----------------------------------------------------------------------- # -----------------------------------------------------------------------
# Detect Dell hardware # Detect Dell hardware

View file

@ -18,19 +18,12 @@
spustit-kolo-windows-update: One update pass without reboot. Exits 9 when updates were applied (more rounds needed). Exits 0 when system is fully up to date. spustit-kolo-windows-update: One update pass without reboot. Exits 9 when updates were applied (more rounds needed). Exits 0 when system is fully up to date.
#> #>
param( param(
[object]$Config, [string]$ConfigPath,
[string]$LogFile [string]$LogFile
) )
$ErrorActionPreference = "Continue" . "$PSScriptRoot\common.ps1"
$Config = Load-Config $ConfigPath
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 Write-Log "=== Step 12 - Windows Update ===" -Level STEP

44
scripts/common.ps1 Normal file
View file

@ -0,0 +1,44 @@
# common.ps1 - shared functions for all deployment scripts
# Dot-source at the top of each script: . "$PSScriptRoot\common.ps1"
# Requires $LogFile variable set in the calling script's scope.
$ErrorActionPreference = "Continue"
function Write-Log {
param([string]$Message, [string]$Level = "INFO")
$line = "[$(Get-Date -Format 'HH:mm:ss')] [$Level] $Message"
if ($LogFile) {
$null = New-Item -ItemType Directory -Force -Path (Split-Path $LogFile -Parent) -ErrorAction SilentlyContinue
Add-Content -Path $LogFile -Value $line -Encoding UTF8
}
Write-Output $line
}
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 }
}
function Load-Config {
param([string]$Path)
if (-not $Path -or -not (Test-Path $Path)) {
Write-Log "No config file at: $Path" -Level WARN
return $null
}
try {
$cfg = Get-Content $Path -Raw -Encoding UTF8 | ConvertFrom-Json
Write-Log "Config loaded from $Path" -Level INFO
return $cfg
}
catch {
Write-Log "Failed to parse config: $_" -Level ERROR
return $null
}
}

View file

@ -99,7 +99,6 @@ Test-Check "Windows activated" {
Write-Host "" Write-Host ""
Write-Host "--- Software ---" Write-Host "--- Software ---"
Test-Check "7-Zip installed" { Test-Check "7-Zip installed" {
(Get-AppxPackage -Name "7zip.7zip" -ErrorAction SilentlyContinue) -or
(Test-Path "${env:ProgramFiles}\7-Zip\7z.exe") -or (Test-Path "${env:ProgramFiles}\7-Zip\7z.exe") -or
(Test-Path "${env:ProgramFiles(x86)}\7-Zip\7z.exe") (Test-Path "${env:ProgramFiles(x86)}\7-Zip\7z.exe")
} }
@ -117,6 +116,24 @@ Test-Check "OpenVPN Connect installed" {
-ErrorAction SilentlyContinue | Where-Object { $_.DisplayName -like "OpenVPN*" }) -ErrorAction SilentlyContinue | Where-Object { $_.DisplayName -like "OpenVPN*" })
} -WarnOnly } -WarnOnly
Test-Check "Atera agent installed" {
(Test-Path "$env:ProgramFiles\ATERA Networks\AteraAgent\AteraAgent.exe") -or
(Test-Path "${env:ProgramFiles(x86)}\ATERA Networks\AteraAgent\AteraAgent.exe")
} -WarnOnly
# -----------------------------------------------------------------------
# PDF default
# -----------------------------------------------------------------------
Write-Host ""
Write-Host "--- PDF default ---"
Test-Check "HKCR .pdf set to AcroExch" {
if (-not (Get-PSDrive -Name HKCR -ErrorAction SilentlyContinue)) {
New-PSDrive -Name HKCR -PSProvider Registry -Root HKEY_CLASSES_ROOT | Out-Null
}
$val = (Get-ItemProperty -Path "HKCR:\.pdf" -Name "(Default)" -ErrorAction SilentlyContinue)."(Default)"
$val -eq "AcroExch.Document.DC"
} -WarnOnly
# ----------------------------------------------------------------------- # -----------------------------------------------------------------------
# Bloatware # Bloatware
# ----------------------------------------------------------------------- # -----------------------------------------------------------------------
@ -166,10 +183,6 @@ Test-Check "Edge First Run hidden" {
(Get-RegValue "HKLM:\SOFTWARE\Policies\Microsoft\Edge" "HideFirstRunExperience") -eq 1 (Get-RegValue "HKLM:\SOFTWARE\Policies\Microsoft\Edge" "HideFirstRunExperience") -eq 1
} }
Test-Check "OneDrive disabled via policy" {
(Get-RegValue "HKLM:\SOFTWARE\Policies\Microsoft\Windows\OneDrive" "DisableFileSyncNGSC") -eq 1
}
Test-Check "GameDVR disabled" { Test-Check "GameDVR disabled" {
(Get-RegValue "HKLM:\SOFTWARE\Policies\Microsoft\Windows\GameDVR" "AllowGameDVR") -eq 0 (Get-RegValue "HKLM:\SOFTWARE\Policies\Microsoft\Windows\GameDVR" "AllowGameDVR") -eq 0
} }
@ -178,12 +191,17 @@ Test-Check "Time zone set" {
(Get-TimeZone).Id -eq "Central Europe Standard Time" (Get-TimeZone).Id -eq "Central Europe Standard Time"
} }
Test-Check "Deployment date in registry" { Test-Check "Standby timeout AC = 0 (never)" {
(Get-RegValue "HKLM:\SOFTWARE\X9\Deployment" "DeployDate") -ne $null $val = & powercfg /query SCHEME_CURRENT SUB_SLEEP STANDBYIDLE 2>&1 | Select-String "Current AC Power Setting Index"
} $val -match "0x00000000"
} -WarnOnly
Test-Check "WPAD proxy disabled" {
(Get-RegValue "HKLM:\SOFTWARE\Policies\Microsoft\Windows\CurrentVersion\Internet Settings" "AutoDetect") -eq 0
} -WarnOnly
# ----------------------------------------------------------------------- # -----------------------------------------------------------------------
# Current user (HKCU) - personalization # Current user (HKCU) - profile + personalization
# ----------------------------------------------------------------------- # -----------------------------------------------------------------------
Write-Host "" Write-Host ""
Write-Host "--- User settings (current user) ---" Write-Host "--- User settings (current user) ---"
@ -211,41 +229,60 @@ Test-Check "File extensions visible" {
Test-Check "Explorer opens to This PC" { Test-Check "Explorer opens to This PC" {
(Get-RegValue "HKCU:\Software\Microsoft\Windows\CurrentVersion\Explorer\Advanced" "LaunchTo") -eq 1 (Get-RegValue "HKCU:\Software\Microsoft\Windows\CurrentVersion\Explorer\Advanced" "LaunchTo") -eq 1
} }
Test-Check "This PC icon on desktop" { Test-Check "This PC icon on desktop" {
(Get-RegValue "HKCU:\Software\Microsoft\Windows\CurrentVersion\Explorer\HideDesktopIcons\NewStartPanel" "{20D04FE0-3AEA-1069-A2D8-08002B30309D}") -eq 0 (Get-RegValue "HKCU:\Software\Microsoft\Windows\CurrentVersion\Explorer\HideDesktopIcons\NewStartPanel" "{20D04FE0-3AEA-1069-A2D8-08002B30309D}") -eq 0
} }
Test-Check "Start menu Recommended section hidden" {
Test-Check "Start menu Recommended hidden" {
(Get-RegValue "HKLM:\SOFTWARE\Policies\Microsoft\Windows\Explorer" "HideRecommendedSection") -eq 1 (Get-RegValue "HKLM:\SOFTWARE\Policies\Microsoft\Windows\Explorer" "HideRecommendedSection") -eq 1
} }
Test-Check "Start menu recently added hidden" { Test-Check "Start menu recently added hidden" {
(Get-RegValue "HKCU:\Software\Microsoft\Windows\CurrentVersion\Explorer\Advanced" "Start_TrackProgs") -eq 0 (Get-RegValue "HKCU:\Software\Microsoft\Windows\CurrentVersion\Explorer\Advanced" "Start_TrackProgs") -eq 0
} }
# ----------------------------------------------------------------------- # -----------------------------------------------------------------------
# Scheduled tasks # BackInfo
# ----------------------------------------------------------------------- # -----------------------------------------------------------------------
Write-Host "" Write-Host ""
Write-Host "--- Scheduled tasks ---" Write-Host "--- BackInfo ---"
$tasks = @("ShowAllTrayIcons", "PDF-DefaultApp", "DesktopInfo", "UnlockStartLayout") Test-Check "BackInfo.exe deployed" {
foreach ($t in $tasks) { Test-Path "C:\Program Files\Backinfo\BackInfo.exe"
Test-Check "Task registered: $t" { }
Get-ScheduledTask -TaskName $t -ErrorAction SilentlyContinue
} Test-Check "BackInfo startup shortcut" {
Test-Path "C:\ProgramData\Microsoft\Windows\Start Menu\Programs\StartUp\BackInfo.lnk"
}
Test-Check "BackInfo OSName registry" {
(Get-RegValue "HKLM:\SOFTWARE\BackInfo" "OSName") -ne $null
} }
# ----------------------------------------------------------------------- # -----------------------------------------------------------------------
# DesktopInfo # Network
# ----------------------------------------------------------------------- # -----------------------------------------------------------------------
Write-Host "" Write-Host ""
Write-Host "--- DesktopInfo ---" Write-Host "--- Network ---"
Test-Check "Render script exists" { Test-Check "Network profile Private" {
Test-Path "C:\Windows\Setup\Scripts\DesktopInfo-Render.ps1" $profiles = Get-NetConnectionProfile -ErrorAction SilentlyContinue
-not ($profiles | Where-Object { $_.NetworkCategory -ne "Private" })
} -WarnOnly
# -----------------------------------------------------------------------
# C:\X9 directory
# -----------------------------------------------------------------------
Write-Host ""
Write-Host "--- PC identity ---"
Test-Check "C:\\X9 directory exists" {
Test-Path "C:\X9"
} }
Test-Check "BMP file exists" { Test-Check "C:\\X9 has custom icon" {
Test-Path "C:\Windows\Setup\Scripts\desktopinfo.bmp" Test-Path "C:\X9\desktop.ini"
} -WarnOnly } -WarnOnly
# ----------------------------------------------------------------------- # -----------------------------------------------------------------------