# Configure-PC.ps1 - Interactive tool for SupportUser to configure a # shopfloor PC after imaging. Two sections: # # 1. Machine number - if UDC/eDNC are still at placeholder 9999, prompt # to set the real number right now. # # 2. Auto-startup items + machine-number logon prompt - toggle which apps # start automatically for all users, and optionally register a logon # task that prompts STANDARD users for the machine number if it's # still 9999 when they log in (for the case where SupportUser skips # it here and the end user needs to set it themselves). # # Startup .lnk files go in the AllUsers Startup folder: # C:\ProgramData\Microsoft\Windows\Start Menu\Programs\Startup\ # # Run via Configure-PC.bat on the SupportUser desktop. $ErrorActionPreference = 'Continue' # --- Transcript logging --- $logDir = 'C:\Logs\SFLD' if (-not (Test-Path $logDir)) { try { New-Item -ItemType Directory -Path $logDir -Force | Out-Null } catch { $logDir = $env:TEMP } } $transcriptPath = Join-Path $logDir 'Configure-PC.log' try { Start-Transcript -Path $transcriptPath -Append -Force | Out-Null } catch {} Write-Host "Transcript: $transcriptPath" Write-Host "Started: $(Get-Date -Format 'yyyy-MM-dd HH:mm:ss')" Write-Host "Running as: $([System.Security.Principal.WindowsIdentity]::GetCurrent().Name)" $startupDir = 'C:\ProgramData\Microsoft\Windows\Start Menu\Programs\Startup' $publicDesktop = 'C:\Users\Public\Desktop' # ============================================================================ # Helpers # ============================================================================ function Get-UrlFromFile { param([string]$BaseName) $candidates = @( (Join-Path $publicDesktop "$BaseName.url"), (Join-Path (Join-Path $publicDesktop 'Web Links') "$BaseName.url") ) foreach ($c in $candidates) { if (-not (Test-Path -LiteralPath $c)) { continue } try { $content = Get-Content -LiteralPath $c -ErrorAction Stop $urlLine = $content | Where-Object { $_ -match '^URL=' } | Select-Object -First 1 if ($urlLine) { return ($urlLine -replace '^URL=', '').Trim() } } catch {} } return $null } function New-StartupLnk { param( [string]$Name, [string]$Target, [string]$Arguments = '', [string]$WorkingDirectory = '' ) $path = Join-Path $startupDir "$Name.lnk" $wsh = New-Object -ComObject WScript.Shell try { $sc = $wsh.CreateShortcut($path) $sc.TargetPath = $Target if ($Arguments) { $sc.Arguments = $Arguments } if ($WorkingDirectory) { $sc.WorkingDirectory = $WorkingDirectory } elseif ($Target) { $parent = Split-Path -Parent $Target if ($parent) { $sc.WorkingDirectory = $parent } } $sc.Save() return $true } catch { Write-Warning "Failed to create startup shortcut '$Name': $_" return $false } finally { try { [System.Runtime.InteropServices.Marshal]::ReleaseComObject($wsh) | Out-Null } catch {} } } # ============================================================================ # Machine number - read current state # ============================================================================ $udcSettingsPath = 'C:\ProgramData\UDC\udc_settings.json' $udcExePath = 'C:\Program Files\UDC\UDC.exe' $ednRegPath = 'HKLM:\SOFTWARE\WOW6432Node\GE Aircraft Engines\DNC\General' $currentUdc = $null $currentEdnc = $null if (Test-Path $udcSettingsPath) { try { $json = Get-Content $udcSettingsPath -Raw | ConvertFrom-Json $currentUdc = $json.GeneralSettings.MachineNumber } catch {} } if (Test-Path $ednRegPath) { try { $currentEdnc = (Get-ItemProperty -Path $ednRegPath -Name MachineNo -ErrorAction Stop).MachineNo } catch {} } $needsMachineNumber = ($currentUdc -eq '9999' -or $currentEdnc -eq '9999') # ============================================================================ # Edge path (for URL-based startup items) # ============================================================================ $edgePath = @( 'C:\Program Files (x86)\Microsoft\Edge\Application\msedge.exe', 'C:\Program Files\Microsoft\Edge\Application\msedge.exe' ) | Where-Object { Test-Path -LiteralPath $_ } | Select-Object -First 1 # ============================================================================ # Startup item definitions # ============================================================================ $items = @( @{ Num = 1 Label = 'UDC' Detail = 'UDC.exe' Available = (Test-Path 'C:\Program Files\UDC\UDC.exe') CreateLnk = { return (New-StartupLnk -Name 'UDC' -Target 'C:\Program Files\UDC\UDC.exe') } } @{ Num = 2 Label = 'eDNC' Detail = 'DncMain.exe' Available = (Test-Path 'C:\Program Files (x86)\Dnc\bin\DncMain.exe') CreateLnk = { return (New-StartupLnk -Name 'eDNC' -Target 'C:\Program Files (x86)\Dnc\bin\DncMain.exe') } } @{ Num = 3 Label = 'Defect Tracker' Detail = 'ClickOnce app' Available = $true CreateLnk = { $src = @( (Join-Path $publicDesktop 'Defect_Tracker.lnk'), (Join-Path (Join-Path $publicDesktop 'Shopfloor Tools') 'Defect_Tracker.lnk') ) | Where-Object { Test-Path -LiteralPath $_ } | Select-Object -First 1 if ($src) { $dst = Join-Path $startupDir 'Defect Tracker.lnk' try { Copy-Item -LiteralPath $src -Destination $dst -Force; return $true } catch { Write-Warning "Failed to copy Defect Tracker: $_"; return $false } } else { Write-Warning "Defect_Tracker.lnk not found on desktop" return $false } } } @{ Num = 4 Label = 'WJ Shopfloor' Detail = 'HostExplorer session' Available = $true CreateLnk = { $src = @( (Join-Path $publicDesktop 'WJ Shopfloor.lnk'), (Join-Path (Join-Path $publicDesktop 'Shopfloor Tools') 'WJ Shopfloor.lnk') ) | Where-Object { Test-Path -LiteralPath $_ } | Select-Object -First 1 if ($src) { $dst = Join-Path $startupDir 'WJ Shopfloor.lnk' try { Copy-Item -LiteralPath $src -Destination $dst -Force; return $true } catch { Write-Warning "Failed to copy WJ Shopfloor: $_"; return $false } } else { Write-Warning "WJ Shopfloor.lnk not found on desktop" return $false } } } @{ Num = 5 Label = 'Plant Apps' Detail = 'opens in Edge' Available = [bool]$edgePath CreateLnk = { $fallback = 'https://mes-wjefferson.apps.lr.geaerospace.net/run/?app_name=Plant%20Applications' $url = Get-UrlFromFile 'Plant Apps' if (-not $url) { Write-Host " Plant Apps .url not found on desktop, using known URL." $url = $fallback } Write-Host " URL: $url" return (New-StartupLnk -Name 'Plant Apps' -Target $edgePath -Arguments "--new-window `"$url`"") } } ) # Machine-number logon task is item 6 $machineNumTaskName = 'Check Machine Number' # ============================================================================ # Interactive UI # ============================================================================ Clear-Host Write-Host "" Write-Host "========================================" -ForegroundColor Cyan Write-Host " Configure PC" -ForegroundColor Cyan Write-Host "========================================" -ForegroundColor Cyan # --- Section 1: Machine number --- Write-Host "" Write-Host " MACHINE NUMBER" -ForegroundColor Yellow Write-Host " ----------------------------------------" if ($needsMachineNumber) { if ($currentUdc) { Write-Host " UDC : $currentUdc" -ForegroundColor Red } if ($currentEdnc) { Write-Host " eDNC : $currentEdnc" -ForegroundColor Red } Write-Host "" $newNum = Read-Host " Enter new machine number (digits only, Enter to skip)" $newNum = $newNum.Trim() if ($newNum -and $newNum -match '^\d+$') { $updated = @() # Stop UDC before editing its JSON Get-Process UDC -ErrorAction SilentlyContinue | ForEach-Object { try { $_.Kill(); $_.WaitForExit(5000) | Out-Null } catch {} } Start-Sleep -Seconds 1 # UDC JSON if (Test-Path $udcSettingsPath) { try { $json = Get-Content $udcSettingsPath -Raw | ConvertFrom-Json $json.GeneralSettings.MachineNumber = $newNum $json | ConvertTo-Json -Depth 99 | Set-Content -Path $udcSettingsPath -Encoding UTF8 Write-Host " UDC : $currentUdc -> $newNum" -ForegroundColor Green $updated += 'UDC' $currentUdc = $newNum } catch { Write-Warning " UDC update failed: $_" } } # eDNC registry if (Test-Path $ednRegPath) { try { Set-ItemProperty -Path $ednRegPath -Name MachineNo -Value $newNum -Type String -Force Write-Host " eDNC : $currentEdnc -> $newNum" -ForegroundColor Green $updated += 'eDNC' $currentEdnc = $newNum } catch { Write-Warning " eDNC update failed: $_" } } # Relaunch UDC if ((Test-Path $udcExePath) -and $updated -contains 'UDC') { try { Start-Process -FilePath $udcExePath -ArgumentList @('-site', '"West Jefferson"', '-machine', $newNum) Write-Host " UDC.exe relaunched." } catch {} } $needsMachineNumber = ($currentUdc -eq '9999' -or $currentEdnc -eq '9999') } elseif ($newNum) { Write-Host " Invalid (digits only). Skipped." -ForegroundColor Yellow } else { Write-Host " Skipped (still 9999)." -ForegroundColor DarkGray } } else { if ($currentUdc) { Write-Host " UDC : $currentUdc" -ForegroundColor Green } if ($currentEdnc) { Write-Host " eDNC : $currentEdnc" -ForegroundColor Green } } # --- Section 2: Startup items + machine-number logon task --- Write-Host "" Write-Host " AUTO-STARTUP ITEMS" -ForegroundColor Yellow Write-Host " ----------------------------------------" Write-Host " Toggle which items start at user logon:" Write-Host "" $existingStartup = @(Get-ChildItem -LiteralPath $startupDir -Filter '*.lnk' -File -ErrorAction SilentlyContinue | Select-Object -ExpandProperty BaseName) foreach ($item in $items) { $on = if ($existingStartup -contains $item.Label) { '[ON]' } else { '[ ]' } $avail = if ($item.Available) { '' } else { ' (not installed)' } Write-Host " $($item.Num). $on $($item.Label) - $($item.Detail)$avail" } # Item 6: machine number logon prompt $machineNumTaskExists = [bool](Get-ScheduledTask -TaskName $machineNumTaskName -ErrorAction SilentlyContinue) $mnOn = if ($machineNumTaskExists) { '[ON]' } else { '[ ]' } Write-Host " 6. $mnOn Prompt standard user for machine number if 9999" Write-Host "" Write-Host " Enter numbers to toggle (e.g. 1,2,6), Enter to keep current:" $selection = Read-Host " Selection" $selection = $selection.Trim() if ($selection) { $selected = $selection -split '[,\s]+' | Where-Object { $_ -match '^\d+$' } | ForEach-Object { [int]$_ } # Process startup items 1-5 foreach ($item in $items) { if ($selected -notcontains $item.Num) { continue } if (-not $item.Available) { Write-Host " $($item.Label): not installed, skipping" -ForegroundColor DarkGray continue } $existingLnk = Join-Path $startupDir "$($item.Label).lnk" if (Test-Path -LiteralPath $existingLnk) { try { Remove-Item -LiteralPath $existingLnk -Force Write-Host " $($item.Label): REMOVED from startup" -ForegroundColor Yellow } catch { Write-Warning " Failed to remove $($item.Label): $_" } } else { $result = & $item.CreateLnk if ($result) { Write-Host " $($item.Label): ADDED to startup" -ForegroundColor Green } } } # Process item 6: machine number logon task if ($selected -contains 6) { if ($machineNumTaskExists) { # Toggle OFF try { Unregister-ScheduledTask -TaskName $machineNumTaskName -Confirm:$false -ErrorAction Stop Write-Host " Machine number logon prompt: REMOVED" -ForegroundColor Yellow $machineNumTaskExists = $false } catch { Write-Warning " Failed to remove task: $_" } } else { # Toggle ON - register logon task # The task needs to run as the logged-in user (for GUI), but # writing to HKLM + ProgramData requires the ACLs we pre-grant # during imaging (see task 7 / ACL pre-grant script). $scriptDir = Split-Path -Parent $MyInvocation.MyCommand.Path $checkScript = Join-Path $scriptDir 'Check-MachineNumber.ps1' if (-not (Test-Path -LiteralPath $checkScript)) { # Fallback: check enrollment staging dir $checkScript = 'C:\Enrollment\shopfloor-setup\Shopfloor\Check-MachineNumber.ps1' } if (Test-Path -LiteralPath $checkScript) { try { $action = New-ScheduledTaskAction ` -Execute 'powershell.exe' ` -Argument "-NoProfile -ExecutionPolicy Bypass -WindowStyle Normal -File `"$checkScript`"" $trigger = New-ScheduledTaskTrigger -AtLogOn # Run as the logged-in user (needs GUI for InputBox), NOT # SYSTEM (SYSTEM can't show UI to the user's desktop). $principal = New-ScheduledTaskPrincipal ` -GroupId 'S-1-5-32-545' ` -RunLevel Limited $settings = New-ScheduledTaskSettingsSet ` -AllowStartIfOnBatteries ` -DontStopIfGoingOnBatteries ` -StartWhenAvailable ` -ExecutionTimeLimit (New-TimeSpan -Minutes 5) Register-ScheduledTask ` -TaskName $machineNumTaskName ` -Action $action ` -Trigger $trigger ` -Principal $principal ` -Settings $settings ` -Force ` -ErrorAction Stop | Out-Null Write-Host " Machine number logon prompt: ENABLED" -ForegroundColor Green Write-Host " (will auto-disable after machine number is set)" -ForegroundColor DarkGray $machineNumTaskExists = $true } catch { Write-Warning " Failed to register task: $_" } } else { Write-Warning " Check-MachineNumber.ps1 not found at $checkScript" } } } } else { Write-Host " No changes." -ForegroundColor DarkGray } # --- Summary --- Write-Host "" Write-Host " CURRENT STATE" -ForegroundColor Cyan Write-Host " ----------------------------------------" $final = @(Get-ChildItem -LiteralPath $startupDir -Filter '*.lnk' -File -ErrorAction SilentlyContinue | Select-Object -ExpandProperty BaseName) Write-Host " Startup items:" if ($final.Count -eq 0) { Write-Host " (none)" } else { foreach ($f in $final) { Write-Host " - $f" } } $mnState = if ($machineNumTaskExists) { 'ON (prompts at logon if 9999)' } else { 'OFF' } Write-Host " Machine number logon prompt: $mnState" Write-Host "" Write-Host "========================================" -ForegroundColor Cyan Write-Host " Done" -ForegroundColor Cyan Write-Host "========================================" -ForegroundColor Cyan Write-Host "" Write-Host "Completed: $(Get-Date -Format 'yyyy-MM-dd HH:mm:ss')" try { Stop-Transcript | Out-Null } catch {} Write-Host "Press any key to close..." try { [void][Console]::ReadKey($true) } catch { [void](Read-Host) }