# Set-ControllerCredential.ps1 - Self-heal a Windows Credential Manager # entry for the controller's NIC subnet (default 192.168.1.1). Re-applied # every GE-Enforce cycle so the entry survives any Defender / policy # blowaway between cycles. # # Why: collections bays periodically lose the controller credential from # Credential Manager (cause TBD - suspect Defender / Intune scrub). Without # the cred, controller-side connections need interactive prompts. Restoring # it on each enforce cycle keeps the bay working unattended. # # Wiring: pointed to by gea-shopfloor-collections\manifest.json on the SFLD # share. GE-Enforce calls this directly via the Install-FromManifest PS1 # action type. Idempotent - cmdkey /add overwrites silently if the entry # already exists. # # Edit the three values below to set the actual credential, then push the # manifest entry to the SFLD share (see README in same dir). # # Log: C:\Logs\Shopfloor\controller-credential.log $ErrorActionPreference = 'Continue' # --- EDIT THESE THREE VALUES --- $Target = '192.168.1.1' # Controller IP or hostname $Username = 'CHANGEME' # Controller-side username $Password = 'CHANGEME' # Controller-side password # --- END EDIT --- $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 'controller-credential.log' function Write-CredLog { param([string]$Message, [string]$Level = 'INFO') $line = '[{0}] [{1}] [{2}] {3}' -f (Get-Date -Format 'yyyy-MM-dd HH:mm:ss'), $Level, $env:USERNAME, $Message Add-Content -Path $logFile -Value $line -ErrorAction SilentlyContinue Write-Host $line } Write-CredLog "=== Set-ControllerCredential start (target=$Target) ===" if ($Username -eq 'CHANGEME' -or $Password -eq 'CHANGEME') { Write-CredLog 'Credential placeholders not filled in - refusing to write CHANGEME values' 'ERROR' exit 1 } # Check current state. cmdkey /list output for a missing target returns # 'Currently stored credentials: ... NONE' or omits the target. $listOut = & cmdkey /list:$Target 2>&1 | Out-String if ($listOut -match [regex]::Escape("Target: $Target")) { Write-CredLog "Entry for $Target already present in Credential Manager - re-applying anyway (cmdkey /add updates idempotently)" } else { Write-CredLog "No entry for $Target found in Credential Manager - adding" } # cmdkey /add expects /generic for non-domain creds (SMB / RDP / SQL). # Use /add: for plain network credential (matches the older 'net use' # style cred used by NET shares + most non-AD apps). Switch to /generic: # if the target is HTTP / RDP TERMSRV-specific. & cmdkey /add:$Target /user:$Username /pass:$Password 2>&1 | ForEach-Object { Write-CredLog " cmdkey: $_" } $rc = $LASTEXITCODE if ($rc -eq 0) { Write-CredLog "cmdkey /add succeeded (target=$Target user=$Username)" } else { Write-CredLog "cmdkey /add failed (exit $rc)" 'ERROR' exit $rc } # Quick verify $verify = & cmdkey /list:$Target 2>&1 | Out-String if ($verify -match [regex]::Escape("Target: $Target")) { Write-CredLog 'Verification passed - entry present after add' } else { Write-CredLog 'Verification FAILED - entry not visible after add' 'WARN' } Write-CredLog '=== Set-ControllerCredential end ===' exit 0