Files
pxe-server/playbook/shopfloor-setup/common/scripts/Set-EventSaverScreensaver.ps1
cproudlock 54cbe6b5d6 Bring the share's common scripts under version control
Sixteen files that run on every shopfloor PC existed only on the SFLD share.
The cost showed up while debugging the NTLARS backup: the script that posts to
ShopDB could not be read, reviewed or diffed, so its behaviour was inferred
from log output for most of a day. It turned out to hold a silent fallback that
had been governing the whole fleet for months.

Imported as-is from tsgwp00525-v2, no edits:

  lib/ShopdbBackupClient.psm1        the shared backup client
  scripts/Backup-NtlarsSettings.ps1  converted to use it
  scripts/Set-ShopdbCollectorKey.ps1 collector credential delivery
  scripts/Test-RegExport.ps1         exercises the .reg codec with mocks
  scripts/Set-EventSaver*.ps1        kiosk power / screensaver / disable
  scripts/Setup-OpenText.*           OpenText install + toolbar
  scripts/Migrate-PCType.ps1, Select-KioskType.ps1, Set-FmsHostsEntry.ps1,
  scripts/ensure-vnc-firewall.ps1, Install-AcroReader.cmd, Install-Oracle11r2.cmd

lib/Install-FromManifest.ps1 is also updated from the share, which was 37 lines
AHEAD of this repo and purely additive: the Add-EnforceResult reporting added
during the kiosk API cutover, done live and never committed back. Nothing was
removed.

Checked for embedded secrets before committing; there are none.
Set-ShopdbCollectorKey deliberately reads its token from a sibling file on the
share rather than holding it, so the script is safe to track.

The share remains what actually runs. This makes it reviewable, and makes the
next drift visible as a diff rather than a surprise.
2026-08-11 12:36:38 -04:00

124 lines
5.3 KiB
PowerShell
Executable File

# Set-EventSaverScreensaver.ps1
#
# Enable the EventSaver shopfloor screensaver for EVERY user on the box. Runs
# under GE-Enforce (SYSTEM) every cycle.
#
# WHY THIS WAS REWRITTEN (2026-08-06)
# The previous version wrote the timeout to exactly two places: HKU\.DEFAULT,
# which only seeds profiles created AFTERWARDS, and the hive of one profile
# whose folder had to be named literally 'Shopfloor'. On any PC where the
# operator signs in as anything else, no HKCU was ever touched - the screensaver
# then ran on whatever the profile already carried (a domain default, commonly
# 120 seconds), while GE-Enforce reported success every cycle because from its
# point of view it had done its job.
#
# That is what the "screensaver after 2 minutes instead of 9" reports were: the
# manifest said 480 and the machines had never been told.
#
# Now: seed .DEFAULT for future profiles, then apply to EVERY loaded user hive.
# Same approach Set-DisplayAlwaysOn.ps1 already uses for the kiosks. A user who
# signs in between cycles is picked up on the next one.
#
# IDEMPOTENT + SILENT: hives already correct are skipped, so the common path
# writes nothing.
[CmdletBinding()]
param(
[string]$ScrPath = 'C:\Windows\System32\EventSaver.scr',
[int] $TimeoutSeconds = 540,
# Retired. Kept so an older manifest passing -TargetUser does not fail to
# bind; it is deliberately ignored - targeting one named account is the bug
# this rewrite removes.
[string]$TargetUser = '',
[string]$TaskName = 'EventSaver-Enable'
)
$ErrorActionPreference = 'Continue'
$logDir = 'C:\Logs\Shopfloor'
if (-not (Test-Path $logDir)) { New-Item -ItemType Directory -Path $logDir -Force | Out-Null }
$log = Join-Path $logDir 'eventsaver.log'
function Write-Log($m) {
Add-Content -LiteralPath $log -Value ("{0} {1}" -f (Get-Date -Format 'yyyy-MM-dd HH:mm:ss'), $m)
}
function Get-Val($deskKey, $name) {
return (Get-ItemProperty -Path $deskKey -Name $name -ErrorAction SilentlyContinue).$name
}
# Already what we want? Idempotency gate - keeps the common path silent.
function Saver-IsSet($deskKey) {
if (-not (Test-Path $deskKey)) { return $false }
if ((Get-Val $deskKey 'ScreenSaveActive') -ne '1') { return $false }
if ((Get-Val $deskKey 'SCRNSAVE.EXE') -ne $ScrPath) { return $false }
if ("$((Get-Val $deskKey 'ScreenSaveTimeOut'))" -ne "$TimeoutSeconds") { return $false }
return $true
}
function Set-SaverValues($deskKey) {
if (-not (Test-Path $deskKey)) { New-Item -Path $deskKey -Force | Out-Null }
Set-ItemProperty -Path $deskKey -Name 'ScreenSaveActive' -Value '1' -Type String -Force
Set-ItemProperty -Path $deskKey -Name 'SCRNSAVE.EXE' -Value $ScrPath -Type String -Force
Set-ItemProperty -Path $deskKey -Name 'ScreenSaveTimeOut' -Value "$TimeoutSeconds" -Type String -Force
Set-ItemProperty -Path $deskKey -Name 'ScreenSaverIsSecure' -Value '0' -Type String -Force
}
# --- 1. seed .DEFAULT so profiles created later start correct -----------------
$defKey = 'Registry::HKEY_USERS\.DEFAULT\Control Panel\Desktop'
if (-not (Saver-IsSet $defKey)) {
try { Set-SaverValues $defKey; Write-Log "seeded .DEFAULT ($TimeoutSeconds s)" }
catch { Write-Log "ERROR seeding .DEFAULT: $_" }
}
# --- 2. apply to every loaded human hive --------------------------------------
# Skipped: the three service accounts (SYSTEM, LOCAL SERVICE, NETWORK SERVICE)
# and the _Classes companions, which are not user desktops and would just add
# noise. Everything else that is loaded belongs to somebody signed in now.
$serviceSids = @('S-1-5-18', 'S-1-5-19', 'S-1-5-20')
$applied = 0
$already = 0
try {
$hives = Get-ChildItem 'Registry::HKEY_USERS' -ErrorAction Stop | ForEach-Object { $_.PSChildName }
} catch {
Write-Log "ERROR enumerating HKEY_USERS: $_"
$hives = @()
}
foreach ($sid in $hives) {
if ($sid -eq '.DEFAULT') { continue } # handled above
if ($sid -like '*_Classes') { continue }
if ($serviceSids -contains $sid) { continue }
if ($sid -notlike 'S-1-5-21-*') { continue } # real domain/local users only
$hiveKey = "Registry::HKEY_USERS\$sid\Control Panel\Desktop"
if (Saver-IsSet $hiveKey) { $already++; continue }
try {
Set-SaverValues $hiveKey
$applied++
Write-Log "applied to hive $sid ($TimeoutSeconds s)"
} catch {
Write-Log "ERROR writing hive ${sid}: $_"
}
}
if ($applied -eq 0 -and $already -eq 0) {
# Nobody signed in - normal during imaging or on an idle bay. .DEFAULT above
# covers the next profile, and the next cycle after a logon covers the rest.
Write-Log 'no user hives loaded; .DEFAULT seeded, will apply on a later cycle'
}
# --- 3. remove the old per-user fallback task ---------------------------------
# The previous version registered an AtLogon task for the hardcoded 'Shopfloor'
# account. On machines where nobody signs in as that, it sat queued forever and
# never fired. Applying to loaded hives every cycle replaces it, so clear any
# that are still registered.
try {
if (Get-ScheduledTask -TaskName $TaskName -ErrorAction SilentlyContinue) {
Unregister-ScheduledTask -TaskName $TaskName -Confirm:$false -ErrorAction SilentlyContinue
Write-Log "removed stale fallback task '$TaskName'"
}
} catch { }
exit 0