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:
@@ -21,14 +21,25 @@ $officeApps = @(
|
||||
@{ Exe = 'POWERPNT.EXE'; Name = 'PowerPoint' }
|
||||
)
|
||||
|
||||
# Office binary location depends on x86 vs x64 install. The standard ShopFloor
|
||||
# Office ppkg is x86 (GCCH_Prod_SFLD_StdOffice-x86_*) so it lands under
|
||||
# Program Files (x86), but we check both so the script works either way.
|
||||
$officeRoot = $null
|
||||
foreach ($base in @(
|
||||
# Office binary location varies by install type and version:
|
||||
# - Office 2019+ / M365 / LTSC Click-to-Run: <PF>\Microsoft Office\root\Office16\
|
||||
# - Office 2016 MSI (legacy): <PF>\Microsoft Office\Office16\ (no root\)
|
||||
# - Office 2013 MSI: <PF>\Microsoft Office\Office15\
|
||||
# - 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 (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')) {
|
||||
$officeRoot = $base
|
||||
break
|
||||
@@ -37,6 +48,11 @@ foreach ($base in @(
|
||||
|
||||
if (-not $officeRoot) {
|
||||
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
|
||||
}
|
||||
|
||||
|
||||
@@ -49,14 +49,13 @@ if (-not $isAdmin) {
|
||||
$publicDesktop = 'C:\Users\Public\Desktop'
|
||||
$shopfloorToolsDir = Join-Path $publicDesktop 'Shopfloor Tools'
|
||||
$scriptPath = $MyInvocation.MyCommand.Path
|
||||
$scriptDir = Split-Path -Parent $scriptPath
|
||||
|
||||
# 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
|
||||
# friction. Phase 2 also drops these here as a post-sweep safety net.
|
||||
$keepAtRoot = @(
|
||||
'eDNC.lnk',
|
||||
'NTLARS.lnk'
|
||||
)
|
||||
# Empty right now - every shortcut lives inside a category folder for a
|
||||
# clean end-user desktop. Add entries here if a future shortcut needs to
|
||||
# stay pinned at root.
|
||||
$keepAtRoot = @()
|
||||
|
||||
# ============================================================================
|
||||
# Phase 1: Sweep loose shortcuts at desktop root into category folders
|
||||
@@ -109,17 +108,11 @@ function Invoke-DesktopSweep {
|
||||
}
|
||||
}
|
||||
|
||||
# Ensure category folders exist
|
||||
foreach ($cat in $categories.Keys) {
|
||||
$dir = Join-Path $DesktopPath $cat
|
||||
if (-not (Test-Path -LiteralPath $dir)) {
|
||||
try {
|
||||
New-Item -ItemType Directory -Path $dir -Force -ErrorAction Stop | Out-Null
|
||||
} catch {
|
||||
Write-Warning "Failed to create category folder '$cat' : $_"
|
||||
}
|
||||
}
|
||||
}
|
||||
# Category folders are created LAZILY - only when we're about to move
|
||||
# something into them - so a Display / Wax-Trace PC without Office
|
||||
# doesn't get an empty Office\ folder littering the desktop. See
|
||||
# Remove-EmptyCategoryFolders at the end of the script for the
|
||||
# post-sweep cleanup pass that finishes the job.
|
||||
|
||||
# WScript.Shell for resolving .lnk targets
|
||||
$shell = $null
|
||||
@@ -187,7 +180,15 @@ function Invoke-DesktopSweep {
|
||||
}
|
||||
|
||||
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
|
||||
try {
|
||||
Move-Item -LiteralPath $item.FullName -Destination $destPath -Force -ErrorAction Stop
|
||||
@@ -269,17 +270,10 @@ function Find-ExistingLnk {
|
||||
}
|
||||
|
||||
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
|
||||
# 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 = 'existing' -> copy an existing .lnk via Find-ExistingLnk
|
||||
@@ -291,12 +285,29 @@ function Add-ShopfloorToolsApps {
|
||||
@{ 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) {
|
||||
$dest = Join-Path $shopfloorToolsDir "$($app.Name).lnk"
|
||||
|
||||
switch ($app.Kind) {
|
||||
'exe' {
|
||||
if (Test-Path -LiteralPath $app.ExePath) {
|
||||
if (-not (& $ensureToolsDir)) { break }
|
||||
if (New-ShopfloorLnk -Path $dest -Target $app.ExePath) {
|
||||
Write-Host " created: $($app.Name) -> $dest"
|
||||
}
|
||||
@@ -308,6 +319,7 @@ function Add-ShopfloorToolsApps {
|
||||
'existing' {
|
||||
$src = Find-ExistingLnk $app.SourceName
|
||||
if ($src) {
|
||||
if (-not (& $ensureToolsDir)) { break }
|
||||
try {
|
||||
Copy-Item -LiteralPath $src -Destination $dest -Force -ErrorAction Stop
|
||||
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
|
||||
# in the sweep, and also force-dropped here (copied from the Shopfloor
|
||||
# Tools\ versions we just created) so a sweep-and-forget user still ends
|
||||
# up with them loose at the root.
|
||||
# If the sweep classified nothing into a given category (e.g. no Office
|
||||
# on a Display PC, no Shopfloor Tools apps on a kiosk), we don't want an
|
||||
# empty folder cluttering the desktop. The scheduled-task sweep also runs
|
||||
# this so categories that go empty between logons self-heal.
|
||||
# ============================================================================
|
||||
function Update-DesktopRootPins {
|
||||
foreach ($name in @('eDNC.lnk', 'NTLARS.lnk')) {
|
||||
$src = Join-Path $shopfloorToolsDir $name
|
||||
$dst = Join-Path $publicDesktop $name
|
||||
if (Test-Path -LiteralPath $src) {
|
||||
function Remove-EmptyCategoryFolders {
|
||||
foreach ($cat in @('Office', 'Shopfloor Tools', 'Web Links')) {
|
||||
$dir = Join-Path $publicDesktop $cat
|
||||
if (-not (Test-Path -LiteralPath $dir)) { continue }
|
||||
$contents = @(Get-ChildItem -LiteralPath $dir -Force -ErrorAction SilentlyContinue)
|
||||
if ($contents.Count -eq 0) {
|
||||
try {
|
||||
Copy-Item -LiteralPath $src -Destination $dst -Force -ErrorAction Stop
|
||||
Write-Host " root: $name"
|
||||
Remove-Item -LiteralPath $dir -Force -ErrorAction Stop
|
||||
Write-Host " removed empty: $cat\"
|
||||
} 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 {
|
||||
param([string]$ScriptPath)
|
||||
@@ -365,12 +403,16 @@ function Register-SweepScheduledTask {
|
||||
|
||||
$trigger = New-ScheduledTaskTrigger -AtLogOn
|
||||
|
||||
# Run as whichever user logs in, at Limited (standard) rights. Public
|
||||
# desktop is writable by BUILTIN\Users so no elevation needed. Using
|
||||
# the well-known Users group SID so this works on non-English Windows.
|
||||
# Run as SYSTEM so the script can (a) pass its admin check at the
|
||||
# top, (b) write to Public Desktop / ProgramData Start Menu / the
|
||||
# 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 `
|
||||
-GroupId 'S-1-5-32-545' `
|
||||
-RunLevel Limited
|
||||
-UserId 'NT AUTHORITY\SYSTEM' `
|
||||
-LogonType ServiceAccount `
|
||||
-RunLevel Highest
|
||||
|
||||
$settings = New-ScheduledTaskSettingsSet `
|
||||
-AllowStartIfOnBatteries `
|
||||
@@ -399,6 +441,20 @@ function Register-SweepScheduledTask {
|
||||
# ============================================================================
|
||||
# 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 "=== Phase 1: sweep loose shortcuts into category folders ==="
|
||||
Invoke-DesktopSweep -DesktopPath $publicDesktop
|
||||
@@ -408,11 +464,15 @@ Write-Host "=== Phase 2: populate Shopfloor Tools with app shortcuts ==="
|
||||
Add-ShopfloorToolsApps
|
||||
|
||||
Write-Host ""
|
||||
Write-Host "=== Phase 3: drop eDNC / NTLARS at desktop root ==="
|
||||
Update-DesktopRootPins
|
||||
Write-Host "=== Phase 3: remove empty category folders ==="
|
||||
Remove-EmptyCategoryFolders
|
||||
|
||||
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
|
||||
|
||||
exit 0
|
||||
|
||||
@@ -7,9 +7,7 @@
|
||||
# This script does NOT create, move, or copy any shortcuts - all shortcut
|
||||
# management lives in 06. 07 is the last-mile taskbar config only.
|
||||
#
|
||||
# Pin order (left to right): Edge, WJ Shopfloor, UDC, eDNC, Defect_Tracker.
|
||||
# NTLARS is intentionally not pinned - per the original spec it lives on
|
||||
# the desktop root only.
|
||||
# Pin order (left to right): Edge, WJ Shopfloor, UDC, eDNC, NTLARS, Defect_Tracker.
|
||||
#
|
||||
# LayoutModification.xml is written to the Default User profile shell
|
||||
# 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
|
||||
$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 }
|
||||
|
||||
$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) }
|
||||
Reference in New Issue
Block a user