Shopfloor: Configure-PC tool, machine-number logon prompt, execution order fixes
New tools:
Configure-PC.bat/.ps1 - Interactive desktop 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 (updates UDC JSON + eDNC registry,
restarts UDC.exe with new args).
2. Auto-startup toggle: pick which apps start at user logon from a
numbered list (UDC, eDNC, Defect Tracker, WJ Shopfloor, Plant Apps).
Creates/removes .lnk files in AllUsers Startup folder. Toggle UI
shows [ON]/[ ] state, safe to re-run anytime. Plant Apps URL
resolved from .url file at runtime with hardcoded fallback to
https://mes-wjefferson.apps.lr.geaerospace.net/run/...
3. Item 6 in the toggle list: register/unregister a "Check Machine
Number" logon task for standard (non-admin) users. When enabled,
the task fires at every logon, checks for 9999, pops an InputBox
if found, updates both apps, then unregisters itself on success.
Check-MachineNumber.ps1 - The logon task script. Runs as the logged-in
user (needs GUI for InputBox), not SYSTEM. Writing to ProgramData + HKLM
is possible because 02-MachineNumberACLs.ps1 pre-grants BUILTIN\Users
write access on the two specific targets during imaging.
02-MachineNumberACLs.ps1 - Standard type-specific script (runs after
01-eDNC.ps1). Opens C:\ProgramData\UDC\udc_settings.json for Users:Modify
and HKLM:\...\GE Aircraft Engines\DNC\General for Users:SetValue. Narrow
scope, not blanket admin.
Execution order fixes in Run-ShopfloorSetup.ps1:
The dispatcher now has two lists: $skipInBaseline (scripts NOT run in the
alphabetical baseline loop) and $runAfterTypeSpecific (scripts run
explicitly after type-specific scripts complete). This fixes the bug where
06/07 ran before 01-eDNC.ps1 installed DnC, so eDNC/NTLARS shortcuts were
silently skipped.
New execution order:
Baseline: 00-PreInstall, 04-NetworkAndWinRM (skipping 05-08 + tools)
Type-specific: 01-eDNC, 02-MachineNumberACLs
Finalization: 06-OrganizeDesktop, 07-TaskbarLayout
06 internally calls 05 (Office shortcuts, Phase 0) and 08 (Edge config,
Phase 4) as sub-phases, so they also benefit from running late. Office
isn't installed until after the first reboot (ppkg streams C2R), so 05
no-ops at imaging time but succeeds when 06's SYSTEM logon task re-runs
it on the second boot. 08 resolves startup-tab URLs from .url files
delivered by DSC (even later); same self-heal via the logon task.
Other fixes in this commit:
- OpenText Setup-OpenText.ps1 Step 4: exclude WJ_Office.lnk, IBM_qks.lnk,
mmcs.lnk desktop shortcuts (matching the Step 3 .hep profile exclusion
from the previous commit). Removes stale copies from prior installs.
- 05-OfficeShortcuts.ps1: widened Office detection to 6 path variants
covering C2R + MSI + Office15/16, with diagnostic output on miss.
- 06-OrganizeDesktop.ps1: removed Phase 3 (desktop-root pin copies for
eDNC/NTLARS) so shortcuts live in Shopfloor Tools only, not duplicated
at root. Emptied $keepAtRoot. Added Phase 0 (call 05) and Phase 4
(call 08). Lazy folder creation + empty-folder cleanup. Scheduled task
now runs as SYSTEM (was BUILTIN\Users with Limited which failed the
admin check). Added NTLARS to 07's taskbar pin list.
- 08-EdgeDefaultBrowser.ps1: Plant Apps URL fallback hardcoded from
device-config.yaml.
- All new scripts have Start-Transcript logging to C:\Logs\SFLD\ with
timestamps and running-as identity.
- Run-ShopfloorSetup.ps1: Start-Transcript + Stop-Transcript wrapping
entire dispatcher run, writes to C:\Logs\SFLD\shopfloor-setup.log.
Configure-PC.bat added to SupportUser desktop copy list.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -280,13 +280,40 @@ foreach ($u in $userDirs) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
# --- Step 4: Public Desktop shortcuts ---
|
# --- Step 4: Public Desktop shortcuts ---
|
||||||
|
# Same exclusion list as the Profile step: these three sessions aren't
|
||||||
|
# used on shopfloor PCs, so we skip deploying their .lnk files AND
|
||||||
|
# remove any that a prior install left behind.
|
||||||
Write-SetupLog ""
|
Write-SetupLog ""
|
||||||
Write-SetupLog "Step 4: Deploying public desktop shortcuts..."
|
Write-SetupLog "Step 4: Deploying public desktop shortcuts..."
|
||||||
$shortcutSrc = Join-Path $SourceDir 'W10shortcuts'
|
$shortcutSrc = Join-Path $SourceDir 'W10shortcuts'
|
||||||
$publicDesktop = 'C:\Users\Public\Desktop'
|
$publicDesktop = 'C:\Users\Public\Desktop'
|
||||||
|
|
||||||
|
$excludeShortcuts = @(
|
||||||
|
'WJ_Office.lnk',
|
||||||
|
'IBM_qks.lnk',
|
||||||
|
'mmcs.lnk'
|
||||||
|
)
|
||||||
|
|
||||||
|
# Clean up stale copies from prior installs first
|
||||||
|
foreach ($name in $excludeShortcuts) {
|
||||||
|
$stale = Join-Path $publicDesktop $name
|
||||||
|
if (Test-Path -LiteralPath $stale) {
|
||||||
|
try {
|
||||||
|
Remove-Item -LiteralPath $stale -Force -ErrorAction Stop
|
||||||
|
Write-SetupLog " removed stale desktop shortcut: $name"
|
||||||
|
} catch {
|
||||||
|
Write-SetupLog " failed to remove stale $stale : $_"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (Test-Path $shortcutSrc) {
|
if (Test-Path $shortcutSrc) {
|
||||||
$lnkFiles = Get-ChildItem -Path $shortcutSrc -Filter '*.lnk' -File -ErrorAction SilentlyContinue
|
$lnkFiles = Get-ChildItem -Path $shortcutSrc -Filter '*.lnk' -File -ErrorAction SilentlyContinue
|
||||||
foreach ($l in $lnkFiles) {
|
foreach ($l in $lnkFiles) {
|
||||||
|
if ($excludeShortcuts -contains $l.Name) {
|
||||||
|
Write-SetupLog " skip (excluded): $($l.Name)"
|
||||||
|
continue
|
||||||
|
}
|
||||||
Copy-Item -Path $l.FullName -Destination $publicDesktop -Force
|
Copy-Item -Path $l.FullName -Destination $publicDesktop -Force
|
||||||
Write-SetupLog " $($l.Name) -> $publicDesktop"
|
Write-SetupLog " $($l.Name) -> $publicDesktop"
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,6 +1,24 @@
|
|||||||
# Run-ShopfloorSetup.ps1 - Dispatcher for shopfloor PC type setup
|
# Run-ShopfloorSetup.ps1 - Dispatcher for shopfloor PC type setup
|
||||||
# Runs Shopfloor baseline scripts first, then type-specific scripts on top.
|
# Runs Shopfloor baseline scripts first, then type-specific scripts on top.
|
||||||
|
|
||||||
|
# --- Transcript logging ---
|
||||||
|
# Captures everything the dispatcher and all child scripts write to host so
|
||||||
|
# we can diagnose setup failures after the fact. -Append + -Force so repeat
|
||||||
|
# invocations (e.g. after a reboot mid-setup) accumulate instead of clobbering.
|
||||||
|
$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 'shopfloor-setup.log'
|
||||||
|
try { Start-Transcript -Path $transcriptPath -Append -Force | Out-Null } catch {}
|
||||||
|
|
||||||
|
Write-Host ""
|
||||||
|
Write-Host "================================================================"
|
||||||
|
Write-Host "=== Run-ShopfloorSetup.ps1 starting $(Get-Date -Format 'yyyy-MM-dd HH:mm:ss') ==="
|
||||||
|
Write-Host " Transcript: $transcriptPath"
|
||||||
|
Write-Host "================================================================"
|
||||||
|
Write-Host ""
|
||||||
|
|
||||||
# Bump AutoLogonCount HIGH at the start so reboots during setup (e.g. VC++ 2008
|
# Bump AutoLogonCount HIGH at the start so reboots during setup (e.g. VC++ 2008
|
||||||
# triggering an immediate ExitWindowsEx) don't exhaust autologin attempts before
|
# triggering an immediate ExitWindowsEx) don't exhaust autologin attempts before
|
||||||
# the dispatcher can complete. The end-of-script reset puts it back to 2 once
|
# the dispatcher can complete. The end-of-script reset puts it back to 2 once
|
||||||
@@ -40,11 +58,44 @@ if (-not $pcType) {
|
|||||||
|
|
||||||
Write-Host "Shopfloor PC Type: $pcType"
|
Write-Host "Shopfloor PC Type: $pcType"
|
||||||
|
|
||||||
# --- Run Shopfloor baseline scripts first ---
|
# Scripts to skip in the alphabetical baseline loop. Each is either run
|
||||||
|
# explicitly in the finalization phase below, or invoked internally by
|
||||||
|
# another script:
|
||||||
|
#
|
||||||
|
# 05 - Office shortcuts. Invoked by 06 as Phase 0. Office isn't installed
|
||||||
|
# until after the first reboot, so 05 no-ops on the imaging run.
|
||||||
|
# 06's SYSTEM logon task re-runs it on the second boot.
|
||||||
|
# 06 - Desktop org. Phase 2 needs eDNC/NTLARS on disk (installed by
|
||||||
|
# type-specific 01-eDNC.ps1). Run in finalization phase.
|
||||||
|
# 07 - Taskbar pin layout. Reads 06's output. Run in finalization phase.
|
||||||
|
# 08 - Edge default browser + startup tabs. Invoked by 06 as Phase 4.
|
||||||
|
# Reads .url files delivered by DSC (after setup reboots). 06's
|
||||||
|
# SYSTEM logon task re-runs it to pick them up.
|
||||||
|
$skipInBaseline = @(
|
||||||
|
'05-OfficeShortcuts.ps1',
|
||||||
|
'06-OrganizeDesktop.ps1',
|
||||||
|
'07-TaskbarLayout.ps1',
|
||||||
|
'08-EdgeDefaultBrowser.ps1',
|
||||||
|
'Check-MachineNumber.ps1',
|
||||||
|
'Configure-PC.ps1'
|
||||||
|
)
|
||||||
|
|
||||||
|
# Scripts run AFTER type-specific scripts complete. 05 and 08 are NOT
|
||||||
|
# here because 06 calls them internally as sub-phases.
|
||||||
|
$runAfterTypeSpecific = @(
|
||||||
|
'06-OrganizeDesktop.ps1',
|
||||||
|
'07-TaskbarLayout.ps1'
|
||||||
|
)
|
||||||
|
|
||||||
|
# --- Run Shopfloor baseline scripts first (skipping deferred ones) ---
|
||||||
$baselineDir = Join-Path $setupDir "Shopfloor"
|
$baselineDir = Join-Path $setupDir "Shopfloor"
|
||||||
if (Test-Path $baselineDir) {
|
if (Test-Path $baselineDir) {
|
||||||
$scripts = Get-ChildItem -Path $baselineDir -Filter "*.ps1" -File | Sort-Object Name
|
$scripts = Get-ChildItem -Path $baselineDir -Filter "*.ps1" -File | Sort-Object Name
|
||||||
foreach ($script in $scripts) {
|
foreach ($script in $scripts) {
|
||||||
|
if ($skipInBaseline -contains $script.Name) {
|
||||||
|
Write-Host "Skipping baseline: $($script.Name) (runs in finalization phase)"
|
||||||
|
continue
|
||||||
|
}
|
||||||
shutdown /a 2>$null
|
shutdown /a 2>$null
|
||||||
Write-Host "Running baseline: $($script.Name)"
|
Write-Host "Running baseline: $($script.Name)"
|
||||||
try {
|
try {
|
||||||
@@ -74,13 +125,36 @@ if ($pcType -ne "Shopfloor") {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
# --- Finalization: run deferred baseline scripts (desktop org, taskbar pins)
|
||||||
|
# ---
|
||||||
|
# These needed to wait until all apps (eDNC, NTLARS, UDC, OpenText) were
|
||||||
|
# installed by the baseline + type-specific phases above. 06 internally
|
||||||
|
# calls 05 (Office shortcuts) and 08 (Edge config) as sub-phases, so we
|
||||||
|
# only need to invoke 06 and 07 explicitly here.
|
||||||
|
foreach ($name in $runAfterTypeSpecific) {
|
||||||
|
$script = Join-Path $baselineDir $name
|
||||||
|
if (-not (Test-Path $script)) {
|
||||||
|
Write-Warning "Deferred script not found: $script"
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
shutdown /a 2>$null
|
||||||
|
Write-Host "Running deferred baseline: $name"
|
||||||
|
try {
|
||||||
|
& $script
|
||||||
|
} catch {
|
||||||
|
Write-Warning "Deferred script $name failed: $_"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
Write-Host "Shopfloor setup complete for $pcType."
|
Write-Host "Shopfloor setup complete for $pcType."
|
||||||
|
|
||||||
# Copy utility scripts to SupportUser desktop
|
# Copy utility scripts to SupportUser desktop
|
||||||
$syncScript = Join-Path $setupDir "Shopfloor\sync_intune.bat"
|
foreach ($tool in @('sync_intune.bat', 'Configure-PC.bat')) {
|
||||||
if (Test-Path $syncScript) {
|
$src = Join-Path $setupDir "Shopfloor\$tool"
|
||||||
Copy-Item -Path $syncScript -Destination "C:\Users\SupportUser\Desktop\sync_intune.bat" -Force
|
if (Test-Path $src) {
|
||||||
Write-Host "sync_intune.bat copied to desktop."
|
Copy-Item -Path $src -Destination "C:\Users\SupportUser\Desktop\$tool" -Force
|
||||||
|
Write-Host "$tool copied to desktop."
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
# Standard PCs get the UDC/eDNC machine number helper
|
# Standard PCs get the UDC/eDNC machine number helper
|
||||||
@@ -98,5 +172,13 @@ if ($pcType -eq "Standard") {
|
|||||||
reg add "HKLM\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Winlogon" /v AutoLogonCount /t REG_DWORD /d 2 /f | Out-Null
|
reg add "HKLM\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Winlogon" /v AutoLogonCount /t REG_DWORD /d 2 /f | Out-Null
|
||||||
Write-Host "Auto-logon set to 2 remaining logins."
|
Write-Host "Auto-logon set to 2 remaining logins."
|
||||||
|
|
||||||
|
Write-Host ""
|
||||||
|
Write-Host "================================================================"
|
||||||
|
Write-Host "=== Run-ShopfloorSetup.ps1 complete $(Get-Date -Format 'yyyy-MM-dd HH:mm:ss') ==="
|
||||||
|
Write-Host "================================================================"
|
||||||
|
|
||||||
|
# Flush transcript before shutdown so the log file is complete on next boot
|
||||||
|
try { Stop-Transcript | Out-Null } catch {}
|
||||||
|
|
||||||
Write-Host "Rebooting in 10 seconds..."
|
Write-Host "Rebooting in 10 seconds..."
|
||||||
shutdown /r /t 10
|
shutdown /r /t 10
|
||||||
|
|||||||
@@ -21,14 +21,25 @@ $officeApps = @(
|
|||||||
@{ Exe = 'POWERPNT.EXE'; Name = 'PowerPoint' }
|
@{ Exe = 'POWERPNT.EXE'; Name = 'PowerPoint' }
|
||||||
)
|
)
|
||||||
|
|
||||||
# Office binary location depends on x86 vs x64 install. The standard ShopFloor
|
# Office binary location varies by install type and version:
|
||||||
# Office ppkg is x86 (GCCH_Prod_SFLD_StdOffice-x86_*) so it lands under
|
# - Office 2019+ / M365 / LTSC Click-to-Run: <PF>\Microsoft Office\root\Office16\
|
||||||
# Program Files (x86), but we check both so the script works either way.
|
# - Office 2016 MSI (legacy): <PF>\Microsoft Office\Office16\ (no root\)
|
||||||
$officeRoot = $null
|
# - Office 2013 MSI: <PF>\Microsoft Office\Office15\
|
||||||
foreach ($base in @(
|
# - x86 Office on 64-bit Windows: Program Files (x86)\...
|
||||||
|
# The standard ShopFloor Office ppkg is x86 Click-to-Run so normal case
|
||||||
|
# is "Program Files (x86)\Microsoft Office\root\Office16\EXCEL.EXE", but
|
||||||
|
# we check all variants so the script works across SKUs.
|
||||||
|
$officeSearchRoots = @(
|
||||||
'C:\Program Files\Microsoft Office\root\Office16',
|
'C:\Program Files\Microsoft Office\root\Office16',
|
||||||
'C:\Program Files (x86)\Microsoft Office\root\Office16'
|
'C:\Program Files (x86)\Microsoft Office\root\Office16',
|
||||||
)) {
|
'C:\Program Files\Microsoft Office\Office16',
|
||||||
|
'C:\Program Files (x86)\Microsoft Office\Office16',
|
||||||
|
'C:\Program Files\Microsoft Office\Office15',
|
||||||
|
'C:\Program Files (x86)\Microsoft Office\Office15'
|
||||||
|
)
|
||||||
|
|
||||||
|
$officeRoot = $null
|
||||||
|
foreach ($base in $officeSearchRoots) {
|
||||||
if (Test-Path (Join-Path $base 'EXCEL.EXE')) {
|
if (Test-Path (Join-Path $base 'EXCEL.EXE')) {
|
||||||
$officeRoot = $base
|
$officeRoot = $base
|
||||||
break
|
break
|
||||||
@@ -37,6 +48,11 @@ foreach ($base in @(
|
|||||||
|
|
||||||
if (-not $officeRoot) {
|
if (-not $officeRoot) {
|
||||||
Write-Host "No Office install detected - skipping shortcut creation."
|
Write-Host "No Office install detected - skipping shortcut creation."
|
||||||
|
Write-Host "Searched:"
|
||||||
|
foreach ($p in $officeSearchRoots) {
|
||||||
|
$hit = if (Test-Path $p) { "(dir exists)" } else { "(missing)" }
|
||||||
|
Write-Host " $p $hit"
|
||||||
|
}
|
||||||
exit 0
|
exit 0
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -49,14 +49,13 @@ if (-not $isAdmin) {
|
|||||||
$publicDesktop = 'C:\Users\Public\Desktop'
|
$publicDesktop = 'C:\Users\Public\Desktop'
|
||||||
$shopfloorToolsDir = Join-Path $publicDesktop 'Shopfloor Tools'
|
$shopfloorToolsDir = Join-Path $publicDesktop 'Shopfloor Tools'
|
||||||
$scriptPath = $MyInvocation.MyCommand.Path
|
$scriptPath = $MyInvocation.MyCommand.Path
|
||||||
|
$scriptDir = Split-Path -Parent $scriptPath
|
||||||
|
|
||||||
# Filenames that always stay at the desktop root regardless of classification.
|
# Filenames that always stay at the desktop root regardless of classification.
|
||||||
# End users click these many times a day and an extra folder click is real
|
# Empty right now - every shortcut lives inside a category folder for a
|
||||||
# friction. Phase 2 also drops these here as a post-sweep safety net.
|
# clean end-user desktop. Add entries here if a future shortcut needs to
|
||||||
$keepAtRoot = @(
|
# stay pinned at root.
|
||||||
'eDNC.lnk',
|
$keepAtRoot = @()
|
||||||
'NTLARS.lnk'
|
|
||||||
)
|
|
||||||
|
|
||||||
# ============================================================================
|
# ============================================================================
|
||||||
# Phase 1: Sweep loose shortcuts at desktop root into category folders
|
# Phase 1: Sweep loose shortcuts at desktop root into category folders
|
||||||
@@ -109,17 +108,11 @@ function Invoke-DesktopSweep {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
# Ensure category folders exist
|
# Category folders are created LAZILY - only when we're about to move
|
||||||
foreach ($cat in $categories.Keys) {
|
# something into them - so a Display / Wax-Trace PC without Office
|
||||||
$dir = Join-Path $DesktopPath $cat
|
# doesn't get an empty Office\ folder littering the desktop. See
|
||||||
if (-not (Test-Path -LiteralPath $dir)) {
|
# Remove-EmptyCategoryFolders at the end of the script for the
|
||||||
try {
|
# post-sweep cleanup pass that finishes the job.
|
||||||
New-Item -ItemType Directory -Path $dir -Force -ErrorAction Stop | Out-Null
|
|
||||||
} catch {
|
|
||||||
Write-Warning "Failed to create category folder '$cat' : $_"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
# WScript.Shell for resolving .lnk targets
|
# WScript.Shell for resolving .lnk targets
|
||||||
$shell = $null
|
$shell = $null
|
||||||
@@ -188,6 +181,14 @@ function Invoke-DesktopSweep {
|
|||||||
|
|
||||||
if ($category) {
|
if ($category) {
|
||||||
$destDir = Join-Path $DesktopPath $category
|
$destDir = Join-Path $DesktopPath $category
|
||||||
|
if (-not (Test-Path -LiteralPath $destDir)) {
|
||||||
|
try {
|
||||||
|
New-Item -ItemType Directory -Path $destDir -Force -ErrorAction Stop | Out-Null
|
||||||
|
} catch {
|
||||||
|
Write-Warning "Failed to create category folder '$category' : $_"
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
}
|
||||||
$destPath = Join-Path $destDir $item.Name
|
$destPath = Join-Path $destDir $item.Name
|
||||||
try {
|
try {
|
||||||
Move-Item -LiteralPath $item.FullName -Destination $destPath -Force -ErrorAction Stop
|
Move-Item -LiteralPath $item.FullName -Destination $destPath -Force -ErrorAction Stop
|
||||||
@@ -269,17 +270,10 @@ function Find-ExistingLnk {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function Add-ShopfloorToolsApps {
|
function Add-ShopfloorToolsApps {
|
||||||
if (-not (Test-Path -LiteralPath $shopfloorToolsDir)) {
|
|
||||||
try {
|
|
||||||
New-Item -ItemType Directory -Path $shopfloorToolsDir -Force -ErrorAction Stop | Out-Null
|
|
||||||
} catch {
|
|
||||||
Write-Warning "Failed to create $shopfloorToolsDir : $_"
|
|
||||||
return
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
# App registry - each entry describes how to materialize one shortcut
|
# App registry - each entry describes how to materialize one shortcut
|
||||||
# into Shopfloor Tools\.
|
# into Shopfloor Tools\. Folder creation is deferred until we know we
|
||||||
|
# have at least one app to put in it (lazy creation, so PC types with
|
||||||
|
# nothing installed don't get an empty Shopfloor Tools folder).
|
||||||
#
|
#
|
||||||
# Kind = 'exe' -> build a fresh .lnk from ExePath
|
# Kind = 'exe' -> build a fresh .lnk from ExePath
|
||||||
# Kind = 'existing' -> copy an existing .lnk via Find-ExistingLnk
|
# Kind = 'existing' -> copy an existing .lnk via Find-ExistingLnk
|
||||||
@@ -291,12 +285,29 @@ function Add-ShopfloorToolsApps {
|
|||||||
@{ Name = 'Defect_Tracker'; Kind = 'existing'; SourceName = 'Defect_Tracker.lnk' }
|
@{ Name = 'Defect_Tracker'; Kind = 'existing'; SourceName = 'Defect_Tracker.lnk' }
|
||||||
)
|
)
|
||||||
|
|
||||||
|
# Lazy folder creation - only create Shopfloor Tools\ the first time
|
||||||
|
# we have an app that's actually going to land in it. PC types with
|
||||||
|
# nothing installed get no empty folder.
|
||||||
|
$ensureToolsDir = {
|
||||||
|
if (-not (Test-Path -LiteralPath $shopfloorToolsDir)) {
|
||||||
|
try {
|
||||||
|
New-Item -ItemType Directory -Path $shopfloorToolsDir -Force -ErrorAction Stop | Out-Null
|
||||||
|
return $true
|
||||||
|
} catch {
|
||||||
|
Write-Warning "Failed to create $shopfloorToolsDir : $_"
|
||||||
|
return $false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return $true
|
||||||
|
}
|
||||||
|
|
||||||
foreach ($app in $apps) {
|
foreach ($app in $apps) {
|
||||||
$dest = Join-Path $shopfloorToolsDir "$($app.Name).lnk"
|
$dest = Join-Path $shopfloorToolsDir "$($app.Name).lnk"
|
||||||
|
|
||||||
switch ($app.Kind) {
|
switch ($app.Kind) {
|
||||||
'exe' {
|
'exe' {
|
||||||
if (Test-Path -LiteralPath $app.ExePath) {
|
if (Test-Path -LiteralPath $app.ExePath) {
|
||||||
|
if (-not (& $ensureToolsDir)) { break }
|
||||||
if (New-ShopfloorLnk -Path $dest -Target $app.ExePath) {
|
if (New-ShopfloorLnk -Path $dest -Target $app.ExePath) {
|
||||||
Write-Host " created: $($app.Name) -> $dest"
|
Write-Host " created: $($app.Name) -> $dest"
|
||||||
}
|
}
|
||||||
@@ -308,6 +319,7 @@ function Add-ShopfloorToolsApps {
|
|||||||
'existing' {
|
'existing' {
|
||||||
$src = Find-ExistingLnk $app.SourceName
|
$src = Find-ExistingLnk $app.SourceName
|
||||||
if ($src) {
|
if ($src) {
|
||||||
|
if (-not (& $ensureToolsDir)) { break }
|
||||||
try {
|
try {
|
||||||
Copy-Item -LiteralPath $src -Destination $dest -Force -ErrorAction Stop
|
Copy-Item -LiteralPath $src -Destination $dest -Force -ErrorAction Stop
|
||||||
Write-Host " copied: $($app.Name) from $src"
|
Write-Host " copied: $($app.Name) from $src"
|
||||||
@@ -323,30 +335,56 @@ function Add-ShopfloorToolsApps {
|
|||||||
}
|
}
|
||||||
|
|
||||||
# ============================================================================
|
# ============================================================================
|
||||||
# Phase 3: Pin eDNC and NTLARS shortcuts at the desktop root
|
# Phase 3: Remove empty category folders
|
||||||
#
|
#
|
||||||
# These are the two shortcuts end users touch most frequently. Allowlisted
|
# If the sweep classified nothing into a given category (e.g. no Office
|
||||||
# in the sweep, and also force-dropped here (copied from the Shopfloor
|
# on a Display PC, no Shopfloor Tools apps on a kiosk), we don't want an
|
||||||
# Tools\ versions we just created) so a sweep-and-forget user still ends
|
# empty folder cluttering the desktop. The scheduled-task sweep also runs
|
||||||
# up with them loose at the root.
|
# this so categories that go empty between logons self-heal.
|
||||||
# ============================================================================
|
# ============================================================================
|
||||||
function Update-DesktopRootPins {
|
function Remove-EmptyCategoryFolders {
|
||||||
foreach ($name in @('eDNC.lnk', 'NTLARS.lnk')) {
|
foreach ($cat in @('Office', 'Shopfloor Tools', 'Web Links')) {
|
||||||
$src = Join-Path $shopfloorToolsDir $name
|
$dir = Join-Path $publicDesktop $cat
|
||||||
$dst = Join-Path $publicDesktop $name
|
if (-not (Test-Path -LiteralPath $dir)) { continue }
|
||||||
if (Test-Path -LiteralPath $src) {
|
$contents = @(Get-ChildItem -LiteralPath $dir -Force -ErrorAction SilentlyContinue)
|
||||||
|
if ($contents.Count -eq 0) {
|
||||||
try {
|
try {
|
||||||
Copy-Item -LiteralPath $src -Destination $dst -Force -ErrorAction Stop
|
Remove-Item -LiteralPath $dir -Force -ErrorAction Stop
|
||||||
Write-Host " root: $name"
|
Write-Host " removed empty: $cat\"
|
||||||
} catch {
|
} catch {
|
||||||
Write-Warning "Failed to drop $dst : $_"
|
Write-Warning "Failed to remove empty $dir : $_"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
# ============================================================================
|
# ============================================================================
|
||||||
# Scheduled task registration (phase 1 re-run at every logon)
|
# Phase 4: Edge default browser + startup tabs (delegated to 08)
|
||||||
|
#
|
||||||
|
# 08-EdgeDefaultBrowser.ps1 resolves startup-tab URLs from .url files on
|
||||||
|
# the Public Desktop (or in Web Links\ after the sweep). The .url files
|
||||||
|
# are delivered by DSC AFTER this initial shopfloor setup, so the first
|
||||||
|
# run at imaging time won't find them (falls back to hardcoded URLs,
|
||||||
|
# Plant Apps gets skipped). By calling 08 from inside 06, every SYSTEM
|
||||||
|
# scheduled-task logon re-run of 06 also re-runs 08 — so after DSC drops
|
||||||
|
# the .url files and the next sweep files them into Web Links\, 08
|
||||||
|
# picks them up and updates the Edge policy. Self-healing.
|
||||||
|
# ============================================================================
|
||||||
|
function Invoke-EdgeDefaultBrowser {
|
||||||
|
$edgeScript = Join-Path $scriptDir '08-EdgeDefaultBrowser.ps1'
|
||||||
|
if (-not (Test-Path -LiteralPath $edgeScript)) {
|
||||||
|
Write-Host " 08-EdgeDefaultBrowser.ps1 not found - skipping"
|
||||||
|
return
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
& $edgeScript
|
||||||
|
} catch {
|
||||||
|
Write-Warning "08-EdgeDefaultBrowser.ps1 failed: $_"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
# ============================================================================
|
||||||
|
# Scheduled task registration (re-runs 06 at every logon as SYSTEM)
|
||||||
# ============================================================================
|
# ============================================================================
|
||||||
function Register-SweepScheduledTask {
|
function Register-SweepScheduledTask {
|
||||||
param([string]$ScriptPath)
|
param([string]$ScriptPath)
|
||||||
@@ -365,12 +403,16 @@ function Register-SweepScheduledTask {
|
|||||||
|
|
||||||
$trigger = New-ScheduledTaskTrigger -AtLogOn
|
$trigger = New-ScheduledTaskTrigger -AtLogOn
|
||||||
|
|
||||||
# Run as whichever user logs in, at Limited (standard) rights. Public
|
# Run as SYSTEM so the script can (a) pass its admin check at the
|
||||||
# desktop is writable by BUILTIN\Users so no elevation needed. Using
|
# top, (b) write to Public Desktop / ProgramData Start Menu / the
|
||||||
# the well-known Users group SID so this works on non-English Windows.
|
# Default User profile without Access Denied, and (c) register the
|
||||||
|
# next iteration of itself idempotently. Earlier versions used
|
||||||
|
# -GroupId 'BUILTIN\Users' -RunLevel Limited which fired at logon
|
||||||
|
# but the script exited immediately on the non-admin check.
|
||||||
$principal = New-ScheduledTaskPrincipal `
|
$principal = New-ScheduledTaskPrincipal `
|
||||||
-GroupId 'S-1-5-32-545' `
|
-UserId 'NT AUTHORITY\SYSTEM' `
|
||||||
-RunLevel Limited
|
-LogonType ServiceAccount `
|
||||||
|
-RunLevel Highest
|
||||||
|
|
||||||
$settings = New-ScheduledTaskSettingsSet `
|
$settings = New-ScheduledTaskSettingsSet `
|
||||||
-AllowStartIfOnBatteries `
|
-AllowStartIfOnBatteries `
|
||||||
@@ -399,6 +441,20 @@ function Register-SweepScheduledTask {
|
|||||||
# ============================================================================
|
# ============================================================================
|
||||||
# Main
|
# Main
|
||||||
# ============================================================================
|
# ============================================================================
|
||||||
|
Write-Host ""
|
||||||
|
Write-Host "=== Phase 0: create Office shortcuts (if Office is installed) ==="
|
||||||
|
# Delegated to 05-OfficeShortcuts.ps1. Office is installed via ppkg but
|
||||||
|
# doesn't finish streaming until AFTER the first reboot, so the first
|
||||||
|
# imaging-time run of 06 finds no Office and this no-ops. On the second
|
||||||
|
# logon (after reboot), Office is installed and 05 creates the shortcuts
|
||||||
|
# so Phase 1 below can sweep them into the Office\ folder.
|
||||||
|
$officeScript = Join-Path $scriptDir '05-OfficeShortcuts.ps1'
|
||||||
|
if (Test-Path -LiteralPath $officeScript) {
|
||||||
|
try { & $officeScript } catch { Write-Warning "05-OfficeShortcuts.ps1 failed: $_" }
|
||||||
|
} else {
|
||||||
|
Write-Host " 05-OfficeShortcuts.ps1 not found - skipping"
|
||||||
|
}
|
||||||
|
|
||||||
Write-Host ""
|
Write-Host ""
|
||||||
Write-Host "=== Phase 1: sweep loose shortcuts into category folders ==="
|
Write-Host "=== Phase 1: sweep loose shortcuts into category folders ==="
|
||||||
Invoke-DesktopSweep -DesktopPath $publicDesktop
|
Invoke-DesktopSweep -DesktopPath $publicDesktop
|
||||||
@@ -408,11 +464,15 @@ Write-Host "=== Phase 2: populate Shopfloor Tools with app shortcuts ==="
|
|||||||
Add-ShopfloorToolsApps
|
Add-ShopfloorToolsApps
|
||||||
|
|
||||||
Write-Host ""
|
Write-Host ""
|
||||||
Write-Host "=== Phase 3: drop eDNC / NTLARS at desktop root ==="
|
Write-Host "=== Phase 3: remove empty category folders ==="
|
||||||
Update-DesktopRootPins
|
Remove-EmptyCategoryFolders
|
||||||
|
|
||||||
Write-Host ""
|
Write-Host ""
|
||||||
Write-Host "=== Phase 4: register logon sweeper scheduled task ==="
|
Write-Host "=== Phase 4: Edge default browser + startup tabs ==="
|
||||||
|
Invoke-EdgeDefaultBrowser
|
||||||
|
|
||||||
|
Write-Host ""
|
||||||
|
Write-Host "=== Phase 5: register logon sweeper scheduled task ==="
|
||||||
Register-SweepScheduledTask -ScriptPath $scriptPath
|
Register-SweepScheduledTask -ScriptPath $scriptPath
|
||||||
|
|
||||||
exit 0
|
exit 0
|
||||||
|
|||||||
@@ -7,9 +7,7 @@
|
|||||||
# This script does NOT create, move, or copy any shortcuts - all shortcut
|
# This script does NOT create, move, or copy any shortcuts - all shortcut
|
||||||
# management lives in 06. 07 is the last-mile taskbar config only.
|
# management lives in 06. 07 is the last-mile taskbar config only.
|
||||||
#
|
#
|
||||||
# Pin order (left to right): Edge, WJ Shopfloor, UDC, eDNC, Defect_Tracker.
|
# Pin order (left to right): Edge, WJ Shopfloor, UDC, eDNC, NTLARS, Defect_Tracker.
|
||||||
# NTLARS is intentionally not pinned - per the original spec it lives on
|
|
||||||
# the desktop root only.
|
|
||||||
#
|
#
|
||||||
# LayoutModification.xml is written to the Default User profile shell
|
# LayoutModification.xml is written to the Default User profile shell
|
||||||
# directory, which means the pins apply on FIRST LOGON of any new user
|
# directory, which means the pins apply on FIRST LOGON of any new user
|
||||||
|
|||||||
@@ -196,7 +196,7 @@ function Resolve-StartupUrl {
|
|||||||
# Tab order as requested: Plant Apps, Shop Floor Homepage, Shopfloor Dashboard
|
# Tab order as requested: Plant Apps, Shop Floor Homepage, Shopfloor Dashboard
|
||||||
$startupTabs = @()
|
$startupTabs = @()
|
||||||
|
|
||||||
$plantApps = Resolve-StartupUrl -BaseName 'Plant Apps'
|
$plantApps = Resolve-StartupUrl -BaseName 'Plant Apps' -Fallback 'https://mes-wjefferson.apps.lr.geaerospace.net/run/?app_name=Plant%20Applications'
|
||||||
if ($plantApps) { $startupTabs += $plantApps }
|
if ($plantApps) { $startupTabs += $plantApps }
|
||||||
|
|
||||||
$shopFloorHome = Resolve-StartupUrl -BaseName 'WJ Shop Floor Homepage' -Fallback 'http://tsgwp00524.logon.ds.ge.com/'
|
$shopFloorHome = Resolve-StartupUrl -BaseName 'WJ Shop Floor Homepage' -Fallback 'http://tsgwp00524.logon.ds.ge.com/'
|
||||||
|
|||||||
158
playbook/shopfloor-setup/Shopfloor/Check-MachineNumber.ps1
Normal file
158
playbook/shopfloor-setup/Shopfloor/Check-MachineNumber.ps1
Normal file
@@ -0,0 +1,158 @@
|
|||||||
|
# Check-MachineNumber.ps1 - Logon-triggered check for placeholder machine
|
||||||
|
# number. If UDC or eDNC are still at 9999, pops an InputBox for the user
|
||||||
|
# to enter the real number. On success, unregisters the scheduled task so
|
||||||
|
# the prompt never appears again.
|
||||||
|
#
|
||||||
|
# Runs as the LOGGED-IN USER (not SYSTEM) because it needs to show GUI.
|
||||||
|
# Writing to ProgramData + HKLM is possible because 02-MachineNumberACLs.ps1
|
||||||
|
# pre-granted BUILTIN\Users write access on those specific targets during
|
||||||
|
# imaging.
|
||||||
|
#
|
||||||
|
# Registered/unregistered by Configure-PC.ps1 (item 6 in the toggle list).
|
||||||
|
|
||||||
|
# --- 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 'Check-MachineNumber.log'
|
||||||
|
try { Start-Transcript -Path $transcriptPath -Append -Force | Out-Null } catch {}
|
||||||
|
Write-Host "Check-MachineNumber.ps1 starting $(Get-Date -Format 'yyyy-MM-dd HH:mm:ss')"
|
||||||
|
Write-Host "Running as: $([System.Security.Principal.WindowsIdentity]::GetCurrent().Name)"
|
||||||
|
|
||||||
|
Add-Type -AssemblyName Microsoft.VisualBasic
|
||||||
|
Add-Type -AssemblyName System.Windows.Forms
|
||||||
|
|
||||||
|
$taskName = 'Check Machine Number'
|
||||||
|
$udcSettingsPath = 'C:\ProgramData\UDC\udc_settings.json'
|
||||||
|
$udcExePath = 'C:\Program Files\UDC\UDC.exe'
|
||||||
|
$ednRegPath = 'HKLM:\SOFTWARE\WOW6432Node\GE Aircraft Engines\DNC\General'
|
||||||
|
$site = 'West Jefferson'
|
||||||
|
|
||||||
|
# --- Read current values ---
|
||||||
|
$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 {}
|
||||||
|
}
|
||||||
|
|
||||||
|
# --- Check if placeholder ---
|
||||||
|
Write-Host "UDC machine number: $(if ($currentUdc) { $currentUdc } else { '(not found)' })"
|
||||||
|
Write-Host "eDNC machine number: $(if ($currentEdnc) { $currentEdnc } else { '(not found)' })"
|
||||||
|
|
||||||
|
if ($currentUdc -ne '9999' -and $currentEdnc -ne '9999') {
|
||||||
|
Write-Host "Machine number is set (not 9999). Unregistering task and exiting."
|
||||||
|
try {
|
||||||
|
Unregister-ScheduledTask -TaskName $taskName -Confirm:$false -ErrorAction SilentlyContinue
|
||||||
|
} catch {}
|
||||||
|
try { Stop-Transcript | Out-Null } catch {}
|
||||||
|
exit 0
|
||||||
|
}
|
||||||
|
|
||||||
|
Write-Host "Placeholder 9999 detected - showing prompt."
|
||||||
|
|
||||||
|
# --- Show prompt ---
|
||||||
|
$promptLines = @()
|
||||||
|
$promptLines += "The machine number on this PC is still set to the"
|
||||||
|
$promptLines += "placeholder value (9999). Please enter the correct"
|
||||||
|
$promptLines += "machine number for this workstation."
|
||||||
|
$promptLines += ""
|
||||||
|
if ($currentUdc) { $promptLines += "Current UDC: $currentUdc" }
|
||||||
|
if ($currentEdnc) { $promptLines += "Current eDNC: $currentEdnc" }
|
||||||
|
$promptLines += ""
|
||||||
|
$promptLines += "Enter the new Machine Number:"
|
||||||
|
|
||||||
|
$prompt = $promptLines -join "`n"
|
||||||
|
$new = [Microsoft.VisualBasic.Interaction]::InputBox($prompt, "Set Machine Number", "")
|
||||||
|
|
||||||
|
if ([string]::IsNullOrWhiteSpace($new)) {
|
||||||
|
Write-Host "User cancelled. Will prompt again next logon."
|
||||||
|
try { Stop-Transcript | Out-Null } catch {}
|
||||||
|
exit 0
|
||||||
|
}
|
||||||
|
|
||||||
|
$new = $new.Trim()
|
||||||
|
|
||||||
|
# --- Validate ---
|
||||||
|
if ($new -notmatch '^\d+$') {
|
||||||
|
Write-Host "Invalid input: '$new' (not digits only). Will prompt again next logon."
|
||||||
|
[System.Windows.Forms.MessageBox]::Show(
|
||||||
|
"Machine number must be digits only.`n`nYou entered: '$new'`n`nThe prompt will appear again at next logon.",
|
||||||
|
"Invalid Machine Number",
|
||||||
|
[System.Windows.Forms.MessageBoxButtons]::OK,
|
||||||
|
[System.Windows.Forms.MessageBoxIcon]::Error
|
||||||
|
) | Out-Null
|
||||||
|
try { Stop-Transcript | Out-Null } catch {}
|
||||||
|
exit 0
|
||||||
|
}
|
||||||
|
|
||||||
|
# --- Update UDC ---
|
||||||
|
$results = @()
|
||||||
|
if (Test-Path $udcSettingsPath) {
|
||||||
|
# Stop UDC first
|
||||||
|
Get-Process UDC -ErrorAction SilentlyContinue | ForEach-Object {
|
||||||
|
try { $_.Kill(); $_.WaitForExit(5000) | Out-Null } catch {}
|
||||||
|
}
|
||||||
|
Start-Sleep -Seconds 1
|
||||||
|
|
||||||
|
try {
|
||||||
|
$json = Get-Content $udcSettingsPath -Raw | ConvertFrom-Json
|
||||||
|
$json.GeneralSettings.MachineNumber = $new
|
||||||
|
$json | ConvertTo-Json -Depth 99 | Set-Content -Path $udcSettingsPath -Encoding UTF8
|
||||||
|
$results += "UDC updated to $new"
|
||||||
|
} catch {
|
||||||
|
$results += "UDC FAILED: $_"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
# --- Update eDNC ---
|
||||||
|
if (Test-Path $ednRegPath) {
|
||||||
|
try {
|
||||||
|
Set-ItemProperty -Path $ednRegPath -Name MachineNo -Value $new -Type String -Force
|
||||||
|
$results += "eDNC updated to $new"
|
||||||
|
} catch {
|
||||||
|
$results += "eDNC FAILED: $_"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
# --- Relaunch UDC ---
|
||||||
|
if (Test-Path $udcExePath) {
|
||||||
|
try {
|
||||||
|
Start-Process -FilePath $udcExePath -ArgumentList @('-site', "`"$site`"", '-machine', $new)
|
||||||
|
} catch {}
|
||||||
|
}
|
||||||
|
|
||||||
|
# --- Show result ---
|
||||||
|
$summary = ($results -join "`n") + "`n`nTo apply eDNC changes, restart any running DncMain.exe."
|
||||||
|
[System.Windows.Forms.MessageBox]::Show(
|
||||||
|
$summary,
|
||||||
|
"Machine Number Updated",
|
||||||
|
[System.Windows.Forms.MessageBoxButtons]::OK,
|
||||||
|
[System.Windows.Forms.MessageBoxIcon]::Information
|
||||||
|
) | Out-Null
|
||||||
|
|
||||||
|
# --- Unregister task on success ---
|
||||||
|
Write-Host "Results: $($results -join '; ')"
|
||||||
|
$anyFail = $results | Where-Object { $_ -match 'FAILED' }
|
||||||
|
if (-not $anyFail) {
|
||||||
|
Write-Host "All updates succeeded. Unregistering logon task."
|
||||||
|
try {
|
||||||
|
Unregister-ScheduledTask -TaskName $taskName -Confirm:$false -ErrorAction SilentlyContinue
|
||||||
|
} catch {}
|
||||||
|
} else {
|
||||||
|
Write-Host "Some updates failed. Task stays registered - will prompt again next logon."
|
||||||
|
}
|
||||||
|
|
||||||
|
Write-Host "Check-MachineNumber.ps1 finished $(Get-Date -Format 'yyyy-MM-dd HH:mm:ss')"
|
||||||
|
try { Stop-Transcript | Out-Null } catch {}
|
||||||
|
exit 0
|
||||||
23
playbook/shopfloor-setup/Shopfloor/Configure-PC.bat
Normal file
23
playbook/shopfloor-setup/Shopfloor/Configure-PC.bat
Normal file
@@ -0,0 +1,23 @@
|
|||||||
|
@echo off
|
||||||
|
REM Configure-PC.bat - Launches Configure-PC.ps1 in an elevated PowerShell.
|
||||||
|
REM SupportUser desktop tool for setting machine number + auto-startup items.
|
||||||
|
|
||||||
|
title Configure PC
|
||||||
|
|
||||||
|
set "SCRIPT=%~dp0Configure-PC.ps1"
|
||||||
|
if exist "%SCRIPT%" goto :found
|
||||||
|
|
||||||
|
set "SCRIPT=C:\Users\SupportUser\Desktop\Configure-PC.ps1"
|
||||||
|
if exist "%SCRIPT%" goto :found
|
||||||
|
|
||||||
|
set "SCRIPT=C:\Enrollment\shopfloor-setup\Shopfloor\Configure-PC.ps1"
|
||||||
|
if exist "%SCRIPT%" goto :found
|
||||||
|
|
||||||
|
echo ERROR: Configure-PC.ps1 not found
|
||||||
|
pause
|
||||||
|
exit /b 1
|
||||||
|
|
||||||
|
:found
|
||||||
|
echo Launching: %SCRIPT%
|
||||||
|
powershell -NoProfile -Command "Start-Process powershell.exe -Verb RunAs -ArgumentList '-NoProfile','-NoExit','-ExecutionPolicy','Bypass','-File','%SCRIPT%'"
|
||||||
|
exit /b
|
||||||
414
playbook/shopfloor-setup/Shopfloor/Configure-PC.ps1
Normal file
414
playbook/shopfloor-setup/Shopfloor/Configure-PC.ps1
Normal file
@@ -0,0 +1,414 @@
|
|||||||
|
# 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) }
|
||||||
55
playbook/shopfloor-setup/Standard/02-MachineNumberACLs.ps1
Normal file
55
playbook/shopfloor-setup/Standard/02-MachineNumberACLs.ps1
Normal file
@@ -0,0 +1,55 @@
|
|||||||
|
# 02-MachineNumberACLs.ps1 - Pre-grant write access on the UDC settings
|
||||||
|
# file and eDNC registry key so that STANDARD (non-admin) users can update
|
||||||
|
# the machine number via the Check-MachineNumber logon task without
|
||||||
|
# elevation or a UAC prompt.
|
||||||
|
#
|
||||||
|
# Runs during imaging as admin (type-specific Standard phase, after
|
||||||
|
# 01-eDNC.ps1 has installed DnC). Only touches Standard PCs.
|
||||||
|
#
|
||||||
|
# What gets opened up (narrow scope, not blanket admin):
|
||||||
|
# - C:\ProgramData\UDC\udc_settings.json -> BUILTIN\Users : Modify
|
||||||
|
# - HKLM:\SOFTWARE\WOW6432Node\GE Aircraft Engines\DNC\General
|
||||||
|
# -> BUILTIN\Users : SetValue
|
||||||
|
|
||||||
|
Write-Host "02-MachineNumberACLs.ps1 starting $(Get-Date -Format 'yyyy-MM-dd HH:mm:ss')"
|
||||||
|
Write-Host "Running as: $([System.Security.Principal.WindowsIdentity]::GetCurrent().Name)"
|
||||||
|
Write-Host ""
|
||||||
|
Write-Host "Setting ACLs for standard-user machine number access..."
|
||||||
|
|
||||||
|
# --- UDC settings JSON ---
|
||||||
|
$udcJson = 'C:\ProgramData\UDC\udc_settings.json'
|
||||||
|
if (Test-Path -LiteralPath $udcJson) {
|
||||||
|
try {
|
||||||
|
$acl = Get-Acl -LiteralPath $udcJson
|
||||||
|
$rule = New-Object System.Security.AccessControl.FileSystemAccessRule(
|
||||||
|
'BUILTIN\Users', 'Modify', 'Allow')
|
||||||
|
$acl.AddAccessRule($rule)
|
||||||
|
Set-Acl -LiteralPath $udcJson -AclObject $acl -ErrorAction Stop
|
||||||
|
Write-Host " UDC JSON: BUILTIN\Users granted Modify on $udcJson"
|
||||||
|
} catch {
|
||||||
|
Write-Warning " Failed to set ACL on $udcJson : $_"
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
Write-Host " UDC JSON not found at $udcJson - skipping (UDC not installed?)" -ForegroundColor DarkGray
|
||||||
|
}
|
||||||
|
|
||||||
|
# --- eDNC registry key ---
|
||||||
|
$ednRegPathWin = 'SOFTWARE\WOW6432Node\GE Aircraft Engines\DNC\General'
|
||||||
|
try {
|
||||||
|
$regKey = [Microsoft.Win32.Registry]::LocalMachine.OpenSubKey($ednRegPathWin, $true)
|
||||||
|
if ($regKey) {
|
||||||
|
$regSec = $regKey.GetAccessControl()
|
||||||
|
$rule = New-Object System.Security.AccessControl.RegistryAccessRule(
|
||||||
|
'BUILTIN\Users', 'SetValue', 'Allow')
|
||||||
|
$regSec.AddAccessRule($rule)
|
||||||
|
$regKey.SetAccessControl($regSec)
|
||||||
|
$regKey.Close()
|
||||||
|
Write-Host " eDNC reg: BUILTIN\Users granted SetValue on HKLM:\$ednRegPathWin"
|
||||||
|
} else {
|
||||||
|
Write-Host " eDNC registry key not found - skipping (eDNC not installed?)" -ForegroundColor DarkGray
|
||||||
|
}
|
||||||
|
} catch {
|
||||||
|
Write-Warning " Failed to set ACL on HKLM:\$ednRegPathWin : $_"
|
||||||
|
}
|
||||||
|
|
||||||
|
Write-Host "ACL setup complete."
|
||||||
Reference in New Issue
Block a user