PC profiles: per-type/sub-type config + Standard Timeclock/Machine menu

Adds a pcProfiles section to site-config.json that lets each PC type (and
optional sub-type) override startupItems, taskbarPins, and desktopApps.
Scripts resolve: pcProfile > site-wide default > hardcoded fallback.

New shared helper: Shopfloor/lib/Get-PCProfile.ps1
  Dot-sourced by consuming scripts. Reads pc-type.txt + pc-subtype.txt,
  builds a profile key (e.g. "Standard-Machine"), and looks it up in
  site-config.json pcProfiles. Exports $siteConfig, $pcType, $pcSubtype,
  $profileKey, $pcProfile for the caller to use.

  Replaces the inline Get-SiteConfig function that was copy-pasted into
  each script. Scripts now do:
    . "$PSScriptRoot\lib\Get-PCProfile.ps1"
  instead of duplicating the loader.

startnet.cmd changes:
  - Added Lab as PC type option (7)
  - Standard now has a sub-type menu: Timeclock / Machine
  - Display sub-type menu also writes PCSUBTYPE for consistency
  - pc-subtype.txt written alongside pc-type.txt when sub-type selected
  - site-config.json copied from enrollment share to W:\Enrollment\

site-config.json v2.0:
  - New pcProfiles section with profiles for:
    Standard-Timeclock, Standard-Machine, CMM, Genspect, Keyence,
    WaxAndTrace, Lab, Display-Lobby, Display-Dashboard
  - CMM/Genspect/Keyence/WaxAndTrace profiles have TODO comments for
    type-specific apps (placeholder with WJ Shopfloor baseline only)
  - Lab/Display profiles have empty startupItems and desktopApps
  - Top-level startupItems/taskbarPins/desktopApps remain as site-wide
    defaults (used when no profile matches)

Updated scripts:
  06-OrganizeDesktop.ps1 - desktopApps from profile > site > hardcoded
  07-TaskbarLayout.ps1   - taskbarPins from profile > site > hardcoded
  08-EdgeDefaultBrowser.ps1 - uses shared profile loader
  Configure-PC.ps1       - startupItems from profile > site > hardcoded

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
cproudlock
2026-04-10 11:19:51 -04:00
parent 0aaf049942
commit ed803539e0
7 changed files with 255 additions and 68 deletions

View File

@@ -46,20 +46,8 @@ if (-not $isAdmin) {
exit 1
}
function Get-SiteConfig {
$configPath = 'C:\Enrollment\site-config.json'
if (-not (Test-Path -LiteralPath $configPath)) {
Write-Host "site-config.json not found - using defaults" -ForegroundColor DarkGray
return $null
}
try {
return (Get-Content -LiteralPath $configPath -Raw -ErrorAction Stop | ConvertFrom-Json)
} catch {
Write-Warning "Failed to parse site-config.json: $_"
return $null
}
}
$siteConfig = Get-SiteConfig
# Load site config + PC profile
. "$PSScriptRoot\lib\Get-PCProfile.ps1"
$publicDesktop = 'C:\Users\Public\Desktop'
$shopfloorToolsDir = Join-Path $publicDesktop 'Shopfloor Tools'
@@ -292,8 +280,12 @@ function Add-ShopfloorToolsApps {
#
# Kind = 'exe' -> build a fresh .lnk from ExePath
# Kind = 'existing' -> copy an existing .lnk via Find-ExistingLnk
if ($siteConfig -and $siteConfig.desktopApps) {
$apps = @($siteConfig.desktopApps | ForEach-Object {
$cfgApps = if ($pcProfile -and $pcProfile.desktopApps) { $pcProfile.desktopApps }
elseif ($siteConfig -and $siteConfig.desktopApps) { $siteConfig.desktopApps }
else { $null }
if ($cfgApps) {
$apps = @($cfgApps | ForEach-Object {
$entry = @{ Name = $_.name; Kind = $_.kind }
if ($_.kind -eq 'exe') { $entry.ExePath = $_.exePath }
if ($_.kind -eq 'existing') { $entry.SourceName = $_.sourceName }

View File

@@ -30,20 +30,8 @@ if (-not $isAdmin) {
exit 1
}
function Get-SiteConfig {
$configPath = 'C:\Enrollment\site-config.json'
if (-not (Test-Path -LiteralPath $configPath)) {
Write-Host "site-config.json not found - using defaults" -ForegroundColor DarkGray
return $null
}
try {
return (Get-Content -LiteralPath $configPath -Raw -ErrorAction Stop | ConvertFrom-Json)
} catch {
Write-Warning "Failed to parse site-config.json: $_"
return $null
}
}
$siteConfig = Get-SiteConfig
# Load site config + PC profile
. "$PSScriptRoot\lib\Get-PCProfile.ps1"
$publicDesktop = 'C:\Users\Public\Desktop'
$shopfloorToolsDir = Join-Path $publicDesktop 'Shopfloor Tools'
@@ -57,8 +45,12 @@ $layoutXmlPath = Join-Path $defaultUserShell 'LayoutModification.xml'
# it; all other entries reference C:\Users\Public\Desktop\Shopfloor Tools\
# which 06-OrganizeDesktop.ps1 populates.
# ============================================================================
if ($siteConfig -and $siteConfig.taskbarPins) {
$pinSpec = @($siteConfig.taskbarPins | ForEach-Object {
$cfgPins = if ($pcProfile -and $pcProfile.taskbarPins) { $pcProfile.taskbarPins }
elseif ($siteConfig -and $siteConfig.taskbarPins) { $siteConfig.taskbarPins }
else { $null }
if ($cfgPins) {
$pinSpec = @($cfgPins | ForEach-Object {
@{
Name = $_.name
Path = $_.lnkPath

View File

@@ -53,20 +53,8 @@ if (-not $isAdmin) {
exit 1
}
function Get-SiteConfig {
$configPath = 'C:\Enrollment\site-config.json'
if (-not (Test-Path -LiteralPath $configPath)) {
Write-Host "site-config.json not found - using defaults" -ForegroundColor DarkGray
return $null
}
try {
return (Get-Content -LiteralPath $configPath -Raw -ErrorAction Stop | ConvertFrom-Json)
} catch {
Write-Warning "Failed to parse site-config.json: $_"
return $null
}
}
$siteConfig = Get-SiteConfig
# Load site config + PC profile
. "$PSScriptRoot\lib\Get-PCProfile.ps1"
# ----------------------------------------------------------------------------
# Sanity: Edge must be installed for this to mean anything

View File

@@ -28,20 +28,9 @@ 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)"
function Get-SiteConfig {
$configPath = 'C:\Enrollment\site-config.json'
if (-not (Test-Path -LiteralPath $configPath)) {
Write-Host "site-config.json not found - using defaults" -ForegroundColor DarkGray
return $null
}
try {
return (Get-Content -LiteralPath $configPath -Raw -ErrorAction Stop | ConvertFrom-Json)
} catch {
Write-Warning "Failed to parse site-config.json: $_"
return $null
}
}
$siteConfig = Get-SiteConfig
# Load site config + PC profile (resolves pc-type.txt + pc-subtype.txt
# into a profile from site-config.json's pcProfiles section)
. "$PSScriptRoot\lib\Get-PCProfile.ps1"
$startupDir = 'C:\ProgramData\Microsoft\Windows\Start Menu\Programs\Startup'
$publicDesktop = 'C:\Users\Public\Desktop'
@@ -132,12 +121,17 @@ $edgePath = @(
# ============================================================================
# Startup item definitions
# Resolved from: pcProfile.startupItems > siteConfig.startupItems > hardcoded
# ============================================================================
if ($siteConfig -and $siteConfig.startupItems) {
$cfgItems = if ($pcProfile -and $pcProfile.startupItems) { $pcProfile.startupItems }
elseif ($siteConfig -and $siteConfig.startupItems) { $siteConfig.startupItems }
else { $null }
if ($cfgItems) {
$items = @()
$num = 0
foreach ($si in $siteConfig.startupItems) {
foreach ($si in $cfgItems) {
$num++
switch ($si.type) {
'exe' {

View File

@@ -0,0 +1,68 @@
# Get-PCProfile.ps1 - Shared helper for resolving the active PC profile
# from site-config.json. Dot-source this from any script that needs
# profile-aware configuration:
#
# . "$PSScriptRoot\lib\Get-PCProfile.ps1" (from Shopfloor\ scripts)
# . "$PSScriptRoot\Get-PCProfile.ps1" (from lib\ scripts)
#
# After dot-sourcing, these variables are available:
# $siteConfig - full parsed site-config.json (or $null)
# $pcType - from pc-type.txt (e.g. "Standard", "CMM", "Display")
# $pcSubtype - from pc-subtype.txt (e.g. "Timeclock", "Machine", "Lobby")
# $profileKey - lookup key (e.g. "Standard-Machine", "CMM", "Display-Lobby")
# $pcProfile - the matched profile object from pcProfiles, or $null
#
# Resolution order for any config key (e.g. startupItems):
# 1. $pcProfile.startupItems (profile-specific override)
# 2. $siteConfig.startupItems (site-wide default)
# 3. (hardcoded fallback in the calling script)
#
# Usage pattern in consuming scripts:
# $items = if ($pcProfile -and $pcProfile.startupItems) { $pcProfile.startupItems }
# elseif ($siteConfig -and $siteConfig.startupItems) { $siteConfig.startupItems }
# else { $null } # trigger hardcoded fallback
function Get-SiteConfig {
$configPath = 'C:\Enrollment\site-config.json'
if (-not (Test-Path -LiteralPath $configPath)) {
Write-Host "site-config.json not found - using defaults" -ForegroundColor DarkGray
return $null
}
try {
return (Get-Content -LiteralPath $configPath -Raw -ErrorAction Stop | ConvertFrom-Json)
} catch {
Write-Warning "Failed to parse site-config.json: $_"
return $null
}
}
$siteConfig = Get-SiteConfig
# Read PC type + sub-type from the files startnet.cmd wrote during imaging
$pcType = ''
$pcSubtype = ''
$typeFile = 'C:\Enrollment\pc-type.txt'
$subtypeFile = 'C:\Enrollment\pc-subtype.txt'
if (Test-Path -LiteralPath $typeFile) {
$pcType = (Get-Content -LiteralPath $typeFile -First 1 -ErrorAction SilentlyContinue).Trim()
}
if (Test-Path -LiteralPath $subtypeFile) {
$pcSubtype = (Get-Content -LiteralPath $subtypeFile -First 1 -ErrorAction SilentlyContinue).Trim()
}
# Build the profile key: "Standard-Machine", "CMM", "Display-Lobby", etc.
$profileKey = if ($pcSubtype) { "$pcType-$pcSubtype" } else { $pcType }
# Look up the profile in pcProfiles. Fall back to $null (callers use
# site-wide defaults or hardcoded values).
$pcProfile = $null
if ($siteConfig -and $siteConfig.pcProfiles -and $profileKey) {
$pcProfile = $siteConfig.pcProfiles.$profileKey
}
if ($pcProfile) {
Write-Host "PC profile: $profileKey" -ForegroundColor Cyan
} elseif ($profileKey) {
Write-Host "PC profile '$profileKey' not found in site-config.json - using site defaults" -ForegroundColor DarkGray
}

View File

@@ -1,7 +1,7 @@
{
"_version": "1.0",
"_version": "2.0",
"_site": "west-jefferson",
"_comment": "Site-specific configuration for the shopfloor imaging pipeline. Scripts read this from C:\\Enrollment\\site-config.json at runtime and fall back to hardcoded defaults if missing. To deploy at a different site, clone this file and change the values.",
"_comment": "Site-specific configuration for the shopfloor imaging pipeline. Scripts read this from C:\\Enrollment\\site-config.json at runtime and fall back to hardcoded defaults if missing. To deploy at a different site, clone this file and change the values. Top-level keys (startupItems, taskbarPins, desktopApps) are defaults used when no pcProfile matches. Per-type profiles override them.",
"siteName": "West Jefferson",
"siteNameCompact": "WestJefferson",
@@ -46,5 +46,130 @@
{ "name": "NTLARS", "kind": "exe", "exePath": "C:\\Program Files (x86)\\Dnc\\Common\\NTLARS.exe" },
{ "name": "WJ Shopfloor", "kind": "existing", "sourceName": "WJ Shopfloor.lnk" },
{ "name": "Defect_Tracker", "kind": "existing", "sourceName": "Defect_Tracker.lnk" }
],
"pcProfiles": {
"_comment": "Per PC-type (and optional sub-type) overrides. Key format: 'Type' or 'Type-Subtype'. Scripts look up the profile matching pc-type.txt + pc-subtype.txt. If a profile exists, its startupItems/taskbarPins/desktopApps REPLACE the top-level defaults above. If no profile matches, the top-level defaults are used.",
"Standard-Timeclock": {
"startupItems": [
{ "label": "WJ Shopfloor", "type": "existing", "sourceLnk": "WJ Shopfloor.lnk" }
],
"taskbarPins": [
{ "name": "Microsoft Edge", "lnkPath": "%ALLUSERSPROFILE%\\Microsoft\\Windows\\Start Menu\\Programs\\Microsoft Edge.lnk" },
{ "name": "WJ Shopfloor", "lnkPath": "%PUBLIC%\\Desktop\\Shopfloor Tools\\WJ Shopfloor.lnk" }
],
"desktopApps": [
{ "name": "WJ Shopfloor", "kind": "existing", "sourceName": "WJ Shopfloor.lnk" },
{ "name": "Defect_Tracker", "kind": "existing", "sourceName": "Defect_Tracker.lnk" }
]
},
"Standard-Machine": {
"startupItems": [
{ "label": "WJ Shopfloor", "type": "existing", "sourceLnk": "WJ Shopfloor.lnk" },
{ "label": "Plant Apps", "type": "url", "urlKey": "plantApps" },
{ "label": "eDNC", "type": "exe", "target": "C:\\Program Files (x86)\\Dnc\\bin\\DncMain.exe" },
{ "label": "UDC", "type": "exe", "target": "C:\\Program Files\\UDC\\UDC.exe" }
],
"taskbarPins": [
{ "name": "Microsoft Edge", "lnkPath": "%ALLUSERSPROFILE%\\Microsoft\\Windows\\Start Menu\\Programs\\Microsoft Edge.lnk" },
{ "name": "WJ Shopfloor", "lnkPath": "%PUBLIC%\\Desktop\\Shopfloor Tools\\WJ Shopfloor.lnk" },
{ "name": "UDC", "lnkPath": "%PUBLIC%\\Desktop\\Shopfloor Tools\\UDC.lnk" },
{ "name": "eDNC", "lnkPath": "%PUBLIC%\\Desktop\\Shopfloor Tools\\eDNC.lnk" },
{ "name": "NTLARS", "lnkPath": "%PUBLIC%\\Desktop\\Shopfloor Tools\\NTLARS.lnk" },
{ "name": "Defect_Tracker", "lnkPath": "%PUBLIC%\\Desktop\\Shopfloor Tools\\Defect_Tracker.lnk" }
],
"desktopApps": [
{ "name": "UDC", "kind": "exe", "exePath": "C:\\Program Files\\UDC\\UDC.exe" },
{ "name": "eDNC", "kind": "exe", "exePath": "C:\\Program Files (x86)\\Dnc\\bin\\DncMain.exe" },
{ "name": "NTLARS", "kind": "exe", "exePath": "C:\\Program Files (x86)\\Dnc\\Common\\NTLARS.exe" },
{ "name": "WJ Shopfloor", "kind": "existing", "sourceName": "WJ Shopfloor.lnk" },
{ "name": "Defect_Tracker", "kind": "existing", "sourceName": "Defect_Tracker.lnk" }
]
},
"CMM": {
"_comment": "TODO: add PC-DMIS, CLM License, Hexagon CMM tools when app details are known",
"startupItems": [
{ "label": "WJ Shopfloor", "type": "existing", "sourceLnk": "WJ Shopfloor.lnk" }
],
"taskbarPins": [
{ "name": "Microsoft Edge", "lnkPath": "%ALLUSERSPROFILE%\\Microsoft\\Windows\\Start Menu\\Programs\\Microsoft Edge.lnk" },
{ "name": "WJ Shopfloor", "lnkPath": "%PUBLIC%\\Desktop\\Shopfloor Tools\\WJ Shopfloor.lnk" }
],
"desktopApps": [
{ "name": "WJ Shopfloor", "kind": "existing", "sourceName": "WJ Shopfloor.lnk" }
]
},
"Genspect": {
"_comment": "TODO: add Genspect-specific apps when details are known",
"startupItems": [
{ "label": "WJ Shopfloor", "type": "existing", "sourceLnk": "WJ Shopfloor.lnk" }
],
"taskbarPins": [
{ "name": "Microsoft Edge", "lnkPath": "%ALLUSERSPROFILE%\\Microsoft\\Windows\\Start Menu\\Programs\\Microsoft Edge.lnk" },
{ "name": "WJ Shopfloor", "lnkPath": "%PUBLIC%\\Desktop\\Shopfloor Tools\\WJ Shopfloor.lnk" }
],
"desktopApps": [
{ "name": "WJ Shopfloor", "kind": "existing", "sourceName": "WJ Shopfloor.lnk" }
]
},
"Keyence": {
"_comment": "TODO: add Keyence-specific apps when details are known",
"startupItems": [
{ "label": "WJ Shopfloor", "type": "existing", "sourceLnk": "WJ Shopfloor.lnk" }
],
"taskbarPins": [
{ "name": "Microsoft Edge", "lnkPath": "%ALLUSERSPROFILE%\\Microsoft\\Windows\\Start Menu\\Programs\\Microsoft Edge.lnk" },
{ "name": "WJ Shopfloor", "lnkPath": "%PUBLIC%\\Desktop\\Shopfloor Tools\\WJ Shopfloor.lnk" }
],
"desktopApps": [
{ "name": "WJ Shopfloor", "kind": "existing", "sourceName": "WJ Shopfloor.lnk" }
]
},
"WaxAndTrace": {
"_comment": "TODO: add Wax and Trace apps when details are known",
"startupItems": [
{ "label": "WJ Shopfloor", "type": "existing", "sourceLnk": "WJ Shopfloor.lnk" }
],
"taskbarPins": [
{ "name": "Microsoft Edge", "lnkPath": "%ALLUSERSPROFILE%\\Microsoft\\Windows\\Start Menu\\Programs\\Microsoft Edge.lnk" },
{ "name": "WJ Shopfloor", "lnkPath": "%PUBLIC%\\Desktop\\Shopfloor Tools\\WJ Shopfloor.lnk" }
],
"desktopApps": [
{ "name": "WJ Shopfloor", "kind": "existing", "sourceName": "WJ Shopfloor.lnk" }
]
},
"Lab": {
"_comment": "No applications, minimal startup",
"startupItems": [],
"taskbarPins": [
{ "name": "Microsoft Edge", "lnkPath": "%ALLUSERSPROFILE%\\Microsoft\\Windows\\Start Menu\\Programs\\Microsoft Edge.lnk" }
],
"desktopApps": []
},
"Display-Lobby": {
"_comment": "Display kiosk - lobby variant",
"startupItems": [],
"taskbarPins": [
{ "name": "Microsoft Edge", "lnkPath": "%ALLUSERSPROFILE%\\Microsoft\\Windows\\Start Menu\\Programs\\Microsoft Edge.lnk" }
],
"desktopApps": []
},
"Display-Dashboard": {
"_comment": "Display kiosk - dashboard variant",
"startupItems": [],
"taskbarPins": [
{ "name": "Microsoft Edge", "lnkPath": "%ALLUSERSPROFILE%\\Microsoft\\Windows\\Start Menu\\Programs\\Microsoft Edge.lnk" }
],
"desktopApps": []
}
}
}

View File

@@ -87,19 +87,44 @@ echo 3. Keyence
echo 4. Genspect
echo 5. Display
echo 6. Standard
echo 7. Lab
echo.
set PCTYPE=
set /p pctype_choice=Enter your choice (1-6):
set /p pctype_choice=Enter your choice (1-7):
if "%pctype_choice%"=="1" set PCTYPE=CMM
if "%pctype_choice%"=="2" set PCTYPE=WaxAndTrace
if "%pctype_choice%"=="3" set PCTYPE=Keyence
if "%pctype_choice%"=="4" set PCTYPE=Genspect
if "%pctype_choice%"=="5" set PCTYPE=Display
if "%pctype_choice%"=="6" set PCTYPE=Standard
if "%pctype_choice%"=="7" set PCTYPE=Lab
if "%PCTYPE%"=="" goto pctype_menu
REM --- Display sub-type selection ---
REM --- Sub-type selection menus ---
REM PCSUBTYPE is written to pc-subtype.txt alongside pc-type.txt.
REM Scripts read it to look up the right profile in site-config.json.
set PCSUBTYPE=
set DISPLAYTYPE=
REM --- Standard sub-type ---
if not "%PCTYPE%"=="Standard" goto skip_standard_menu
:standard_menu
cls
echo.
echo ========================================
echo Standard PC Sub-Type
echo ========================================
echo.
echo 1. Timeclock (WJ Shopfloor only)
echo 2. Machine (WJ Shopfloor, Plant Apps, eDNC, UDC)
echo.
set /p standard_choice=Enter your choice (1-2):
if "%standard_choice%"=="1" set PCSUBTYPE=Timeclock
if "%standard_choice%"=="2" set PCSUBTYPE=Machine
if "%PCSUBTYPE%"=="" goto standard_menu
:skip_standard_menu
REM --- Display sub-type ---
if not "%PCTYPE%"=="Display" goto skip_display_menu
:display_menu
cls
@@ -113,8 +138,10 @@ echo 2. Dashboard
echo.
set /p display_choice=Enter your choice (1-2):
if "%display_choice%"=="1" set DISPLAYTYPE=Lobby
if "%display_choice%"=="1" set PCSUBTYPE=Lobby
if "%display_choice%"=="2" set DISPLAYTYPE=Dashboard
if "%DISPLAYTYPE%"=="" goto display_menu
if "%display_choice%"=="2" set PCSUBTYPE=Dashboard
if "%PCSUBTYPE%"=="" goto display_menu
:skip_display_menu
REM --- Map enrollment share early (kept open for copy after imaging) ---
@@ -251,6 +278,7 @@ REM --- Copy shopfloor PC type setup scripts ---
if "%PCTYPE%"=="" goto cleanup_enroll
echo %PCTYPE%> W:\Enrollment\pc-type.txt
if not "%DISPLAYTYPE%"=="" echo %DISPLAYTYPE%> W:\Enrollment\display-type.txt
if not "%PCSUBTYPE%"=="" echo %PCSUBTYPE%> W:\Enrollment\pc-subtype.txt
copy /Y "Y:\shopfloor-setup\Run-ShopfloorSetup.ps1" "W:\Enrollment\Run-ShopfloorSetup.ps1"
REM --- Always copy Shopfloor baseline scripts ---
mkdir W:\Enrollment\shopfloor-setup 2>NUL