# 03-ShellDefaults.ps1 - Shell appearance defaults for all new user profiles. # # Applies the following tweaks so shopfloor PCs look/behave closer to the # Win10 baseline and don't reach out to Bing from the Start menu: # 1. Taskbar aligned to the left (TaskbarAl=0). Per-user setting, written # into the Default User hive so every NEW profile inherits it. # 2. Start menu "Recommended" section hidden (HideRecommendedSection=1). # 3. Web results + Bing search-box suggestions killed in Start/Search. # 4. Cortana disabled via policy (no-op on LTSC 2024 since Cortana isn't # shipped, but set anyway for belt-and-suspenders). # # 2-4 are HKLM policy values - W11 LTSC / Enterprise honour them; Home/Pro # do not. Fine here since the fleet is LTSC 2024. # # Existing profiles (SupportUser, pre-existing end-user accounts) are NOT # modified for TaskbarAl - the Default User hive is a template copied on # profile creation, not a live cascade. The HKLM policies affect everyone. $ErrorActionPreference = 'Continue' $isAdmin = ([Security.Principal.WindowsPrincipal][Security.Principal.WindowsIdentity]::GetCurrent()).IsInRole([Security.Principal.WindowsBuiltInRole]::Administrator) if (-not $isAdmin) { Write-Host "ERROR: 03-ShellDefaults.ps1 must run as Administrator." -ForegroundColor Red exit 1 } # ---- 1. HKLM policy DWORDs (all LTSC-honoured) ------------------------------- # Each entry: KeyPath, ValueName, ValueData. Key is created if missing. $hklmPolicies = @( # Hide Start menu "Recommended" section. @{ Key = 'HKLM:\SOFTWARE\Policies\Microsoft\Windows\Explorer' Name = 'HideRecommendedSection'; Value = 1 } # Kill web results in Start/taskbar search. @{ Key = 'HKLM:\SOFTWARE\Policies\Microsoft\Windows\Windows Search' Name = 'DisableWebSearch'; Value = 1 } @{ Key = 'HKLM:\SOFTWARE\Policies\Microsoft\Windows\Windows Search' Name = 'ConnectedSearchUseWeb'; Value = 0 } # Disable Cortana (policy; LTSC doesn't ship Cortana but this is harmless). @{ Key = 'HKLM:\SOFTWARE\Policies\Microsoft\Windows\Windows Search' Name = 'AllowCortana'; Value = 0 } # Kill Bing-powered search-box suggestions (per-keystroke telemetry). @{ Key = 'HKLM:\SOFTWARE\Policies\Microsoft\Windows\Explorer' Name = 'DisableSearchBoxSuggestions'; Value = 1 } ) foreach ($p in $hklmPolicies) { try { if (-not (Test-Path $p.Key)) { New-Item -Path $p.Key -Force | Out-Null } Set-ItemProperty -Path $p.Key -Name $p.Name -Value $p.Value -Type DWord -Force Write-Host ("Set {0}\{1} = {2}" -f $p.Key, $p.Name, $p.Value) } catch { Write-Warning ("Failed to set {0}\{1}: {2}" -f $p.Key, $p.Name, $_) } } # ---- 2. Set Adobe Acrobat Reader as default PDF viewer ---- # OEMDefaultAssociations.xml is read when a new user profile is created. # Deploying it before ShopFloor's first logon means the profile lands with # Acrobat as the PDF handler instead of Edge. Existing profiles (SupportUser) # are not affected. DISM /import-defaultappassociations writes the XML to # C:\Windows\System32\OEMDefaultAssociations.xml and sets the policy key. $assocXml = @" "@ $assocPath = Join-Path $env:TEMP 'DefaultAssociations.xml' try { Set-Content -Path $assocPath -Value $assocXml -Encoding UTF8 -Force $out = & dism.exe /online /import-defaultappassociations:"$assocPath" 2>&1 if ($LASTEXITCODE -eq 0) { Write-Host "Set .pdf default to Acrobat.Document.DC via DISM" } else { Write-Warning "DISM import-defaultappassociations returned $LASTEXITCODE" } Remove-Item $assocPath -Force -ErrorAction SilentlyContinue } catch { Write-Warning "Failed to set default PDF viewer: $_" } # ---- 3. Taskbar left-align via Default User hive ---- $defaultHive = 'C:\Users\Default\NTUSER.DAT' $mountPoint = 'HKU\SFLDDefault' $regPath = 'Registry::HKEY_USERS\SFLDDefault\Software\Microsoft\Windows\CurrentVersion\Explorer\Advanced' if (-not (Test-Path -LiteralPath $defaultHive)) { Write-Warning "Default User hive not found at $defaultHive - skipping taskbar tweak." exit 0 } # Unload a stale mount from a previous run, if any. reg unload returns # non-zero when nothing is mounted; ignore that. & reg.exe unload $mountPoint *> $null $loadOutput = & reg.exe load $mountPoint $defaultHive 2>&1 if ($LASTEXITCODE -ne 0) { Write-Warning "reg load failed ($LASTEXITCODE): $loadOutput" exit 1 } try { if (-not (Test-Path $regPath)) { New-Item -Path $regPath -Force | Out-Null } Set-ItemProperty -Path $regPath -Name 'TaskbarAl' -Value 0 -Type DWord -Force Write-Host "Set Default User TaskbarAl=0 (left-aligned)" } catch { Write-Warning "Failed to set TaskbarAl: $_" } finally { # Force GC so PowerShell drops its handles on the hive before unload, # otherwise reg unload fails with "The process cannot access the file". [gc]::Collect() [gc]::WaitForPendingFinalizers() [gc]::Collect() & reg.exe unload $mountPoint *> $null if ($LASTEXITCODE -ne 0) { Write-Warning "reg unload returned $LASTEXITCODE - Default User hive may still be mounted" } } exit 0