# Register-ControllerCredentialTask.ps1 - Register a user-context AtLogOn # scheduled task that runs Set-ControllerCredential.ps1 as the logged-in # user (ShopFloor). Credential Manager entries are per-user, so cmdkey /add # must run in the user's session, not SYSTEM. # # GE-Enforce (SYSTEM) runs THIS script via the manifest. It registers the # task once (MarkerFile detection prevents re-registration on subsequent # enforce cycles). The task itself fires at every logon and re-applies the # credential, covering Defender / Intune scrubs between sessions. # # Idempotent: safe to re-run. Existing task is overwritten via -Force. $ErrorActionPreference = 'Continue' $logDir = 'C:\Logs\Shopfloor' if (-not (Test-Path $logDir)) { try { New-Item -Path $logDir -ItemType Directory -Force | Out-Null } catch { $logDir = $env:TEMP } } $logFile = Join-Path $logDir 'register-controller-cred.log' function Write-RegLog { param([string]$Message, [string]$Level = 'INFO') $line = '[{0}] [{1}] {2}' -f (Get-Date -Format 'yyyy-MM-dd HH:mm:ss'), $Level, $Message Add-Content -Path $logFile -Value $line -ErrorAction SilentlyContinue Write-Host $line } Write-RegLog '=== Register-ControllerCredentialTask start ===' $taskName = 'Apply Controller Credential' # The actual cmdkey script lives alongside this registration script on the # SFLD share. GE-Enforce mounts the share as W:, so the script path is # relative to the share root. At task-fire time, however, the share may not # be mounted. Copy the script to a local path so the logon task always works. $localDir = 'C:\Program Files\GE\Shopfloor\controller-cred' $localScript = Join-Path $localDir 'Set-ControllerCredential.ps1' # Resolve the source script. When GE-Enforce runs this, $PSScriptRoot # points to the share-mounted dir (W:\gea-shopfloor-collections\apps\ or # similar). Fall back to the same directory as this script. $sourceScript = Join-Path $PSScriptRoot 'Set-ControllerCredential.ps1' if (-not (Test-Path -LiteralPath $sourceScript)) { Write-RegLog "Set-ControllerCredential.ps1 not found at $sourceScript" 'ERROR' exit 1 } # Stage the script locally. if (-not (Test-Path $localDir)) { New-Item -Path $localDir -ItemType Directory -Force | Out-Null } try { Copy-Item -LiteralPath $sourceScript -Destination $localScript -Force -ErrorAction Stop Write-RegLog "Staged $sourceScript -> $localScript" } catch { Write-RegLog "Failed to copy script locally: $_" 'ERROR' exit 1 } # Register the logon task for BUILTIN\Users (catches ShopFloor + any # interactive user). RunLevel Limited -- no elevation needed for cmdkey. try { $action = New-ScheduledTaskAction ` -Execute 'powershell.exe' ` -Argument "-NoProfile -ExecutionPolicy Bypass -WindowStyle Hidden -File `"$localScript`"" $trigger = New-ScheduledTaskTrigger -AtLogOn $principal = New-ScheduledTaskPrincipal -GroupId 'S-1-5-32-545' -RunLevel Limited $settings = New-ScheduledTaskSettingsSet ` -AllowStartIfOnBatteries ` -DontStopIfGoingOnBatteries ` -StartWhenAvailable ` -ExecutionTimeLimit (New-TimeSpan -Minutes 2) Register-ScheduledTask ` -TaskName $taskName ` -Action $action ` -Trigger $trigger ` -Principal $principal ` -Settings $settings ` -Force ` -ErrorAction Stop | Out-Null Write-RegLog "Registered scheduled task '$taskName' (AtLogOn, BUILTIN\Users, Limited)" } catch { Write-RegLog "FAILED to register '$taskName': $_" 'ERROR' exit 1 } # Write marker file so the manifest's MarkerFile detection prevents # re-running this registration on every enforce cycle. $markerDir = 'C:\ProgramData\GE\Shopfloor\markers' if (-not (Test-Path $markerDir)) { New-Item -Path $markerDir -ItemType Directory -Force | Out-Null } $markerFile = Join-Path $markerDir 'controller-credential-task.marker' Set-Content -Path $markerFile -Value (Get-Date -Format 'yyyy-MM-dd HH:mm:ss') -Force Write-RegLog "Marker written: $markerFile" Write-RegLog '=== Register-ControllerCredentialTask end ===' exit 0