Generic build for other GE sites: no WJ data, one shopfloor type, Windows USB builder
Everything West Jefferson specific moved out to a separate repo (pxe-site-wj): NTLARS/UDC/heat-treat backups keyed by WJ machine numbers, CMM and Wax/Trace bay lists, WJ OpenText profiles, site-config.json, the WJ preinstall list, and the WJ shopfloor PC types (Collections, NoCollections, Common, Keyence, CMM, Genspect, HeatTreat, Wax/Trace, Display, PartMarker) with GE-Enforce, machine numbers and the desktop layout. The part-marker bench tools moved to their own repo. Dead scripts removed: build-proxmox-iso, deploy-bios, sync_hardware_models, mirror-from-gold, pull-bios, startnet-template.cmd. Shopfloor is one generic type, gea-shopfloor-standard, with today's timing: - PPKG at first logon (unattend Order 10, unchanged). - Install-AppList.ps1 runs C:\PreInstall\preinstall.json during setup. - A new SYSTEM task, GE Shopfloor Post-PPKG, runs postppkg.json once after the post-PPKG reboot. It also clears AutoLogonCount after the ShopFloor handover (the Users-level monitor can be denied that HKLM write) and removes the Intune Sync task when done. - Both lists ship empty. A site adds entries and installers. - WinPE choice 3 goes straight to the PPKG menu. Staging, fetch and heal carry only the generic payload. The webapp's shopfloor sub-menu editor is gone, and the imaging tiles name the new stages. - The playbook deploys the empty lists only if missing. It now deploys the PowerShell 7 MSI the shopfloor unattend installs, which it never did before. Blancco site settings move into the webapp (Updates > Blancco releases): business location, licensing Wi-Fi SSID and password. They are rendered into the served preferences.xml and applied to every staged release, and are seeded from site-vars (site_name, blancco_wifi_ssid, blancco_wifi_password) only while none exist. The repo XML carries no site values; the plaintext Wi-Fi password is gone from it. New site_name and site_timezone settings: report and evidence-pack site name, server clock and webapp time zone. No more West Jefferson defaults in webapp/config.py or the dashboard title. Sync-BPRT.ps1 gets the server address filled in at download instead of WJ's GE address. USB on Windows: - scripts/Build-PxeUsb.ps1 runs the same checks as build-usb.sh. It writes one FAT32 CIDATA partition (ISO files plus patched grub.cfg plus payload) with diskpart and reads every file back by SHA-256. - Tested with Windows PowerShell 5.1 in the win11 VM, and the layout installs and first-boots in the pxetest VM. - scripts/stage-usb-share.sh stages the build folder on a share. - site-content/ is optional for both builders. KB docs/kb/How_To_Deploy_PXE_Server_New_Site.html: new-site deployment, Windows only, with a site-vars.yml guide. Checks: webapp tests pass (5 suites); the unattend lint and playbook syntax checks pass; every .ps1 parses; there are no WJ hosts, IPs, names or PC types in playbook/, webapp/, scripts/ or autoinstall/.
This commit is contained in:
@@ -1,23 +0,0 @@
|
||||
@echo off
|
||||
REM Install-AcroReader.cmd - Install Adobe Acrobat Reader DC + DC update patch
|
||||
REM
|
||||
REM Two-step install: base MSI with enterprise transform, then DC update patch.
|
||||
REM Same version as the GEA-Engineering image (specialize pass Orders 22-23).
|
||||
REM Files staged by startnet.cmd from enrollment share to C:\PreInstall\installers\adobe\.
|
||||
|
||||
echo Installing Adobe Acrobat Reader DC...
|
||||
msiexec /i "%~dp0AcroRead.msi" TRANSFORMS="%~dp0AcroRead.mst" /quiet /norestart
|
||||
if %errorlevel% neq 0 if %errorlevel% neq 3010 (
|
||||
echo Acrobat Reader MSI failed with exit code %errorlevel%
|
||||
exit /b %errorlevel%
|
||||
)
|
||||
|
||||
echo Applying Adobe Reader DC update patch...
|
||||
msiexec /p "%~dp0AcroRdrDCUpd2500120531.msp" /quiet /norestart
|
||||
if %errorlevel% neq 0 if %errorlevel% neq 3010 (
|
||||
echo Acrobat Reader patch failed with exit code %errorlevel%
|
||||
exit /b %errorlevel%
|
||||
)
|
||||
|
||||
echo Adobe Acrobat Reader DC installed successfully.
|
||||
exit /b 0
|
||||
@@ -1,43 +0,0 @@
|
||||
@echo off
|
||||
REM Install-KioskApp.cmd - Install Lobby Display or Dashboard kiosk app
|
||||
REM
|
||||
REM Reads C:\Enrollment\display-type.txt to determine which app to install.
|
||||
REM Only runs on Display PCs (PCTypes filter in preinstall.json).
|
||||
REM Both installers live alongside this script in the staged display\ subtree.
|
||||
|
||||
set "TYPEFILE=C:\Enrollment\display-type.txt"
|
||||
|
||||
if not exist "%TYPEFILE%" (
|
||||
echo No display-type.txt found - skipping kiosk app install.
|
||||
exit /b 0
|
||||
)
|
||||
|
||||
set /p DISPLAYTYPE=<"%TYPEFILE%"
|
||||
|
||||
if /i "%DISPLAYTYPE%"=="Lobby" (
|
||||
set "INSTALLER=%~dp0GEAerospaceLobbyDisplaySetup.exe"
|
||||
set "APPNAME=Lobby Display"
|
||||
) else if /i "%DISPLAYTYPE%"=="Dashboard" (
|
||||
set "INSTALLER=%~dp0GEAerospaceDashboardSetup.exe"
|
||||
set "APPNAME=Dashboard"
|
||||
) else (
|
||||
echo Unknown display type: %DISPLAYTYPE%
|
||||
exit /b 1
|
||||
)
|
||||
|
||||
if not exist "%INSTALLER%" (
|
||||
echo %APPNAME% installer not found: %INSTALLER%
|
||||
exit /b 1
|
||||
)
|
||||
|
||||
echo Installing %APPNAME%...
|
||||
"%INSTALLER%" /VERYSILENT /SUPPRESSMSGBOXES /NORESTART /LOG="C:\Logs\PreInstall\%APPNAME%-install.log"
|
||||
set EXITCODE=%errorlevel%
|
||||
|
||||
if %EXITCODE% equ 0 (
|
||||
echo %APPNAME% installed successfully.
|
||||
) else (
|
||||
echo %APPNAME% exited with code %EXITCODE%.
|
||||
)
|
||||
|
||||
exit /b %EXITCODE%
|
||||
@@ -1,46 +0,0 @@
|
||||
@echo off
|
||||
REM Install-Drivers.cmd - Adds bundled INF driver packages to the Windows driver store
|
||||
REM via pnputil. Runs from C:\PreInstall\installers\drivers\ where each vendor
|
||||
REM subdir (prolific\, startech\) sits alongside this script. /subdirs walks into
|
||||
REM them so one call covers every bundled driver.
|
||||
REM
|
||||
REM Writes C:\ProgramData\PXEDrivers\drivers-installed.marker on success so the
|
||||
REM preinstall runner's File DetectionMethod can skip re-runs.
|
||||
|
||||
setlocal
|
||||
|
||||
set LOGDIR=C:\Logs\PreInstall
|
||||
set LOG=%LOGDIR%\Install-Drivers.log
|
||||
set MARKER_DIR=C:\ProgramData\PXEDrivers
|
||||
set MARKER=%MARKER_DIR%\drivers-installed.marker
|
||||
|
||||
if not exist "%LOGDIR%" mkdir "%LOGDIR%"
|
||||
if not exist "%MARKER_DIR%" mkdir "%MARKER_DIR%"
|
||||
|
||||
echo ================================================================ >> "%LOG%"
|
||||
echo [%date% %time%] Install-Drivers session start >> "%LOG%"
|
||||
echo Source dir: %~dp0 >> "%LOG%"
|
||||
echo ================================================================ >> "%LOG%"
|
||||
|
||||
REM pnputil /add-driver with /subdirs recurses into vendor subdirs. /install
|
||||
REM binds the driver to any matching hardware present now; drivers without a
|
||||
REM matching device still land in the driver store and bind on plug-in later.
|
||||
pnputil.exe /add-driver "%~dp0*.inf" /subdirs /install >> "%LOG%" 2>&1
|
||||
set RC=%ERRORLEVEL%
|
||||
|
||||
echo [%date% %time%] pnputil exit code: %RC% >> "%LOG%"
|
||||
|
||||
REM pnputil exit codes:
|
||||
REM 0 success
|
||||
REM 259 ERROR_NO_MORE_ITEMS - no INFs matched (treat as failure)
|
||||
REM 3010 at least one driver installed, reboot recommended (treat as success)
|
||||
if "%RC%"=="0" goto :ok
|
||||
if "%RC%"=="3010" goto :ok
|
||||
|
||||
echo [%date% %time%] FAILED (exit %RC%) >> "%LOG%"
|
||||
exit /b %RC%
|
||||
|
||||
:ok
|
||||
echo [%date% %time%] SUCCESS >> "%LOG%"
|
||||
echo installed %date% %time% > "%MARKER%"
|
||||
exit /b 0
|
||||
@@ -1,38 +0,0 @@
|
||||
# OpenText HostExplorer ShopFloor - install scripts
|
||||
|
||||
These three files are git-tracked snapshots of what lives at runtime
|
||||
in `/home/camp/pxe-images/main/dependencies/opentext/`. The full
|
||||
runtime tree also contains the bundled installer binaries (~106 MB
|
||||
total) which are intentionally NOT in git:
|
||||
|
||||
```
|
||||
OpenTextHostExplorer15x64.msi ~16 MB
|
||||
OpenTextHostExplorer15x64.cab ~86 MB
|
||||
OpenTextHostExplorer15x64_ServicePack1.msp ~4.4 MB
|
||||
ShopFloorx64.mst ~20 KB
|
||||
Profile/ 5 .hep connection profiles
|
||||
Accessories/EB/ 6 .ebs/.ebx macros
|
||||
HostExplorer/Keymap/ 2 .kmv keymaps
|
||||
HostExplorer/Menu/ 2 .hmv menu layouts
|
||||
W10shortcuts/ 4 .lnk public-desktop shortcuts
|
||||
```
|
||||
|
||||
The canonical source for everything (scripts AND binaries) is
|
||||
`/home/camp/pxe-images/main/dependencies/opentext/`. The files in
|
||||
this dir are mirrors that exist so changes to the install logic and
|
||||
the version stamp end up in git history. When editing:
|
||||
|
||||
1. Edit `/home/camp/pxe-images/main/dependencies/opentext/Setup-OpenText.ps1`
|
||||
(or `.cmd` / `version.txt`)
|
||||
2. Re-run `bash playbook/sync-preinstall.sh` to push the runtime tree
|
||||
to the live PXE server
|
||||
3. `cp` the changed file(s) into `playbook/preinstall/opentext/` here
|
||||
so git picks up the change
|
||||
4. Re-upload the changed file(s) to Azure Blob at
|
||||
`prod/main/dependencies/opentext/<filename>`
|
||||
|
||||
To bump OpenText version: edit `version.txt` only - the value flows
|
||||
through to Setup-OpenText.ps1 (which reads it at runtime), to
|
||||
Install-OpenText.ps1 (the DSC wrapper, which downloads version.txt
|
||||
first as a cheap detection check), and to the registry marker at
|
||||
`HKLM:\SOFTWARE\GE\OpenText\Installed`.
|
||||
@@ -1,11 +0,0 @@
|
||||
@echo off
|
||||
REM Setup-OpenText.cmd - tiny launcher for Setup-OpenText.ps1
|
||||
REM
|
||||
REM The PXE PreInstall runner only invokes Type:MSI or Type:EXE entries from
|
||||
REM preinstall.json. This .cmd lives next to Setup-OpenText.ps1 in the staged
|
||||
REM opentext\ subtree and just hands off to PowerShell with bypass policy.
|
||||
REM Both files end up at C:\PreInstall\installers\opentext\ via xcopy /E from
|
||||
REM the WinPE staging step in startnet.cmd.
|
||||
|
||||
powershell -NoProfile -ExecutionPolicy Bypass -File "%~dp0Setup-OpenText.ps1"
|
||||
exit /b %errorlevel%
|
||||
@@ -1,361 +0,0 @@
|
||||
#!/usr/bin/env pwsh
|
||||
# Setup-OpenText.ps1 - OpenText HostExplorer 15 SP1 ShopFloor installer + profile
|
||||
# deployment, callable from both PXE PreInstall and Intune DSC paths.
|
||||
#
|
||||
# WHY THIS EXISTS:
|
||||
# The vendor-supplied OpenText.exe (Inno Setup wrapper built by WJDT) bundles
|
||||
# the install steps but its [Files] section deploys per-user content to
|
||||
# {userappdata} - which resolves to SYSTEM's profile under DSC and to a single
|
||||
# user under PreInstall. As a result the operator (logging in via Azure AD)
|
||||
# never sees the profiles, keymaps, menus, or macros - only the installed
|
||||
# binaries. This script replaces OpenText.exe entirely, doing the same install
|
||||
# steps via direct msiexec calls AND fanning the per-user content out to:
|
||||
# - %ProgramData%\Hummingbird\Connectivity\15.00\Shared\
|
||||
# - C:\Users\Default\AppData\Roaming\Hummingbird\Connectivity\15.00\
|
||||
# - Each existing user profile under C:\Users\
|
||||
#
|
||||
# INVOKED BY:
|
||||
# - PreInstall: Setup-OpenText.cmd wrapper (because the runner only knows MSI/EXE)
|
||||
# - DSC: Install-OpenText.ps1 downloads the bundled tree from blob, then
|
||||
# invokes this script with -SourceDir <temp dir>
|
||||
#
|
||||
# DETECTION:
|
||||
# Skips if HKLM:\SOFTWARE\GE\OpenText\Installed = $expectedVersion. Marker is
|
||||
# written at the end of a successful run, so the runner / DSC wrapper can
|
||||
# no-op on subsequent invocations.
|
||||
|
||||
[CmdletBinding()]
|
||||
param(
|
||||
# Override when invoked from a temp dir (DSC path) where the bundled files were
|
||||
# just downloaded. Defaults to $PSScriptRoot, but resolved INSIDE the script body
|
||||
# below - PowerShell evaluates `param([string]$X = $PSScriptRoot)` at parameter-
|
||||
# binding time, when $PSScriptRoot may not yet be populated, so the default winds
|
||||
# up as an empty string. Setting it in the body works because $PSScriptRoot is
|
||||
# reliably populated by then.
|
||||
[string]$SourceDir
|
||||
)
|
||||
|
||||
$ErrorActionPreference = 'Stop'
|
||||
|
||||
if (-not $SourceDir) {
|
||||
$SourceDir = $PSScriptRoot
|
||||
}
|
||||
|
||||
# Normalize $SourceDir to a canonical absolute path. The CMD shim passes
|
||||
# "%~dp0..\apps\opentext" which embeds a literal "..". msiexec / the Windows
|
||||
# Installer service fail to open the package with that unresolved segment
|
||||
# (exit 1619, ERROR_INSTALL_PACKAGE_OPEN_FAILED), even though every other
|
||||
# .NET / PowerShell API resolves it fine. Resolve-Path collapses ".." into
|
||||
# a clean drive-rooted path before any msiexec invocation.
|
||||
if (Test-Path -LiteralPath $SourceDir) {
|
||||
try { $SourceDir = (Resolve-Path -LiteralPath $SourceDir).ProviderPath } catch {}
|
||||
}
|
||||
|
||||
# --- Inline site-config reader (this script runs from C:\PreInstall\installers\opentext\,
|
||||
# NOT from C:\Enrollment\shopfloor-setup\, so it can't dot-source Get-PCProfile.ps1) ---
|
||||
function Get-SiteConfig {
|
||||
$configPath = 'C:\Enrollment\site-config.json'
|
||||
if (-not (Test-Path $configPath)) { return $null }
|
||||
try {
|
||||
return Get-Content $configPath -Raw | ConvertFrom-Json
|
||||
} catch {
|
||||
return $null
|
||||
}
|
||||
}
|
||||
|
||||
# --- Logging (set up FIRST so any startup error - missing version.txt, broken
|
||||
# bundled file, etc. - lands in the log file instead of disappearing into the
|
||||
# runner's stdout void) ---
|
||||
$logDir = 'C:\Logs\PreInstall'
|
||||
$logFile = Join-Path $logDir 'Setup-OpenText.log'
|
||||
$msiLog = Join-Path $logDir 'Setup-OpenText-msi.log'
|
||||
$mspLog = Join-Path $logDir 'Setup-OpenText-msp.log'
|
||||
|
||||
if (-not (Test-Path $logDir)) {
|
||||
New-Item -Path $logDir -ItemType Directory -Force | Out-Null
|
||||
}
|
||||
|
||||
function Write-SetupLog {
|
||||
param([string]$Message)
|
||||
$line = "[$(Get-Date -Format 'yyyy-MM-dd HH:mm:ss')] $Message"
|
||||
Add-Content -Path $logFile -Value $line -ErrorAction SilentlyContinue
|
||||
Write-Host $line
|
||||
}
|
||||
|
||||
Write-SetupLog "================================================================"
|
||||
Write-SetupLog "=== Setup-OpenText.ps1 starting ==="
|
||||
Write-SetupLog "================================================================"
|
||||
Write-SetupLog "SourceDir: $SourceDir"
|
||||
Write-SetupLog "PSScriptRoot: $PSScriptRoot"
|
||||
Write-SetupLog "Running as: $([System.Security.Principal.WindowsIdentity]::GetCurrent().Name)"
|
||||
|
||||
# --- Config ---
|
||||
# Version is read from version.txt next to this script. ONE source of truth: bumping
|
||||
# version.txt is the only edit needed when shipping a new OpenText build. Setup-
|
||||
# OpenText.ps1 itself, Install-OpenText.ps1 (DSC wrapper), and the registry marker
|
||||
# all derive their notion of "expected version" from this file.
|
||||
$versionFile = Join-Path $SourceDir 'version.txt'
|
||||
Write-SetupLog "Looking for version.txt at: $versionFile"
|
||||
if (-not (Test-Path $versionFile)) {
|
||||
Write-SetupLog "ERROR: version.txt not found in $SourceDir - cannot determine expected version."
|
||||
Write-SetupLog "Directory listing of $SourceDir :"
|
||||
if (Test-Path $SourceDir) {
|
||||
Get-ChildItem $SourceDir -ErrorAction SilentlyContinue | ForEach-Object {
|
||||
Write-SetupLog " $($_.Name) $($_.Length) bytes"
|
||||
}
|
||||
} else {
|
||||
Write-SetupLog " (SourceDir does not exist)"
|
||||
}
|
||||
exit 1
|
||||
}
|
||||
$expectedVersion = (Get-Content -Path $versionFile -Raw -ErrorAction Stop).Trim()
|
||||
if (-not $expectedVersion) {
|
||||
Write-SetupLog "ERROR: version.txt at $versionFile is empty."
|
||||
exit 1
|
||||
}
|
||||
Write-SetupLog "Expected version (from version.txt): $expectedVersion"
|
||||
|
||||
# --- Detection: skip if already deployed at expected version ---
|
||||
$markerKey = 'HKLM:\SOFTWARE\GE\OpenText'
|
||||
$markerVal = 'Installed'
|
||||
if (Test-Path $markerKey) {
|
||||
$installed = (Get-ItemProperty -Path $markerKey -Name $markerVal -ErrorAction SilentlyContinue).$markerVal
|
||||
if ($installed -eq $expectedVersion) {
|
||||
Write-SetupLog "OpenText $expectedVersion already deployed (marker present) - skipping."
|
||||
exit 0
|
||||
}
|
||||
Write-SetupLog "OpenText marker mismatch (found '$installed', expected '$expectedVersion') - re-deploying."
|
||||
}
|
||||
else {
|
||||
Write-SetupLog "OpenText marker not present - first install."
|
||||
}
|
||||
|
||||
# --- Verify bundled files are where we expect ---
|
||||
$msiPath = Join-Path $SourceDir 'OpenTextHostExplorer15x64.msi'
|
||||
$cabPath = Join-Path $SourceDir 'OpenTextHostExplorer15x64.cab'
|
||||
$mspPath = Join-Path $SourceDir 'OpenTextHostExplorer15x64_ServicePack1.msp'
|
||||
$mstPath = Join-Path $SourceDir 'ShopFloorx64.mst'
|
||||
|
||||
foreach ($f in @($msiPath, $cabPath, $mspPath, $mstPath)) {
|
||||
if (-not (Test-Path $f)) {
|
||||
Write-SetupLog "ERROR: required file not found: $f"
|
||||
exit 1
|
||||
}
|
||||
}
|
||||
|
||||
# --- Step 1: Install the base MSI with the ShopFloor transform ---
|
||||
# NOTE: We deliberately do NOT pass REBOOT=ReallySuppress here even though we do
|
||||
# for the VC++ MSIs. OpenText HostExplorer installs shell extensions that hook
|
||||
# explorer.exe, and the MSI uses Restart Manager to ask explorer to close so the
|
||||
# in-use shell DLLs can be replaced. With REBOOT=ReallySuppress, RM closes
|
||||
# explorer.exe but interprets "restart explorer" as a reboot action and refuses
|
||||
# to relaunch it - leaving the user without a desktop. /norestart on its own
|
||||
# prevents the actual Windows reboot but lets RM cleanly close-and-relaunch
|
||||
# explorer mid-install. msiexec still returns 3010 ("reboot would be needed"),
|
||||
# which we treat as success below.
|
||||
Write-SetupLog ""
|
||||
Write-SetupLog "Step 1: Installing OpenTextHostExplorer15x64.msi with ShopFloorx64.mst..."
|
||||
if (Test-Path $msiLog) { Remove-Item $msiLog -Force -ErrorAction SilentlyContinue }
|
||||
|
||||
$msiArgs = "/i `"$msiPath`" TRANSFORMS=`"$mstPath`" /qn /norestart /L*v `"$msiLog`""
|
||||
Write-SetupLog " msiexec.exe $msiArgs"
|
||||
|
||||
$psi = New-Object System.Diagnostics.ProcessStartInfo
|
||||
$psi.FileName = 'msiexec.exe'
|
||||
$psi.Arguments = $msiArgs
|
||||
$psi.UseShellExecute = $false
|
||||
$psi.CreateNoWindow = $true
|
||||
$proc = [System.Diagnostics.Process]::Start($psi)
|
||||
$proc.WaitForExit()
|
||||
$msiExit = $proc.ExitCode
|
||||
Write-SetupLog " msiexec exit code: $msiExit"
|
||||
|
||||
if ($msiExit -ne 0 -and $msiExit -ne 3010) {
|
||||
Write-SetupLog "ERROR: base MSI install failed (exit $msiExit). See $msiLog"
|
||||
exit 1
|
||||
}
|
||||
if ($msiExit -eq 3010) {
|
||||
Write-SetupLog " (3010 = reboot needed but suppressed)"
|
||||
}
|
||||
|
||||
# --- Step 2: Apply Service Pack 1 patch ---
|
||||
# Same Restart Manager rationale as Step 1 - skip REBOOT=ReallySuppress so RM
|
||||
# can relaunch explorer.exe after replacing the patched shell extension DLLs.
|
||||
Write-SetupLog ""
|
||||
Write-SetupLog "Step 2: Applying SP1 patch..."
|
||||
if (Test-Path $mspLog) { Remove-Item $mspLog -Force -ErrorAction SilentlyContinue }
|
||||
|
||||
$mspArgs = "/p `"$mspPath`" /qn /norestart /L*v `"$mspLog`""
|
||||
Write-SetupLog " msiexec.exe $mspArgs"
|
||||
|
||||
$psi.Arguments = $mspArgs
|
||||
$proc = [System.Diagnostics.Process]::Start($psi)
|
||||
$proc.WaitForExit()
|
||||
$mspExit = $proc.ExitCode
|
||||
Write-SetupLog " msiexec exit code: $mspExit"
|
||||
|
||||
if ($mspExit -ne 0 -and $mspExit -ne 3010) {
|
||||
Write-SetupLog "ERROR: SP1 patch failed (exit $mspExit). See $mspLog"
|
||||
exit 1
|
||||
}
|
||||
|
||||
# --- Step 3: Deploy profiles, keymaps, menus, accessories ---
|
||||
# Source layout (bundled with this script):
|
||||
# $SourceDir\Profile\*.hep
|
||||
# $SourceDir\Accessories\EB\*.eb*
|
||||
# $SourceDir\HostExplorer\Keymap\*.kmv
|
||||
# $SourceDir\HostExplorer\Menu\*.hmv
|
||||
#
|
||||
# Target layouts (Hummingbird-canonical):
|
||||
# %ProgramData%\Hummingbird\Connectivity\15.00\Shared\Profile\
|
||||
# %ProgramData%\Hummingbird\Connectivity\15.00\Shared\Accessories\EB\
|
||||
# %ProgramData%\Hummingbird\Connectivity\15.00\Shared\HostExplorer\Keymap\
|
||||
# %ProgramData%\Hummingbird\Connectivity\15.00\Shared\HostExplorer\Menu\
|
||||
# <user>\AppData\Roaming\Hummingbird\Connectivity\15.00\Profile\
|
||||
# <user>\AppData\Roaming\Hummingbird\Connectivity\15.00\Accessories\EB\
|
||||
# <user>\AppData\Roaming\Hummingbird\Connectivity\15.00\HostExplorer\Keymap\
|
||||
# <user>\AppData\Roaming\Hummingbird\Connectivity\15.00\HostExplorer\Menu\
|
||||
#
|
||||
# We deploy to ProgramData\Shared (system-wide fallback), Default User (template
|
||||
# inherited by every NEW user profile), and every existing user profile (so
|
||||
# already-created accounts like SupportUser get them immediately).
|
||||
|
||||
Write-SetupLog ""
|
||||
Write-SetupLog "Step 3: Deploying profiles/keymaps/menus/macros..."
|
||||
|
||||
# --- Resolve exclude lists from site-config.json (falls back to West Jefferson defaults) ---
|
||||
$siteConfig = Get-SiteConfig
|
||||
$profileExcludes = if ($siteConfig -and $siteConfig.opentext -and $siteConfig.opentext.excludeProfiles) {
|
||||
@($siteConfig.opentext.excludeProfiles)
|
||||
} else {
|
||||
@('WJ_Office.hep', 'IBM_qks.hep', 'mmcs.hep') # West Jefferson defaults
|
||||
}
|
||||
$shortcutExcludes = if ($siteConfig -and $siteConfig.opentext -and $siteConfig.opentext.excludeShortcuts) {
|
||||
@($siteConfig.opentext.excludeShortcuts)
|
||||
} else {
|
||||
@('WJ_Office.lnk', 'IBM_qks.lnk', 'mmcs.lnk')
|
||||
}
|
||||
if ($siteConfig) {
|
||||
Write-SetupLog "Site config loaded - profile excludes: $($profileExcludes -join ', ')"
|
||||
Write-SetupLog "Site config loaded - shortcut excludes: $($shortcutExcludes -join ', ')"
|
||||
} else {
|
||||
Write-SetupLog "No site-config.json found - using West Jefferson defaults for excludes"
|
||||
}
|
||||
|
||||
# Map of source subdir -> destination subdir relative to the Hummingbird root.
|
||||
# Optional Exclude list drops specific filenames from both the source-to-dest
|
||||
# copy AND from the destination if they were left over from a prior install.
|
||||
$contentMap = @(
|
||||
@{
|
||||
Src = 'Profile'
|
||||
Dst = 'Profile'
|
||||
Exclude = $profileExcludes
|
||||
}
|
||||
@{ Src = 'Accessories\EB'; Dst = 'Accessories\EB' }
|
||||
@{ Src = 'HostExplorer\Keymap'; Dst = 'HostExplorer\Keymap' }
|
||||
@{ Src = 'HostExplorer\Menu'; Dst = 'HostExplorer\Menu' }
|
||||
)
|
||||
|
||||
function Copy-HummingbirdContent {
|
||||
param(
|
||||
[string]$RootDst, # Hummingbird root, e.g. C:\ProgramData\Hummingbird\Connectivity\15.00\Shared
|
||||
[string]$Label
|
||||
)
|
||||
foreach ($entry in $contentMap) {
|
||||
$srcPath = Join-Path $SourceDir $entry.Src
|
||||
if (-not (Test-Path $srcPath)) { continue }
|
||||
$dstPath = Join-Path $RootDst $entry.Dst
|
||||
New-Item -Path $dstPath -ItemType Directory -Force | Out-Null
|
||||
|
||||
# Remove any previously-deployed excluded files from the destination
|
||||
# - handles the case where a PC got them from an older install.
|
||||
if ($entry.Exclude) {
|
||||
foreach ($name in $entry.Exclude) {
|
||||
$stale = Join-Path $dstPath $name
|
||||
if (Test-Path -LiteralPath $stale) {
|
||||
try {
|
||||
Remove-Item -LiteralPath $stale -Force -ErrorAction Stop
|
||||
Write-SetupLog " $Label : removed stale $name"
|
||||
} catch {
|
||||
Write-SetupLog " $Label : failed to remove $stale : $_"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
$files = Get-ChildItem -Path $srcPath -File -ErrorAction SilentlyContinue
|
||||
if ($entry.Exclude) {
|
||||
$files = @($files | Where-Object { $entry.Exclude -notcontains $_.Name })
|
||||
}
|
||||
foreach ($f in $files) {
|
||||
Copy-Item -Path $f.FullName -Destination $dstPath -Force
|
||||
}
|
||||
Write-SetupLog " $Label : $($entry.Src) -> $dstPath ($($files.Count) files)"
|
||||
}
|
||||
}
|
||||
|
||||
# 3a. ProgramData Shared
|
||||
$sharedRoot = Join-Path $env:ProgramData 'Hummingbird\Connectivity\15.00\Shared'
|
||||
Copy-HummingbirdContent -RootDst $sharedRoot -Label 'Shared'
|
||||
|
||||
# 3b. Default User (template for new user profiles)
|
||||
$defaultUserRoot = 'C:\Users\Default\AppData\Roaming\Hummingbird\Connectivity\15.00'
|
||||
Copy-HummingbirdContent -RootDst $defaultUserRoot -Label 'Default User'
|
||||
|
||||
# 3c. Every existing user profile under C:\Users\
|
||||
$skipNames = @('Default', 'Default User', 'Public', 'defaultuser0', 'All Users', 'WDAGUtilityAccount')
|
||||
$userDirs = Get-ChildItem 'C:\Users' -Directory -ErrorAction SilentlyContinue |
|
||||
Where-Object { $skipNames -notcontains $_.Name -and (Test-Path "$($_.FullName)\AppData\Roaming") }
|
||||
|
||||
foreach ($u in $userDirs) {
|
||||
$userRoot = Join-Path $u.FullName 'AppData\Roaming\Hummingbird\Connectivity\15.00'
|
||||
Copy-HummingbirdContent -RootDst $userRoot -Label $u.Name
|
||||
}
|
||||
|
||||
# --- Step 4: Public Desktop shortcuts ---
|
||||
# Uses $shortcutExcludes (resolved from site-config.json above) to skip
|
||||
# deploying unwanted .lnk files AND remove any a prior install left behind.
|
||||
Write-SetupLog ""
|
||||
Write-SetupLog "Step 4: Deploying public desktop shortcuts..."
|
||||
$shortcutSrc = Join-Path $SourceDir 'W10shortcuts'
|
||||
$publicDesktop = 'C:\Users\Public\Desktop'
|
||||
|
||||
# Clean up stale copies from prior installs first
|
||||
foreach ($name in $shortcutExcludes) {
|
||||
$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) {
|
||||
$lnkFiles = Get-ChildItem -Path $shortcutSrc -Filter '*.lnk' -File -ErrorAction SilentlyContinue
|
||||
foreach ($l in $lnkFiles) {
|
||||
if ($shortcutExcludes -contains $l.Name) {
|
||||
Write-SetupLog " skip (excluded): $($l.Name)"
|
||||
continue
|
||||
}
|
||||
Copy-Item -Path $l.FullName -Destination $publicDesktop -Force
|
||||
Write-SetupLog " $($l.Name) -> $publicDesktop"
|
||||
}
|
||||
}
|
||||
|
||||
# --- Step 5: Write registry marker ---
|
||||
Write-SetupLog ""
|
||||
Write-SetupLog "Step 5: Writing registry marker..."
|
||||
if (-not (Test-Path $markerKey)) {
|
||||
New-Item -Path $markerKey -Force | Out-Null
|
||||
}
|
||||
Set-ItemProperty -Path $markerKey -Name $markerVal -Value $expectedVersion -Force
|
||||
Set-ItemProperty -Path $markerKey -Name 'InstalledAt' -Value (Get-Date -Format 'o') -Force
|
||||
|
||||
Write-SetupLog ""
|
||||
Write-SetupLog "================================================================"
|
||||
Write-SetupLog "=== OpenText HostExplorer ShopFloor $expectedVersion deployed ==="
|
||||
Write-SetupLog "================================================================"
|
||||
exit 0
|
||||
@@ -1 +0,0 @@
|
||||
15.0.SP1.2
|
||||
@@ -1,113 +0,0 @@
|
||||
@echo off
|
||||
REM Install-Oracle11r2.cmd
|
||||
REM Expands the GE Oracle Client 11.2 Administrator zip to a temp dir and
|
||||
REM runs Oracle Universal Installer silently with the GE-customized
|
||||
REM response file.
|
||||
REM
|
||||
REM Accepted zip locations (first hit wins):
|
||||
REM %~dp0Oracle_OracleDatabase_11r2_V03.zip (preinstall flat)
|
||||
REM %~dp0..\apps\Oracle_OracleDatabase_11r2_V03.zip (SFLD share, enforcer)
|
||||
REM
|
||||
REM Called by:
|
||||
REM - preinstall runner (Type=EXE, image build time)
|
||||
REM - Install-FromManifest.ps1 (Type=CMD, runtime enforcer)
|
||||
REM
|
||||
REM Oracle 11.2 OUI exit codes worth knowing:
|
||||
REM 0 = success
|
||||
REM 3 = success but with warnings
|
||||
REM 1 = general failure
|
||||
REM 6 = silent install requested but missing / bad response file
|
||||
|
||||
setlocal enabledelayedexpansion
|
||||
set "LOG=C:\Logs\OracleClient\install.log"
|
||||
if not exist "C:\Logs\OracleClient" mkdir "C:\Logs\OracleClient"
|
||||
|
||||
REM Emit a datestamp
|
||||
for /f "tokens=2 delims==" %%I in ('wmic os get localdatetime /value 2^>nul ^| find "="') do set LDT=%%I
|
||||
set "STAMP=!LDT:~0,14!"
|
||||
|
||||
echo [%STAMP%] Install-Oracle11r2.cmd starting >> "%LOG%"
|
||||
|
||||
set "SRC_ZIP=%~dp0Oracle_OracleDatabase_11r2_V03.zip"
|
||||
if not exist "%SRC_ZIP%" set "SRC_ZIP=%~dp0..\apps\Oracle_OracleDatabase_11r2_V03.zip"
|
||||
set "STAGING=%TEMP%\oracle-11r2-install"
|
||||
set "CLIENT_DIR=%STAGING%\Oracle_OracleDatabase_11r2_V03\client"
|
||||
set "RSP=%CLIENT_DIR%\response\ge_client_install.rsp"
|
||||
|
||||
if not exist "%SRC_ZIP%" (
|
||||
echo [%STAMP%] ERROR: zip not found at %SRC_ZIP% >> "%LOG%"
|
||||
echo ERROR: zip not found at %SRC_ZIP%
|
||||
exit /b 2
|
||||
)
|
||||
|
||||
echo [%STAMP%] Expanding %SRC_ZIP% to %STAGING% >> "%LOG%"
|
||||
if exist "%STAGING%" rmdir /s /q "%STAGING%" >nul 2>&1
|
||||
mkdir "%STAGING%"
|
||||
powershell.exe -NoProfile -ExecutionPolicy Bypass -Command ^
|
||||
"try { Expand-Archive -Path '%SRC_ZIP%' -DestinationPath '%STAGING%' -Force -ErrorAction Stop; exit 0 } catch { Write-Error $_; exit 1 }" ^
|
||||
>> "%LOG%" 2>&1
|
||||
|
||||
if not exist "%CLIENT_DIR%\setup.exe" (
|
||||
echo [%STAMP%] ERROR: expanded setup.exe not found at %CLIENT_DIR%\setup.exe >> "%LOG%"
|
||||
exit /b 3
|
||||
)
|
||||
|
||||
if not exist "%RSP%" (
|
||||
echo [%STAMP%] ERROR: response file missing at %RSP% >> "%LOG%"
|
||||
exit /b 4
|
||||
)
|
||||
|
||||
echo [%STAMP%] Running OUI silent install (this takes 2-8 minutes) >> "%LOG%"
|
||||
"%CLIENT_DIR%\setup.exe" -silent -waitforcompletion -nowait ^
|
||||
-ignoreSysPrereqs ^
|
||||
-responseFile "%RSP%" >> "%LOG%" 2>&1
|
||||
set RC=%ERRORLEVEL%
|
||||
|
||||
echo [%STAMP%] OUI exit code: %RC% >> "%LOG%"
|
||||
|
||||
REM --- Drop GE-customized tnsnames.ora / sqlnet.ora / ldap.ora into ORACLE_HOME.
|
||||
REM The zip ships these in client\ora\ but Oracle's setup.exe does not consume
|
||||
REM them - that copy is the GE Wise wrapper's job, which we bypass. Without
|
||||
REM these, every Oracle-dependent app (eDNC/UDC/NTLARS/CMM tooling) fails with
|
||||
REM ORA-12154 "TNS could not resolve the connect identifier specified".
|
||||
REM
|
||||
REM Per-file override: if %~dp0<name>.ora exists (deployed alongside this
|
||||
REM wrapper on the PXE server / SFLD share), use it instead of the bundled
|
||||
REM copy. Lets us push an updated tnsnames.ora without repackaging the zip.
|
||||
REM
|
||||
REM Only run when OUI succeeded (RC 0 or 3). On failure ORACLE_HOME may not
|
||||
REM be fully populated and the copy targets may not exist.
|
||||
if %RC%==0 goto :do_ora_copy
|
||||
if %RC%==3 goto :do_ora_copy
|
||||
goto :skip_ora_copy
|
||||
|
||||
:do_ora_copy
|
||||
set "ORA_DST=C:\Apps\product\11.2.0\client_1\network\admin"
|
||||
if not exist "%ORA_DST%" (
|
||||
echo [%STAMP%] WARN: %ORA_DST% does not exist after OUI - skipping .ora copy >> "%LOG%"
|
||||
goto :skip_ora_copy
|
||||
)
|
||||
for %%F in (tnsnames.ora sqlnet.ora ldap.ora) do (
|
||||
set "ORA_SRC=%~dp0%%F"
|
||||
if not exist "!ORA_SRC!" set "ORA_SRC=%CLIENT_DIR%\ora\%%F"
|
||||
if exist "!ORA_SRC!" (
|
||||
echo [%STAMP%] Copying %%F from !ORA_SRC! to %ORA_DST%\%%F >> "%LOG%"
|
||||
copy /Y "!ORA_SRC!" "%ORA_DST%\%%F" >> "%LOG%" 2>&1
|
||||
) else (
|
||||
echo [%STAMP%] WARN: %%F not found in either %~dp0 or %CLIENT_DIR%\ora >> "%LOG%"
|
||||
)
|
||||
)
|
||||
|
||||
:skip_ora_copy
|
||||
|
||||
REM Cleanup staging dir to reclaim ~1.5 GB - OUI copies everything to ORACLE_HOME
|
||||
echo [%STAMP%] Cleaning up staging dir >> "%LOG%"
|
||||
rmdir /s /q "%STAGING%" >nul 2>&1
|
||||
|
||||
REM OUI returns 0 for success, 3 for success-with-warnings. Treat both as OK.
|
||||
if %RC%==3 (
|
||||
echo [%STAMP%] OUI reported warnings but install succeeded - returning 0 >> "%LOG%"
|
||||
exit /b 0
|
||||
)
|
||||
|
||||
exit /b %RC%
|
||||
File diff suppressed because it is too large
Load Diff
13
playbook/preinstall/postppkg.json
Normal file
13
playbook/preinstall/postppkg.json
Normal file
@@ -0,0 +1,13 @@
|
||||
{
|
||||
"Version": "1.0",
|
||||
"_comment": "Site app list, installed after the post-PPKG reboot (once, as SYSTEM). Empty by default. Add one object per app to Applications and put its installer under pre-install/installers/<folder>/ on the PXE server (enrollment share). See docs/kb/How_To_Deploy_PXE_Server_New_Site.html, 'Adding shopfloor apps'.",
|
||||
"_example": {
|
||||
"Name": "Example App 1.2",
|
||||
"Installer": "exampleapp\\ExampleApp.msi",
|
||||
"Type": "MSI",
|
||||
"InstallArgs": "/qn /norestart",
|
||||
"DetectionMethod": "Registry",
|
||||
"DetectionPath": "HKLM:\\SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Uninstall\\{00000000-0000-0000-0000-000000000000}"
|
||||
},
|
||||
"Applications": []
|
||||
}
|
||||
@@ -1,245 +1,13 @@
|
||||
{
|
||||
"Version": "1.0",
|
||||
"Site": "West Jefferson",
|
||||
"Applications": [
|
||||
{
|
||||
"_comment": "PowerShell 7.5.4 - installed BEFORE PPKG via FlatUnattendW10-shopfloor.xml FirstLogonCommand Order 6 (race fix: Intune SetupCredentials Win32App install command starts with pwsh.exe; if PS7 not yet installed when that Win32App fires, it errors with FILE_NOT_FOUND 0x80070002 and IME's GRS retry never re-fires under V3Processor). This entry is a backstop - no-op via ProductCode detection if unattend Order 6 already installed it. PreEnrollment flag is informational; runner does not currently filter on it.",
|
||||
"Name": "PowerShell 7.5.4",
|
||||
"Installer": "powershell7\\PowerShell-7.5.4-win-x64.msi",
|
||||
"Type": "MSI",
|
||||
"InstallArgs": "/qn /norestart ADD_PATH=1 USE_MU=0 ENABLE_MU=0 DISABLE_TELEMETRY=1",
|
||||
"DetectionMethod": "Registry",
|
||||
"DetectionPath": "HKLM:\\SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Uninstall\\{E8159677-ACF8-4D64-9D36-5C36B8BBEA39}",
|
||||
"PreEnrollment": true,
|
||||
"PCTypes": ["*"]
|
||||
},
|
||||
{
|
||||
"_comment": "Oracle Client 11.2 Administrator - installed first because downstream apps (eDNC/NTLARS/UDC and CMM tooling) link against the Oracle home and fail cold if it's missing. Installer is a .cmd wrapper (Type=EXE is the preinstall runner's shim for non-MSI launchers, same pattern as OpenText Setup-OpenText.cmd). The wrapper expects Oracle_OracleDatabase_11r2_V03.zip (686 MB) staged next to it, unpacks to %TEMP%, runs Oracle Universal Installer silently with ge_client_install.rsp, then cleans up the staging dir. OUI exit 3 is treated as success (warnings-but-ok). Detection via the registered home key; downstream upgrades or version pins are handled by the runtime enforcer's Oracle Client 11.2 manifest entry in common/manifest.json. Scoped to the DNC-bearing PC types (collections, nocollections, partmarker, heattreat) plus CMM, whose metrology tooling links the Oracle home; non-DNC types (Genspect, Keyence, WaxAndTrace, Display, Timeclock, Lab) do not get it.",
|
||||
"Name": "Oracle Client 11.2",
|
||||
"Installer": "oracle\\Install-Oracle11r2.cmd",
|
||||
"Type": "EXE",
|
||||
"InstallArgs": "",
|
||||
"LogFile": "C:\\Logs\\OracleClient\\install.log",
|
||||
"DetectionMethod": "Registry",
|
||||
"DetectionPath": "HKLM:\\SOFTWARE\\WOW6432Node\\Oracle\\KEY_OraClient11g_home1",
|
||||
"DetectionName": "ORACLE_HOME_NAME",
|
||||
"DetectionValue": "OraClient11g_home1",
|
||||
"PCTypes": ["gea-shopfloor-collections", "gea-shopfloor-nocollections", "gea-shopfloor-partmarker", "gea-shopfloor-heattreat", "gea-shopfloor-cmm"]
|
||||
},
|
||||
{
|
||||
"_comment": "VC++ 2008 SP1 x86 - the bootstrapper (vcredist2008_x86.exe) ignores /norestart and triggers an immediate Windows reboot when files are in use (per Aaron Stebner's MSDN docs). Fix: install the extracted vc_red.msi directly with REBOOT=ReallySuppress, which IS hard-honored by Windows Installer. msiexec may return 3010 (would-have-rebooted-but-suppressed) but won't actually reboot. cab name 'vc_red.cab' is hardcoded in the MSI's Media table - do not rename.",
|
||||
"Name": "VC++ Redistributable 2008 x86",
|
||||
"Installer": "vcredist/2008/installer.msi",
|
||||
"Type": "MSI",
|
||||
"InstallArgs": "/qn /norestart REBOOT=ReallySuppress NOVSUI=1 USING_EXUIH_SILENT=1",
|
||||
"DetectionMethod": "Registry",
|
||||
"DetectionPath": "HKLM:\\SOFTWARE\\WOW6432Node\\Microsoft\\Windows\\CurrentVersion\\Uninstall\\{9BE518E6-ECC6-35A9-88E4-87755C07200F}",
|
||||
"PCTypes": ["gea-shopfloor-collections", "gea-shopfloor-nocollections", "gea-shopfloor-common", "gea-shopfloor-cmm", "gea-shopfloor-genspect", "gea-shopfloor-heattreat", "gea-shopfloor-keyence", "gea-shopfloor-partmarker", "gea-shopfloor-waxtrace"]
|
||||
},
|
||||
{
|
||||
"_comment": "VC++ 2010 x86 - same fix as 2008. Bootstrapper ignores /norestart; extracted MSI with REBOOT=ReallySuppress does not.",
|
||||
"Name": "VC++ Redistributable 2010 x86",
|
||||
"Installer": "vcredist/2010/installer.msi",
|
||||
"Type": "MSI",
|
||||
"InstallArgs": "/qn /norestart REBOOT=ReallySuppress NOVSUI=1 USING_EXUIH_SILENT=1",
|
||||
"DetectionMethod": "Registry",
|
||||
"DetectionPath": "HKLM:\\SOFTWARE\\WOW6432Node\\Microsoft\\Windows\\CurrentVersion\\Uninstall\\{F0C3E5D1-1ADE-321E-8167-68EF0DE699A5}",
|
||||
"PCTypes": ["gea-shopfloor-collections", "gea-shopfloor-nocollections", "gea-shopfloor-common", "gea-shopfloor-cmm", "gea-shopfloor-genspect", "gea-shopfloor-heattreat", "gea-shopfloor-keyence", "gea-shopfloor-partmarker", "gea-shopfloor-waxtrace"]
|
||||
},
|
||||
{
|
||||
"_comment": "VC++ 2012 x86 Minimum Runtime - extracted from vcredist2012_x86.exe Burn bundle. Same REBOOT=ReallySuppress fix.",
|
||||
"Name": "VC++ Redistributable 2012 x86 (Minimum)",
|
||||
"Installer": "vcredist/2012-min/installer.msi",
|
||||
"Type": "MSI",
|
||||
"InstallArgs": "/qn /norestart REBOOT=ReallySuppress NOVSUI=1 USING_EXUIH_SILENT=1",
|
||||
"DetectionMethod": "Registry",
|
||||
"DetectionPath": "HKLM:\\SOFTWARE\\WOW6432Node\\Microsoft\\Windows\\CurrentVersion\\Uninstall\\{BD95A8CD-1D9F-35AD-981A-3E7925026EBB}",
|
||||
"PCTypes": ["gea-shopfloor-collections", "gea-shopfloor-nocollections", "gea-shopfloor-common", "gea-shopfloor-cmm", "gea-shopfloor-genspect", "gea-shopfloor-heattreat", "gea-shopfloor-keyence", "gea-shopfloor-partmarker", "gea-shopfloor-waxtrace"]
|
||||
},
|
||||
{
|
||||
"Name": "VC++ Redistributable 2012 x86 (Additional)",
|
||||
"Installer": "vcredist/2012-add/installer.msi",
|
||||
"Type": "MSI",
|
||||
"InstallArgs": "/qn /norestart REBOOT=ReallySuppress NOVSUI=1 USING_EXUIH_SILENT=1",
|
||||
"DetectionMethod": "Registry",
|
||||
"DetectionPath": "HKLM:\\SOFTWARE\\WOW6432Node\\Microsoft\\Windows\\CurrentVersion\\Uninstall\\{B175520C-86A2-35A7-8619-86DC379688B9}",
|
||||
"PCTypes": ["gea-shopfloor-collections", "gea-shopfloor-nocollections", "gea-shopfloor-common", "gea-shopfloor-cmm", "gea-shopfloor-genspect", "gea-shopfloor-heattreat", "gea-shopfloor-keyence", "gea-shopfloor-partmarker", "gea-shopfloor-waxtrace"]
|
||||
},
|
||||
{
|
||||
"_comment": "VC++ 2013 x86 Minimum Runtime - extracted from vcredist2013_x86.exe Burn bundle.",
|
||||
"Name": "VC++ Redistributable 2013 x86 (Minimum)",
|
||||
"Installer": "vcredist/2013-min/installer.msi",
|
||||
"Type": "MSI",
|
||||
"InstallArgs": "/qn /norestart REBOOT=ReallySuppress NOVSUI=1 USING_EXUIH_SILENT=1",
|
||||
"DetectionMethod": "Registry",
|
||||
"DetectionPath": "HKLM:\\SOFTWARE\\WOW6432Node\\Microsoft\\Windows\\CurrentVersion\\Uninstall\\{13A4EE12-23EA-3371-91EE-EFB36DDFFF3E}",
|
||||
"PCTypes": ["gea-shopfloor-collections", "gea-shopfloor-nocollections", "gea-shopfloor-common", "gea-shopfloor-cmm", "gea-shopfloor-genspect", "gea-shopfloor-heattreat", "gea-shopfloor-keyence", "gea-shopfloor-partmarker", "gea-shopfloor-waxtrace"]
|
||||
},
|
||||
{
|
||||
"Name": "VC++ Redistributable 2013 x86 (Additional)",
|
||||
"Installer": "vcredist/2013-add/installer.msi",
|
||||
"Type": "MSI",
|
||||
"InstallArgs": "/qn /norestart REBOOT=ReallySuppress NOVSUI=1 USING_EXUIH_SILENT=1",
|
||||
"DetectionMethod": "Registry",
|
||||
"DetectionPath": "HKLM:\\SOFTWARE\\WOW6432Node\\Microsoft\\Windows\\CurrentVersion\\Uninstall\\{F8CFEB22-A2E7-3971-9EDA-4B11EDEFC185}",
|
||||
"PCTypes": ["gea-shopfloor-collections", "gea-shopfloor-nocollections", "gea-shopfloor-common", "gea-shopfloor-cmm", "gea-shopfloor-genspect", "gea-shopfloor-heattreat", "gea-shopfloor-keyence", "gea-shopfloor-partmarker", "gea-shopfloor-waxtrace"]
|
||||
},
|
||||
{
|
||||
"_comment": "VC++ 2013 x64 Minimum Runtime - required by Keyence VR-6000 Series Software. Extracted from the Keyence installer's Windows Installer cache. Same REBOOT=ReallySuppress pattern as the x86 variants.",
|
||||
"Name": "VC++ Redistributable 2013 x64 (Minimum)",
|
||||
"Installer": "vcredist/2013-x64-min/installer.msi",
|
||||
"Type": "MSI",
|
||||
"InstallArgs": "/qn /norestart REBOOT=ReallySuppress NOVSUI=1 USING_EXUIH_SILENT=1",
|
||||
"DetectionMethod": "Registry",
|
||||
"DetectionPath": "HKLM:\\SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Uninstall\\{A749D8E6-B613-3BE3-8F5F-045C84EBA29B}",
|
||||
"PCTypes": ["gea-shopfloor-collections", "gea-shopfloor-nocollections", "gea-shopfloor-common", "gea-shopfloor-cmm", "gea-shopfloor-genspect", "gea-shopfloor-heattreat", "gea-shopfloor-keyence", "gea-shopfloor-partmarker", "gea-shopfloor-waxtrace"]
|
||||
},
|
||||
{
|
||||
"_comment": "VC++ 2013 x64 Additional Runtime - required by Keyence VR-6000 Series Software. Pairs with the Minimum Runtime above.",
|
||||
"Name": "VC++ Redistributable 2013 x64 (Additional)",
|
||||
"Installer": "vcredist/2013-x64-add/installer.msi",
|
||||
"Type": "MSI",
|
||||
"InstallArgs": "/qn /norestart REBOOT=ReallySuppress NOVSUI=1 USING_EXUIH_SILENT=1",
|
||||
"DetectionMethod": "Registry",
|
||||
"DetectionPath": "HKLM:\\SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Uninstall\\{929FBD26-9020-399B-9A7A-751D61F0B942}",
|
||||
"PCTypes": ["gea-shopfloor-collections", "gea-shopfloor-nocollections", "gea-shopfloor-common", "gea-shopfloor-cmm", "gea-shopfloor-genspect", "gea-shopfloor-heattreat", "gea-shopfloor-keyence", "gea-shopfloor-partmarker", "gea-shopfloor-waxtrace"]
|
||||
},
|
||||
{
|
||||
"_comment": "VC++ 2010 x64 - required by PC-DMIS 2016/2019 R2 on CMM PCs. PCDLRN.exe links against msvcr100.dll and the VS 2010 MFC DLLs which are only provided by this redistributable. Extracted from the PC-DMIS 2016 bundle's attached container (a1 payload). Silent install: /q /norestart. Detection: Uninstall key under the native x64 hive with fixed product GUID.",
|
||||
"Name": "VC++ Redistributable 2010 x64",
|
||||
"Installer": "vcredist/2010-x64/vcredist_x64.exe",
|
||||
"Type": "EXE",
|
||||
"InstallArgs": "/q /norestart",
|
||||
"DetectionMethod": "Registry",
|
||||
"DetectionPath": "HKLM:\\SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Uninstall\\{1D8E6291-B0D5-35EC-8441-6616F567A0F7}",
|
||||
"DetectionName": "DisplayVersion",
|
||||
"DetectionValue": "10.0.40219",
|
||||
"PCTypes": ["gea-shopfloor-collections", "gea-shopfloor-nocollections", "gea-shopfloor-common", "gea-shopfloor-cmm", "gea-shopfloor-genspect", "gea-shopfloor-heattreat", "gea-shopfloor-keyence", "gea-shopfloor-partmarker", "gea-shopfloor-waxtrace"]
|
||||
},
|
||||
{
|
||||
"_comment": "VC++ 2012 x64 - required by PC-DMIS 2016/2019 R2. Same rationale as 2010 x64; PC-DMIS links against msvcr110.dll / MFC110. Extracted from the PC-DMIS 2016 bundle's attached container (a2 payload). Detection on the Minimum Runtime GUID (the main redist wrapper installs both Minimum and Additional sub-packages).",
|
||||
"Name": "VC++ Redistributable 2012 x64",
|
||||
"Installer": "vcredist/2012-x64/vcredist_x64.exe",
|
||||
"Type": "EXE",
|
||||
"InstallArgs": "/q /norestart",
|
||||
"DetectionMethod": "Registry",
|
||||
"DetectionPath": "HKLM:\\SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Uninstall\\{5AF4E09F-5C9B-3AAF-B731-544D3DC821DD}",
|
||||
"DetectionName": "DisplayVersion",
|
||||
"DetectionValue": "11.0.51106",
|
||||
"PCTypes": ["gea-shopfloor-collections", "gea-shopfloor-nocollections", "gea-shopfloor-common", "gea-shopfloor-cmm", "gea-shopfloor-genspect", "gea-shopfloor-heattreat", "gea-shopfloor-keyence", "gea-shopfloor-partmarker", "gea-shopfloor-waxtrace"]
|
||||
},
|
||||
{
|
||||
"_comment": "VC++ 2015-2022 x86 - extracted from vcredist2015_2017_2019_2022_x86.exe Burn bundle. The bundle contains 2022 14.44.35211 plus 8 chained KB updates for older 2015/2017/2019 releases. We install only the 2022 Min+Add MSIs - the CRT v140 ABI is shared across 2015/2017/2019/2022, so the latest pair covers all four versions on Windows 10/11.",
|
||||
"Name": "VC++ Redistributable 2022 x86 (Minimum)",
|
||||
"Installer": "vcredist/2022-min/installer.msi",
|
||||
"Type": "MSI",
|
||||
"InstallArgs": "/qn /norestart REBOOT=ReallySuppress NOVSUI=1 USING_EXUIH_SILENT=1",
|
||||
"DetectionMethod": "Registry",
|
||||
"DetectionPath": "HKLM:\\SOFTWARE\\WOW6432Node\\Microsoft\\Windows\\CurrentVersion\\Uninstall\\{922480B5-CAEB-4B1B-AAA4-9716EFDCE26B}",
|
||||
"PCTypes": ["gea-shopfloor-collections", "gea-shopfloor-nocollections", "gea-shopfloor-common", "gea-shopfloor-cmm", "gea-shopfloor-genspect", "gea-shopfloor-heattreat", "gea-shopfloor-keyence", "gea-shopfloor-partmarker", "gea-shopfloor-waxtrace"]
|
||||
},
|
||||
{
|
||||
"Name": "VC++ Redistributable 2022 x86 (Additional)",
|
||||
"Installer": "vcredist/2022-add/installer.msi",
|
||||
"Type": "MSI",
|
||||
"InstallArgs": "/qn /norestart REBOOT=ReallySuppress NOVSUI=1 USING_EXUIH_SILENT=1",
|
||||
"DetectionMethod": "Registry",
|
||||
"DetectionPath": "HKLM:\\SOFTWARE\\WOW6432Node\\Microsoft\\Windows\\CurrentVersion\\Uninstall\\{C18FB403-1E88-43C8-AD8A-CED50F23DE8B}",
|
||||
"PCTypes": ["gea-shopfloor-collections", "gea-shopfloor-nocollections", "gea-shopfloor-common", "gea-shopfloor-cmm", "gea-shopfloor-genspect", "gea-shopfloor-heattreat", "gea-shopfloor-keyence", "gea-shopfloor-partmarker", "gea-shopfloor-waxtrace"]
|
||||
},
|
||||
{
|
||||
"_comment": "VC++ 2015-2022 x64 - required by PC-DMIS 2026 (PCDLRN.exe links vcruntime140_1.dll, added in VC++ 2019 / v14.20). The x64 redist line above previously stopped at 2013, so 64-bit PC-DMIS 2026 was missing its runtime and PCDLRN.exe failed to start with 'vcruntime140_1.dll was not found'. The patched PC-DMIS MSI bypasses Hexagon's Burn bundle, which is what would otherwise have pulled this in. Full vc_redist.x64.exe (14.44.35211, 2015-2022 shared CRT). Modern bootstrapper honors /norestart. Detect on the DLL itself so it is version-independent.",
|
||||
"Name": "VC++ Redistributable 2015-2022 x64",
|
||||
"Installer": "vcredist/2022-x64/vc_redist.x64.exe",
|
||||
"Type": "EXE",
|
||||
"InstallArgs": "/install /quiet /norestart",
|
||||
"DetectionMethod": "File",
|
||||
"DetectionPath": "C:\\Windows\\System32\\vcruntime140_1.dll",
|
||||
"PCTypes": ["*"]
|
||||
},
|
||||
{
|
||||
"_comment": "Adobe Acrobat Reader DC - same version as GEA-Engineering image. Two-step install via Install-AcroReader.cmd wrapper: base MSI with enterprise transform (AcroRead.mst) then DC update patch (AcroRdrDCUpd2500120531.msp). Source files on PXE server at /srv/samba/winpeapps/gea-engineer/Deploy/Applications/extra/adobe/ - copy to /srv/samba/enrollment/preinstall/installers/adobe/.",
|
||||
"Name": "Adobe Acrobat Reader DC",
|
||||
"Installer": "adobe\\Install-AcroReader.cmd",
|
||||
"Type": "EXE",
|
||||
"InstallArgs": "",
|
||||
"DetectionMethod": "File",
|
||||
"DetectionPath": "C:\\Program Files (x86)\\Adobe\\Acrobat Reader DC\\Reader\\AcroRd32.exe",
|
||||
"PCTypes": ["gea-shopfloor-collections", "gea-shopfloor-nocollections", "gea-shopfloor-common", "gea-shopfloor-cmm", "gea-shopfloor-genspect", "gea-shopfloor-heattreat", "gea-shopfloor-keyence", "gea-shopfloor-partmarker", "gea-shopfloor-waxtrace"]
|
||||
},
|
||||
{
|
||||
"_comment": "OpenText HostExplorer 15 SP1 ShopFloor - replaced the WJDT-built OpenText.exe Inno wrapper with our own Setup-OpenText.ps1 that does the same install steps (msiexec base + ShopFloor.mst transform + SP1 .msp patch) PLUS fans the per-user profile/keymap/menu/macro content out to Default User and every existing user profile. The Inno wrapper deployed per-user content to {userappdata} which resolves to whichever user is running the installer (SYSTEM under DSC, single user under PreInstall) so Azure-AD users never saw the profiles. Setup-OpenText.cmd is a tiny launcher that hands off to Setup-OpenText.ps1 because the runner only handles MSI/EXE types. All bundled files live in vcredist-style subtree at dependencies/opentext/ and get xcopied through WinPE staging. NO DetectionMethod here on purpose - Setup-OpenText.ps1 owns its own version check by reading version.txt next to itself and comparing to HKLM:\\SOFTWARE\\GE\\OpenText\\Installed; the runner always invokes the wrapper (cost: ~1s of PowerShell launch when up-to-date) so the version constant lives in exactly one place: dependencies/opentext/version.txt.",
|
||||
"Name": "OpenText HostExplorer ShopFloor",
|
||||
"Installer": "opentext\\Setup-OpenText.cmd",
|
||||
"Type": "EXE",
|
||||
"InstallArgs": "",
|
||||
"LogFile": "C:\\Logs\\PreInstall\\Setup-OpenText.log",
|
||||
"PCTypes": ["gea-shopfloor-collections", "gea-shopfloor-nocollections", "gea-shopfloor-common", "gea-shopfloor-cmm", "gea-shopfloor-genspect", "gea-shopfloor-heattreat", "gea-shopfloor-keyence", "gea-shopfloor-partmarker", "gea-shopfloor-waxtrace"]
|
||||
},
|
||||
{
|
||||
"_comment": "UDC_Setup.exe spawns a hidden WPF window (UDC.exe) after install and never exits, so the runner needs KillAfterDetection: true to terminate UDC_Setup.exe + UDC.exe once the registry detection passes. This is an OPT-IN flag - normal installers should NOT set it because killing msiexec mid-install leaves msiserver holding the install mutex and the next msiexec call returns 1618 (Oracle hit this exact bug).",
|
||||
"Name": "UDC",
|
||||
"Installer": "UDC_Setup.exe",
|
||||
"Type": "EXE",
|
||||
"InstallArgs": "\"West Jefferson\" -9999",
|
||||
"KillAfterDetection": true,
|
||||
"DetectionMethod": "Registry",
|
||||
"DetectionPath": "HKLM:\\SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Uninstall\\UDC",
|
||||
"PCTypes": ["gea-shopfloor-collections"],
|
||||
"PCTypesStrict": true,
|
||||
"_pcTypesNote": "UDC = the C in 'collections'. nocollections does NOT collect data so MUST NOT install UDC. PCTypesStrict bypasses the alias-expansion matcher so a nocollections PC's myNames (which transitively contains gea-shopfloor-collections via the Standard group) still won't match this entry."
|
||||
},
|
||||
{
|
||||
"_comment": "Display kiosk app (Lobby Display or Dashboard). Install-KioskApp.cmd wrapper reads C:\\Enrollment\\display-type.txt to determine which installer to run. Both GEAerospaceLobbyDisplaySetup.exe and GEAerospaceDashboardSetup.exe must be staged in the display\\ subtree alongside the wrapper. Inno Setup /VERYSILENT is idempotent so no detection needed.",
|
||||
"Name": "Display Kiosk App",
|
||||
"Installer": "display\\Install-KioskApp.cmd",
|
||||
"Type": "EXE",
|
||||
"InstallArgs": "",
|
||||
"LogFile": "C:\\Logs\\PreInstall\\Dashboard-install.log",
|
||||
"PCTypes": ["Display"]
|
||||
},
|
||||
{
|
||||
"_comment": "WJF Defect Tracker - replaces old ClickOnce deployment. MSI creates desktop + Start Menu shortcuts. Enforcer on SFLD share handles version updates post-imaging. TARGETDIR explicit because VS deployment MSI defaults to random path without it.",
|
||||
"Name": "WJF Defect Tracker",
|
||||
"Installer": "WJF_Defect_Tracker.msi",
|
||||
"Type": "MSI",
|
||||
"InstallArgs": "/qn /norestart ALLUSERS=1 REBOOT=ReallySuppress TARGETDIR=\"C:\\Program Files (x86)\\WJF_Defect_Tracker\"",
|
||||
"DetectionMethod": "File",
|
||||
"DetectionPath": "C:\\Program Files (x86)\\WJF_Defect_Tracker\\Defect_Tracker.exe",
|
||||
"PCTypes": ["gea-shopfloor-collections", "gea-shopfloor-nocollections", "gea-shopfloor-common", "gea-shopfloor-cmm", "gea-shopfloor-genspect", "gea-shopfloor-heattreat", "gea-shopfloor-keyence", "gea-shopfloor-partmarker", "gea-shopfloor-waxtrace"]
|
||||
},
|
||||
{
|
||||
"_comment": "Shopfloor Standard serial-port drivers: StarTech PCIe serial adapter (MosChip-based) + Prolific PL2303 USB-to-serial. Install-Drivers.cmd runs pnputil /add-driver with /subdirs /install so every bundled INF under drivers/ lands in the Windows driver store and auto-binds to matching hardware present now or plugged in later. Installed on every PC type (PCTypes ['*']) because serial hardware turns up across bays; a serial driver on a PC without the hardware is harmless - it just sits in the driver store until matching hardware is plugged in.",
|
||||
"Name": "Shopfloor Serial Drivers",
|
||||
"Installer": "drivers\\Install-Drivers.cmd",
|
||||
"Type": "EXE",
|
||||
"InstallArgs": "",
|
||||
"LogFile": "C:\\Logs\\PreInstall\\Install-Drivers.log",
|
||||
"DetectionMethod": "File",
|
||||
"DetectionPath": "C:\\ProgramData\\PXEDrivers\\drivers-installed.marker",
|
||||
"PCTypes": ["gea-shopfloor-collections", "gea-shopfloor-nocollections", "gea-shopfloor-common", "gea-shopfloor-cmm", "gea-shopfloor-genspect", "gea-shopfloor-heattreat", "gea-shopfloor-keyence", "gea-shopfloor-partmarker", "gea-shopfloor-waxtrace"]
|
||||
},
|
||||
{
|
||||
"_comment": "HP universal print driver, staged at imaging so a bay comes off the line able to build an HP queue without waiting on the SFLD share. Set-ShopdbPrinters.ps1 creates queues against drivers that are already present and SKIPS any that are not, so without this a freshly imaged bay silently gets no printers until a later enforcement cycle tops it up. NO WAVE GATE HERE, deliberately: waves exist because ~300 bays share one runtime share, whereas imaging runs a handful of bays at a time on the isolated PXE LAN that already moves multi-GB WIMs. Detection is the SPOOLER's driver key, not pnputil - pnputil only proves the package reached the driver store, and Get-PrinterDriver (what Set-ShopdbPrinters consults) reads the spooler, so a pnputil check goes green on a half-install. Payload is NOT in git: stage printer-drivers/ onto the PXE share like the other installer payloads.",
|
||||
"Name": "ShopDB Printer Driver - HP Universal PS",
|
||||
"Installer": "printer-drivers\\Install-ShopdbPrinterDrivers.ps1",
|
||||
"Type": "PS1",
|
||||
"InstallArgs": "-Only 'HP Universal Printing PS'",
|
||||
"LogFile": "C:\\Logs\\PreInstall\\printer-drivers.log",
|
||||
"DetectionMethod": "Registry",
|
||||
"DetectionPath": "HKLM:\\SYSTEM\\CurrentControlSet\\Control\\Print\\Environments\\Windows x64\\Drivers\\Version-3\\HP Universal Printing PS",
|
||||
"PCTypes": ["gea-shopfloor-collections", "gea-shopfloor-nocollections", "gea-shopfloor-common", "gea-shopfloor-cmm", "gea-shopfloor-genspect", "gea-shopfloor-heattreat", "gea-shopfloor-keyence", "gea-shopfloor-partmarker", "gea-shopfloor-waxtrace"]
|
||||
},
|
||||
{
|
||||
"_comment": "Xerox universal print driver. Same reasoning as the HP entry above. These two universals are 100 MB combined and resolve the overwhelming majority of the fleet's printers; the four device-specific drivers (DesignJet, Zebra ZT411, Epson C3500, FARGO card printer) are another 126 MB and are deliberately NOT staged at imaging - they belong only on the bays that have that hardware, and those bays pick them up from the runtime manifest on their next enforcement cycle.",
|
||||
"Name": "ShopDB Printer Driver - Xerox Global PCL6",
|
||||
"Installer": "printer-drivers\\Install-ShopdbPrinterDrivers.ps1",
|
||||
"Type": "PS1",
|
||||
"InstallArgs": "-Only 'Xerox Global Print Driver PCL6'",
|
||||
"LogFile": "C:\\Logs\\PreInstall\\printer-drivers.log",
|
||||
"DetectionMethod": "Registry",
|
||||
"DetectionPath": "HKLM:\\SYSTEM\\CurrentControlSet\\Control\\Print\\Environments\\Windows x64\\Drivers\\Version-3\\Xerox Global Print Driver PCL6",
|
||||
"PCTypes": ["gea-shopfloor-collections", "gea-shopfloor-nocollections", "gea-shopfloor-common", "gea-shopfloor-cmm", "gea-shopfloor-genspect", "gea-shopfloor-heattreat", "gea-shopfloor-keyence", "gea-shopfloor-partmarker", "gea-shopfloor-waxtrace"]
|
||||
}
|
||||
]
|
||||
"_comment": "Site app list, installed during setup (same logon as the PPKG, before the post-PPKG reboot). Empty by default. Add one object per app to Applications and put its installer under pre-install/installers/<folder>/ on the PXE server (enrollment share). See docs/kb/How_To_Deploy_PXE_Server_New_Site.html, 'Adding shopfloor apps'.",
|
||||
"_example": {
|
||||
"Name": "Example App 1.2",
|
||||
"Installer": "exampleapp\\ExampleApp.msi",
|
||||
"Type": "MSI",
|
||||
"InstallArgs": "/qn /norestart",
|
||||
"DetectionMethod": "Registry",
|
||||
"DetectionPath": "HKLM:\\SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Uninstall\\{00000000-0000-0000-0000-000000000000}"
|
||||
},
|
||||
"Applications": []
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user