Renumber PXE LAN from 10.9.100.0/24 to 172.16.9.0/24
Single-site bay-stuck issue at WJ: GE Intune Report IP script filters
Get-NetIPAddress on StartsWith("10.") and posts everything matching
to the GE Tines webhook. Bays at WJ get the PXE LAN 10.9.100.x IP
captured and reported -> GE backend tags bays as on a non-corp 10.x
subnet -> dynamic group eligibility for SFLD policy never matches.
Other GE sites work because their PXE LANs aren't on 10.x at all.
Renumber PXE LAN to RFC1918 172.16.9.0/24 so the GE filter naturally
skips wired PXE addresses without any disable-NIC dance.
Server-side already in flight (netplan dual-bound, dnsmasq scope +
boot URL repointed, blancco preferences + grub.cfg + iPXE GetPxeScript
all sed'd to 172.16.9.1). This commit is the playbook / scripts /
docs side: 109 hits across 35 files sed'd in one shot.
After this lands + boot.wim is rebuilt + bays renumber off DHCP,
the 10.9.100.1 binding will be dropped from netplan as the final
cleanup step.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
BIN
Binary/Binary.NewBinary1
Normal file
|
After Width: | Height: | Size: 4.9 KiB |
BIN
Binary/Binary.NewBinary10
Normal file
|
After Width: | Height: | Size: 4.4 KiB |
BIN
Binary/Binary.NewBinary11
Normal file
|
After Width: | Height: | Size: 4.4 KiB |
BIN
Binary/Binary.NewBinary12
Normal file
|
After Width: | Height: | Size: 3.2 KiB |
BIN
Binary/Binary.NewBinary13
Normal file
|
After Width: | Height: | Size: 766 B |
BIN
Binary/Binary.NewBinary14
Normal file
|
After Width: | Height: | Size: 766 B |
BIN
Binary/Binary.NewBinary15
Normal file
|
After Width: | Height: | Size: 766 B |
BIN
Binary/Binary.NewBinary16
Normal file
|
After Width: | Height: | Size: 766 B |
BIN
Binary/Binary.NewBinary17
Normal file
|
After Width: | Height: | Size: 766 B |
BIN
Binary/Binary.NewBinary18
Normal file
|
After Width: | Height: | Size: 766 B |
40
Binary/Binary.NewBinary19
Normal file
@@ -0,0 +1,40 @@
|
||||
Option Explicit
|
||||
|
||||
|
||||
' アップグレードコードから、製品コードを取得
|
||||
'
|
||||
' 第1引数 : アップグレードコード(「{」、「}」、ハイフンあり)
|
||||
Function GetProductCodeFromUpgradeCode(UpgCode)
|
||||
Dim listProductCode
|
||||
Dim szProductCode
|
||||
|
||||
' アップグレードコードから、関連する製品名のリストを取得
|
||||
Set listProductCode = Session.Installer.RelatedProducts(UpgCode)
|
||||
|
||||
' 基本、1件のみヒットするものとする
|
||||
For Each szProductCode In listProductCode
|
||||
GetProductCodeFromUpgradeCode = szProductCode
|
||||
' 1件目を取得した段階で抜ける
|
||||
Exit For
|
||||
Next
|
||||
End Function
|
||||
|
||||
|
||||
' アップグレードコードから既にインストール済みのアプリケーションのインストールパスを取得する
|
||||
Sub GetInstallPath()
|
||||
Dim WshShell
|
||||
Dim szProductCode
|
||||
Dim szInstallStringKey
|
||||
|
||||
Set WshShell = CreateObject("WScript.Shell")
|
||||
|
||||
' アップグレードコードから、製品コードを取得
|
||||
szProductCode = GetProductCodeFromUpgradeCode(Session.Property("UpgradeCode"))
|
||||
|
||||
' レジストリのInstallLocationを取得
|
||||
szInstallStringKey = WshShell.RegRead("HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\" + szProductCode + "\InstallLocation")
|
||||
|
||||
Session.Property("INSTALLDIR_FOR_MAJORUPGRADE") = szInstallStringKey
|
||||
|
||||
Set WshShell = nothing
|
||||
End Sub
|
||||
BIN
Binary/Binary.NewBinary2
Normal file
|
After Width: | Height: | Size: 318 B |
22
Binary/Binary.NewBinary20
Normal file
@@ -0,0 +1,22 @@
|
||||
Option Explicit
|
||||
|
||||
Sub CheckOSVersion
|
||||
Const HKEY_LOCAL_MACHINE = &H80000002
|
||||
Dim WshShell,objRegistry
|
||||
Dim strComputer, strKeyPath, strValue, strValueName
|
||||
|
||||
Set WshShell = CreateObject("WScript.Shell")
|
||||
|
||||
strComputer = "."
|
||||
Set objRegistry = GetObject("winmgmts:{impersonationLevel=impersonate}!\\" & strComputer & "\root\default:StdRegProv")
|
||||
strKeyPath = "SOFTWARE\Microsoft\Windows NT\CurrentVersion"
|
||||
strValueName = "CurrentMajorVersionNumber"
|
||||
objRegistry.GetDWORDValue HKEY_LOCAL_MACHINE,strKeyPath,strValueName,strValue
|
||||
|
||||
If (not IsNull(strValue)) and (strValue=10) Then
|
||||
Session.Property("IsWindows10")="1"
|
||||
else
|
||||
Session.Property("IsWindows10")="0"
|
||||
End If
|
||||
|
||||
End Sub
|
||||
13
Binary/Binary.NewBinary21
Normal file
@@ -0,0 +1,13 @@
|
||||
Option Explicit
|
||||
|
||||
'レジストリに登録する日付をプロパティに設定
|
||||
Sub SetInstallDate
|
||||
Session.Property("INSTALLDATE") = YYYYMMDD
|
||||
End Sub
|
||||
|
||||
'YYYYMMDD形式の日付を返す
|
||||
Function YYYYMMDD
|
||||
|
||||
YYYYMMDD = Year(Date) & Right("0" & Month(Date), 2) & Right("0" & Day(Date), 2)
|
||||
|
||||
End Function
|
||||
BIN
Binary/Binary.NewBinary3
Normal file
|
After Width: | Height: | Size: 318 B |
BIN
Binary/Binary.NewBinary4
Normal file
|
After Width: | Height: | Size: 3.2 KiB |
BIN
Binary/Binary.NewBinary5
Normal file
|
After Width: | Height: | Size: 25 KiB |
BIN
Binary/Binary.NewBinary6
Normal file
|
After Width: | Height: | Size: 4.4 KiB |
BIN
Binary/Binary.NewBinary7
Normal file
|
After Width: | Height: | Size: 766 B |
BIN
Binary/Binary.NewBinary8
Normal file
|
After Width: | Height: | Size: 766 B |
BIN
Binary/Binary.NewBinary9
Normal file
|
After Width: | Height: | Size: 9.9 KiB |
BIN
Binary/Binary.SetAllUsers.dll
Normal file
BIN
Icon/Icon.ARPPRODUCTICON.exe
Normal file
BIN
Icon/Icon.NewShortcut1_AB8E7834205C40DE9AD7D94845255E55.exe
Normal file
BIN
Icon/Icon.NewShortcut2_1E955C7F522448028AA8419A487CA996.exe
Normal file
BIN
Icon/Icon._052C53DD_2BAF_4769_A1A0_1519CA2B23FB
Normal file
BIN
Icon/Icon._173060F8_E06D_4B06_B289_4656D92A595E
Normal file
BIN
Icon/Icon._3336CEAD_1861_4B26_A1C1_2D2F75C36A27
Normal file
BIN
Icon/Icon._59497049_1008_4427_84DF_744B04B0F075
Normal file
BIN
Icon/Icon._5EF3CFE6_6B6A_49D5_A54E_95222360D405
Normal file
BIN
Icon/Icon._823D3F96_4702_483C_BE0E_6CF23CAA78AD
Normal file
BIN
Icon/Icon._90919B36_D3D7_437D_B050_7D5620C88056
Normal file
BIN
Icon/Icon._E7806B4E_27A4_4270_8F13_3E9E01192773
Normal file
16
README.md
@@ -23,7 +23,7 @@ Client PXE boot (UEFI Secure Boot)
|
||||
|
||||
| Service | Port | Purpose |
|
||||
|-------------|-----------|------------------------------------------|
|
||||
| dnsmasq | 67/udp | DHCP (10.9.100.10-100, 12h lease) |
|
||||
| dnsmasq | 67/udp | DHCP (172.16.9.10-100, 12h lease) |
|
||||
| dnsmasq | 69/udp | TFTP (serves ipxe.efi) |
|
||||
| Apache | 80/tcp | HTTP (wimboot, WinPE boot files, proxy) |
|
||||
| Apache | 4433/tcp | iPXE boot script (GetPxeScript.aspx) |
|
||||
@@ -32,8 +32,8 @@ Client PXE boot (UEFI Secure Boot)
|
||||
|
||||
### Network
|
||||
|
||||
- **PXE server IP:** `10.9.100.1/24`
|
||||
- **DHCP range:** `10.9.100.10` - `10.9.100.100`
|
||||
- **PXE server IP:** `172.16.9.1/24`
|
||||
- **DHCP range:** `172.16.9.10` - `172.16.9.100`
|
||||
- **Firewall:** UFW deny-by-default, only service ports open (22, 67, 69, 80, 445, 4433, 9009)
|
||||
|
||||
## Quick Start
|
||||
@@ -85,12 +85,12 @@ Creates a bootable USB with two partitions:
|
||||
4. After reboot, the first-boot script:
|
||||
- Installs all offline .deb packages
|
||||
- Runs the Ansible playbook (configures dnsmasq, Apache, Samba, UFW, webapp)
|
||||
- Configures static IP `10.9.100.1/24`
|
||||
- Configures static IP `172.16.9.1/24`
|
||||
5. Move the server's wired NIC to the isolated PXE switch
|
||||
|
||||
### Step 5: Access the Web Interface
|
||||
|
||||
Open `http://10.9.100.1:9009` from any machine on the isolated network.
|
||||
Open `http://172.16.9.1:9009` from any machine on the isolated network.
|
||||
|
||||
## Web Management Interface
|
||||
|
||||
@@ -213,11 +213,11 @@ This creates `pxe-server-proxmox.iso` containing the Ubuntu installer, autoinsta
|
||||
3. Attach the ISO as CD-ROM and start the VM
|
||||
4. Ubuntu auto-installs with zero interaction (~10-15 minutes)
|
||||
5. After reboot, first-boot configures all PXE services automatically
|
||||
6. Access the web interface at `http://10.9.100.1:9009`
|
||||
6. Access the web interface at `http://172.16.9.1:9009`
|
||||
|
||||
### Import WinPE Images
|
||||
|
||||
After the server is running, import deployment images via the web interface at `http://10.9.100.1:9009/import` or by mounting a USB drive with WinPE content.
|
||||
After the server is running, import deployment images via the web interface at `http://172.16.9.1:9009/import` or by mounting a USB drive with WinPE content.
|
||||
|
||||
## Samba Shares
|
||||
|
||||
@@ -235,7 +235,7 @@ All shares use guest access (no authentication) for ease of use on the isolated
|
||||
|
||||
Blancco Drive Eraser 7.15.1 boots via a native Ubuntu kernel with a custom initramfs (`blancco-init.sh`) that downloads and mounts the Blancco rootfs over HTTP. XML erasure reports are automatically saved to the PXE server's Samba share (`blancco-reports`). The server supports BMC cloud licensing for Blancco activation over WiFi.
|
||||
|
||||
Reports are viewable and downloadable from the web interface at `http://10.9.100.1:9009/reports`.
|
||||
Reports are viewable and downloadable from the web interface at `http://172.16.9.1:9009/reports`.
|
||||
|
||||
## Notes
|
||||
|
||||
|
||||
12
SETUP.md
@@ -18,7 +18,7 @@ Client PXE boot
|
||||
|
||||
| Service | Port | Purpose |
|
||||
|-------------|-----------|------------------------------------------|
|
||||
| dnsmasq | 67/udp | DHCP (10.9.100.10-100) |
|
||||
| dnsmasq | 67/udp | DHCP (172.16.9.10-100) |
|
||||
| dnsmasq | 69/udp | TFTP (serves ipxe.efi) |
|
||||
| Apache | 80/tcp | HTTP (wimboot, WinPE boot files, proxy) |
|
||||
| Apache | 4433/tcp | iPXE boot script (GetPxeScript.aspx) |
|
||||
@@ -95,7 +95,7 @@ Move the server's wired NIC to the isolated switch for PXE clients.
|
||||
|
||||
### Step 6: Import WinPE Content (if not bundled in Step 3)
|
||||
|
||||
**Option A:** Use the web interface at `http://10.9.100.1:9009` to import from USB.
|
||||
**Option A:** Use the web interface at `http://172.16.9.1:9009` to import from USB.
|
||||
|
||||
**Option B:** Manual copy:
|
||||
```bash
|
||||
@@ -107,7 +107,7 @@ sudo umount /mnt/usb2
|
||||
|
||||
## Web Management Interface
|
||||
|
||||
Access at `http://10.9.100.1:9009` from any machine on the isolated network.
|
||||
Access at `http://172.16.9.1:9009` from any machine on the isolated network.
|
||||
|
||||
| Page | URL Path | Purpose |
|
||||
|-------------------|-------------|-----------------------------------------------|
|
||||
@@ -146,7 +146,7 @@ sudo ./test-vm.sh ~/Downloads/ubuntu-24.04.3-live-server-amd64.iso
|
||||
# Watch progress (Ctrl+] to detach)
|
||||
sudo virsh console pxe-test
|
||||
|
||||
# After install: ssh pxe@10.9.100.1 / http://10.9.100.1:9009
|
||||
# After install: ssh pxe@172.16.9.1 / http://172.16.9.1:9009
|
||||
|
||||
# Clean up
|
||||
sudo ./test-vm.sh --destroy
|
||||
@@ -215,8 +215,8 @@ pxe-server/
|
||||
|
||||
## Network Configuration
|
||||
|
||||
- PXE server static IP: `10.9.100.1/24`
|
||||
- DHCP range: `10.9.100.10` - `10.9.100.100`
|
||||
- PXE server static IP: `172.16.9.1/24`
|
||||
- DHCP range: `172.16.9.10` - `172.16.9.100`
|
||||
- Lease time: 12 hours
|
||||
- DNS: `8.8.8.8` (passed to clients, not used by server)
|
||||
- Firewall: UFW deny-by-default, allow 67/udp 69/udp 80/tcp 445/tcp 4433/tcp 9009/tcp
|
||||
|
||||
@@ -17,7 +17,7 @@ autoinstall:
|
||||
match:
|
||||
name: "en*"
|
||||
addresses:
|
||||
- 10.9.100.1/24
|
||||
- 172.16.9.1/24
|
||||
dhcp4: false
|
||||
dhcp6: false
|
||||
optional: true
|
||||
|
||||
@@ -16,8 +16,8 @@ systems.
|
||||
|
||||
## Network layout
|
||||
|
||||
- PXE server static IP: `10.9.100.1/24` on an isolated subnet.
|
||||
- DHCP range served by dnsmasq: `10.9.100.10 - 10.9.100.100`, 12h leases.
|
||||
- PXE server static IP: `172.16.9.1/24` on an isolated subnet.
|
||||
- DHCP range served by dnsmasq: `172.16.9.10 - 172.16.9.100`, 12h leases.
|
||||
- Default gateway and DNS handed out via DHCP point at the PXE server itself.
|
||||
- The subnet has no route to the corporate LAN. Client traffic (Blancco BMC
|
||||
cloud, Intune enrollment) goes out via WiFi after Windows boots; PXE-time
|
||||
@@ -166,7 +166,7 @@ USB installer (2 partitions: ISO + CIDATA)
|
||||
Ubuntu auto-install + first-boot Ansible playbook
|
||||
|
|
||||
v
|
||||
Configured PXE server (10.9.100.1) ----+
|
||||
Configured PXE server (172.16.9.1) ----+
|
||||
|
|
||||
Windows PCs running Upload-Image.ps1 --+--> Image content (SMB, webapp import)
|
||||
|
|
||||
|
||||
@@ -22,9 +22,9 @@ contribute a `config/sites/<sitename>.yaml` template back to the repo.
|
||||
|
||||
| Value | Default | Where it lives |
|
||||
|-------------------|----------------------|--------------------------------------------------------------------------------|
|
||||
| PXE server IP | 10.9.100.1 | `playbook/pxe_server_setup.yml` (dnsmasq config, iPXE script, samba conf, webapp env), `playbook/startnet.cmd` (mount paths), `boot-tools/blancco/grub-blancco.cfg` (TFTP/HTTP URLs) |
|
||||
| PXE subnet | 10.9.100.0/24 | Same as above, plus `playbook/pxe_server_setup.yml` (UFW rules) |
|
||||
| DHCP range | 10.9.100.10-100 | `playbook/pxe_server_setup.yml` (dnsmasq config) |
|
||||
| PXE server IP | 172.16.9.1 | `playbook/pxe_server_setup.yml` (dnsmasq config, iPXE script, samba conf, webapp env), `playbook/startnet.cmd` (mount paths), `boot-tools/blancco/grub-blancco.cfg` (TFTP/HTTP URLs) |
|
||||
| PXE subnet | 172.16.9.0/24 | Same as above, plus `playbook/pxe_server_setup.yml` (UFW rules) |
|
||||
| DHCP range | 172.16.9.10-100 | `playbook/pxe_server_setup.yml` (dnsmasq config) |
|
||||
| Hostname | pxeserver | `autoinstall/user-data` (identity.hostname) |
|
||||
|
||||
### Identity and credentials
|
||||
@@ -143,7 +143,7 @@ Blob storage account.
|
||||
### Image-upload paths on Windows
|
||||
|
||||
`scripts/Upload-Image.ps1` defaults to:
|
||||
- `\\10.9.100.1\image-upload` as the destination
|
||||
- `\\172.16.9.1\image-upload` as the destination
|
||||
- `C:\ProgramData\GEAerospace\MediaCreator\Cache\` as the source
|
||||
|
||||
Update both for a different site.
|
||||
@@ -156,10 +156,10 @@ A site config file should drive substitution at build time. Proposed schema:
|
||||
# config/sites/<sitename>.yaml
|
||||
site:
|
||||
name: westjeff
|
||||
pxe_server_ip: 10.9.100.1
|
||||
pxe_subnet: 10.9.100.0/24
|
||||
dhcp_range_start: 10.9.100.10
|
||||
dhcp_range_end: 10.9.100.100
|
||||
pxe_server_ip: 172.16.9.1
|
||||
pxe_subnet: 172.16.9.0/24
|
||||
dhcp_range_start: 172.16.9.10
|
||||
dhcp_range_end: 172.16.9.100
|
||||
hostname: pxeserver
|
||||
|
||||
credentials:
|
||||
|
||||
@@ -196,7 +196,7 @@ Two separate copies of overlapping content with different roles:
|
||||
|
||||
| Path | Source | Used by | Updated when |
|
||||
|------|--------|---------|--------------|
|
||||
| `C:\Enrollment\shopfloor-setup\` | PXE imaging copy from `\\10.9.100.1\enrollment\shopfloor-setup\` | Imaging-flow scripts: `Run-ShopfloorSetup.ps1`, `Stage-Dispatcher.ps1`, `Set-MachineNumber.ps1` -> `Update-MachineNumber.ps1` | Re-image only |
|
||||
| `C:\Enrollment\shopfloor-setup\` | PXE imaging copy from `\\172.16.9.1\enrollment\shopfloor-setup\` | Imaging-flow scripts: `Run-ShopfloorSetup.ps1`, `Stage-Dispatcher.ps1`, `Set-MachineNumber.ps1` -> `Update-MachineNumber.ps1` | Re-image only |
|
||||
| SFLD share `\<scope>\` | Direct upload | GE-Enforce.ps1 / Install-FromManifest.ps1 (every logon) | Direct file upload to share |
|
||||
|
||||
Implication for hot-fixing scripts: a fix to `Restore-UDCData.ps1` needs to
|
||||
|
||||
@@ -52,11 +52,11 @@ Add a new entry (insert before the existing `D12 OptiPlex Family / 7090` entry):
|
||||
the actual driver pack from Dell's catalog by model name (`extract_model_ids`
|
||||
matches "7080") and downloads the latest pack at run time.
|
||||
|
||||
### Side artifacts already on the live PXE server (10.9.100.1)
|
||||
### Side artifacts already on the live PXE server (172.16.9.1)
|
||||
|
||||
- `\\10.9.100.1\winpeapps\_shared\BIOS\OptiPlex_7080_1.37.0.exe` (39.8 MB, BIOS update)
|
||||
- `\\10.9.100.1\image-upload\Deploy\Out-of-box Drivers\Dell_11\OptiPlex\D11 OptiPlex Family\win11_70809ntr8_a09.zip` (Win11 driver pack, 2.6 GB)
|
||||
- `\\10.9.100.1\winpeapps\_shared\BIOS\models.txt` includes the 7080 line.
|
||||
- `\\172.16.9.1\winpeapps\_shared\BIOS\OptiPlex_7080_1.37.0.exe` (39.8 MB, BIOS update)
|
||||
- `\\172.16.9.1\image-upload\Deploy\Out-of-box Drivers\Dell_11\OptiPlex\D11 OptiPlex Family\win11_70809ntr8_a09.zip` (Win11 driver pack, 2.6 GB)
|
||||
- `\\172.16.9.1\winpeapps\_shared\BIOS\models.txt` includes the 7080 line.
|
||||
|
||||
These persist regardless of `geastandardpbr/` rebuilds. Only the model-registry
|
||||
edits need to be re-applied after a USB re-import.
|
||||
|
||||
@@ -6,7 +6,7 @@ Step-by-step for imaging a new (or replacement) shopfloor PC that will sit at a
|
||||
|
||||
- PC connected to the **PXE switch** (not the production network yet)
|
||||
- USB mouse + keyboard connected
|
||||
- PXE server is running and reachable (verify by pinging `10.9.100.1` from another PC on the same switch)
|
||||
- PXE server is running and reachable (verify by pinging `172.16.9.1` from another PC on the same switch)
|
||||
- **Target machine number** known (e.g., `7605`) — you can enter it at PXE time, or use `9999` as a placeholder if the PC will be configured at the bay later
|
||||
- **ARTS Lockdown request submitted** for this PC (or know that you'll submit one mid-imaging)
|
||||
|
||||
@@ -229,7 +229,7 @@ The script needs a desktop session. Won't run via WinRM/SSH/non-interactive. Mak
|
||||
|
||||
## Reference
|
||||
|
||||
- **PXE server**: `10.9.100.1`
|
||||
- **PXE server**: `172.16.9.1`
|
||||
- **SFLD share**: `\\tsgwp00525.wjs.geaerospace.net\shared\dt\shopfloor\`
|
||||
- **Manifest engine log**: `C:\GE Aerospace\machineapps-enforce.log`
|
||||
- **Intune sync transcript**: `C:\Logs\SFLD\sync_intune_transcript.txt`
|
||||
|
||||
@@ -166,11 +166,16 @@
|
||||
</SynchronousCommand>
|
||||
<SynchronousCommand wcm:action="add">
|
||||
<Order>6</Order>
|
||||
<CommandLine>msiexec.exe /i "C:\PreInstall\installers\powershell7\PowerShell-7.5.4-win-x64.msi" /qn /norestart ADD_PATH=1 USE_MU=0 ENABLE_MU=0 DISABLE_TELEMETRY=1</CommandLine>
|
||||
<Description>Install PowerShell 7 BEFORE PPKG so Intune SetupCredentials Win32App finds pwsh.exe (race fix)</Description>
|
||||
</SynchronousCommand>
|
||||
<SynchronousCommand wcm:action="add">
|
||||
<Order>7</Order>
|
||||
<CommandLine>powershell.exe -ExecutionPolicy Bypass -File "C:\run-enrollment.ps1"</CommandLine>
|
||||
<Description>Run GCCH Enrollment</Description>
|
||||
</SynchronousCommand>
|
||||
<SynchronousCommand wcm:action="add">
|
||||
<Order>7</Order>
|
||||
<Order>8</Order>
|
||||
<CommandLine>powershell.exe -ExecutionPolicy Bypass -File "C:\Enrollment\Run-ShopfloorSetup.ps1"</CommandLine>
|
||||
<Description>Run shopfloor PC type setup</Description>
|
||||
</SynchronousCommand>
|
||||
|
||||
@@ -80,10 +80,10 @@ echo " IFACE=$IFACE, bringing up..."
|
||||
ip link set "$IFACE" up || ifconfig "$IFACE" up
|
||||
sleep 2
|
||||
|
||||
SERVER=10.9.100.1
|
||||
ifconfig "$IFACE" 10.9.100.250 netmask 255.255.255.0 up
|
||||
SERVER=172.16.9.1
|
||||
ifconfig "$IFACE" 172.16.9.250 netmask 255.255.255.0 up
|
||||
sleep 1
|
||||
echo " IP: 10.9.100.250 SERVER: $SERVER"
|
||||
echo " IP: 172.16.9.250 SERVER: $SERVER"
|
||||
ip addr
|
||||
|
||||
echo "[3/5] Downloading airootfs.sfs (~756 MB)..."
|
||||
|
||||
@@ -176,7 +176,7 @@
|
||||
<username encrypted="false">blancco</username>
|
||||
<password encrypted="false">blancco</password>
|
||||
<domain/>
|
||||
<hostname>10.9.100.1</hostname>
|
||||
<hostname>172.16.9.1</hostname>
|
||||
<path>blancco-reports</path>
|
||||
<protocols key="protocol" type="array">
|
||||
<protocol selected="true">smb</protocol>
|
||||
|
||||
@@ -3,16 +3,16 @@
|
||||
# Previously this disabled all wired NICs at first logon to keep PPKG /
|
||||
# Intune enrollment routing internet traffic via WiFi. The wired NIC was
|
||||
# preferred by Windows because the PXE dnsmasq was handing out a default
|
||||
# gateway (dhcp-option=3,10.9.100.1) which Windows installed as a default
|
||||
# gateway (dhcp-option=3,172.16.9.1) which Windows installed as a default
|
||||
# route, and the lower interface metric of wired beat WiFi. Internet-bound
|
||||
# traffic then black-holed at 10.9.100.1 (the PXE server, which doesn't
|
||||
# traffic then black-holed at 172.16.9.1 (the PXE server, which doesn't
|
||||
# forward).
|
||||
#
|
||||
# That root cause was fixed by removing the dhcp-option=3 and =6 lines
|
||||
# from /etc/dnsmasq.conf on the PXE server. Without an advertised gateway
|
||||
# on the PXE side, Windows can't add a default route via wired, so all
|
||||
# internet traffic uses WiFi by default and the wired NIC stays harmless
|
||||
# for same-subnet PXE/SMB traffic to 10.9.100.1.
|
||||
# for same-subnet PXE/SMB traffic to 172.16.9.1.
|
||||
#
|
||||
# Side effect of the original behavior was an eDNC race: eDNC autostart
|
||||
# would fire while the wired NIC was still disabled and hit WSAEINVAL
|
||||
|
||||
@@ -2,6 +2,17 @@
|
||||
"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.",
|
||||
"Name": "Oracle Client 11.2",
|
||||
@@ -153,7 +164,7 @@
|
||||
"Type": "EXE",
|
||||
"InstallArgs": "",
|
||||
"LogFile": "C:\\Logs\\PreInstall\\Setup-OpenText.log",
|
||||
"PCTypes": ["Standard", "CMM", "Keyence", "Genspect", "WaxAndTrace", "Lab"]
|
||||
"PCTypes": ["Standard", "CMM", "Keyence", "Genspect", "WaxAndTrace", "Lab", "Heattreat"]
|
||||
},
|
||||
{
|
||||
"_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).",
|
||||
@@ -164,7 +175,9 @@
|
||||
"KillAfterDetection": true,
|
||||
"DetectionMethod": "Registry",
|
||||
"DetectionPath": "HKLM:\\SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Uninstall\\UDC",
|
||||
"PCTypes": ["Standard-Machine"]
|
||||
"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.",
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
# pxe-dhcp-hook.sh - dnsmasq dhcp-script hook.
|
||||
#
|
||||
# Runs every time a PXE client gets/changes/releases a DHCP lease on
|
||||
# 10.9.100.0/24. Flushes conntrack entries and drops any lingering
|
||||
# 172.16.9.0/24. Flushes conntrack entries and drops any lingering
|
||||
# TCP sockets for that client IP. Prevents stale server-side state from
|
||||
# causing "System error 53 - network path not found" when a WinPE client
|
||||
# re-images the same machine without a clean SMB session teardown.
|
||||
|
||||
@@ -14,7 +14,7 @@
|
||||
# Step 2: restart nmbd (NetBIOS daemon - separate from smbd)
|
||||
# Step 3: restart smbd (full smbd restart, kills all child sessions)
|
||||
# Step 4: kill any leftover smbd child processes that survived restart
|
||||
# Step 5: flush conntrack for 10.9.100.0/24 (kernel connection tracking)
|
||||
# Step 5: flush conntrack for 172.16.9.0/24 (kernel connection tracking)
|
||||
# Step 6: flush ARP / neighbour cache on br-pxe
|
||||
# Step 7: drop TCP sockets on port 445 via ss -K
|
||||
# Step 8: restart dnsmasq (DHCP/TFTP state as a last resort before reboot)
|
||||
@@ -56,10 +56,10 @@ sleep 1
|
||||
systemctl start smbd 2>&1
|
||||
pause "Step 4 done"
|
||||
|
||||
echo "=== Step 5/8: flush conntrack entries for 10.9.100.0/24 ==="
|
||||
echo "=== Step 5/8: flush conntrack entries for 172.16.9.0/24 ==="
|
||||
if command -v conntrack >/dev/null 2>&1; then
|
||||
conntrack -D -s 10.9.100.0/24 2>&1 || true
|
||||
conntrack -D -d 10.9.100.0/24 2>&1 || true
|
||||
conntrack -D -s 172.16.9.0/24 2>&1 || true
|
||||
conntrack -D -d 172.16.9.0/24 2>&1 || true
|
||||
else
|
||||
echo " conntrack tool not installed - skipping (apt install conntrack)"
|
||||
fi
|
||||
|
||||
@@ -72,7 +72,7 @@
|
||||
loop: "{{ ansible_interfaces | select('match','^e(th|n)') | list }}"
|
||||
ignore_errors: yes
|
||||
|
||||
- name: "Find interface with 10.9.100.1 already configured"
|
||||
- name: "Find interface with 172.16.9.1 already configured"
|
||||
set_fact:
|
||||
preconfigured_iface: >-
|
||||
{{ ansible_interfaces
|
||||
@@ -80,7 +80,7 @@
|
||||
| map('regex_replace','^(.*)$','ansible_\1')
|
||||
| map('extract', hostvars[inventory_hostname])
|
||||
| selectattr('ipv4','defined')
|
||||
| selectattr('ipv4.address','equalto','10.9.100.1')
|
||||
| selectattr('ipv4.address','equalto','172.16.9.1')
|
||||
| map(attribute='device')
|
||||
| list
|
||||
| first
|
||||
@@ -147,11 +147,11 @@
|
||||
port=0
|
||||
interface={{ pxe_iface }}
|
||||
bind-interfaces
|
||||
dhcp-range=10.9.100.10,10.9.100.100,12h
|
||||
dhcp-range=172.16.9.10,172.16.9.100,12h
|
||||
# No default gateway (option 3) and no DNS (option 6) handed out:
|
||||
# the PXE network is isolated and the PXE server does not forward
|
||||
# internet traffic. Previously we set both, which made imaged PCs
|
||||
# add a default route via 10.9.100.1 and prefer it over WiFi (lower
|
||||
# add a default route via 172.16.9.1 and prefer it over WiFi (lower
|
||||
# interface metric). PPKG / Intune enrollment then black-holed
|
||||
# internet-bound traffic. The fix used to be migrate-to-wifi.ps1
|
||||
# disabling the wired NIC during first-logon, which created an
|
||||
@@ -163,7 +163,7 @@
|
||||
# Important: dnsmasq DEFAULTS to sending its own listening address as
|
||||
# both router and DNS when these options are unset. Commenting them
|
||||
# out is NOT the same as disabling - imaged PCs (and Blancco PXE
|
||||
# clients) end up with 10.9.100.1 as gateway. The empty-value form
|
||||
# clients) end up with 172.16.9.1 as gateway. The empty-value form
|
||||
# below explicitly suppresses both options.
|
||||
dhcp-option=3
|
||||
dhcp-option=6
|
||||
@@ -227,7 +227,7 @@
|
||||
content: |
|
||||
#!ipxe
|
||||
|
||||
set server 10.9.100.1
|
||||
set server 172.16.9.1
|
||||
|
||||
:menu
|
||||
menu GE Aerospace PXE Boot Menu
|
||||
@@ -505,7 +505,7 @@
|
||||
|
||||
- name: "Deploy BIOS check script + manifest to winpeapps/_shared/BIOS/"
|
||||
# Path matches what startnet.cmd reads at WinPE boot:
|
||||
# net use B: \\10.9.100.1\winpeapps\_shared
|
||||
# net use B: \\172.16.9.1\winpeapps\_shared
|
||||
# if exist B:\BIOS\check-bios.cmd ...
|
||||
# Earlier deploy targeted enrollment/pre-install/bios/ (different share)
|
||||
# which startnet.cmd never read, so BIOS_STATUS perma-stuck on
|
||||
@@ -899,7 +899,7 @@
|
||||
shell: |
|
||||
set -e
|
||||
python3 -c 'import xml.etree.ElementTree as ET; ET.parse("{{ web_root }}/blancco/preferences.xml")'
|
||||
grep -q '<hostname>10.9.100.1</hostname>' "{{ web_root }}/blancco/preferences.xml"
|
||||
grep -q '<hostname>172.16.9.1</hostname>' "{{ web_root }}/blancco/preferences.xml"
|
||||
grep -q '<path>blancco-reports</path>' "{{ web_root }}/blancco/preferences.xml"
|
||||
changed_when: false
|
||||
|
||||
@@ -1089,7 +1089,7 @@
|
||||
# Single-NIC fresh-deploy default. Boxes that need higher throughput
|
||||
# (e.g. WJF prod uses a USB-C 5 Gbps NIC) override this with a bridge
|
||||
# config bonding the USB NIC + onboard NIC into br-pxe. Live override
|
||||
# currently deployed on 10.9.100.1 (do NOT re-run this task there
|
||||
# currently deployed on 172.16.9.1 (do NOT re-run this task there
|
||||
# without first reviewing /etc/netplan/50-cloud-init.yaml.pre-gold-swap):
|
||||
#
|
||||
# network:
|
||||
@@ -1101,7 +1101,7 @@
|
||||
# bridges:
|
||||
# br-pxe:
|
||||
# interfaces: [enp128s31f6, enx34c8d6b11010]
|
||||
# addresses: [10.9.100.1/24]
|
||||
# addresses: [172.16.9.1/24]
|
||||
# parameters:
|
||||
# stp: false
|
||||
#
|
||||
@@ -1120,7 +1120,7 @@
|
||||
ethernets:
|
||||
{{ pxe_iface }}:
|
||||
dhcp4: no
|
||||
addresses: [10.9.100.1/24]
|
||||
addresses: [172.16.9.1/24]
|
||||
notify: "Apply netplan"
|
||||
|
||||
handlers:
|
||||
|
||||
@@ -27,7 +27,7 @@ Write-Host "================================================================"
|
||||
Write-Host ""
|
||||
|
||||
# Imaging-progress reporter. Posts coarse stage updates to the PXE webapp
|
||||
# at http://10.9.100.1:9009/imaging/status so the operator can watch
|
||||
# at http://172.16.9.1:9009/imaging/status so the operator can watch
|
||||
# progress in a browser. Best-effort: failures never block imaging.
|
||||
$pxeStatusLib = Join-Path $PSScriptRoot 'shopfloor-setup\Shopfloor\lib\Send-PxeStatus.ps1'
|
||||
if (Test-Path $pxeStatusLib) {
|
||||
|
||||
@@ -165,8 +165,12 @@ if (Test-Path -LiteralPath $machineNumFile) {
|
||||
# before UDC_Setup.exe runs means the installer's File.Copy (overwrite:true)
|
||||
# would overwrite it IF the share were reachable, but since it isn't, our
|
||||
# pre-staged file survives and UDC launches with correct settings.
|
||||
# UDC payload (settings backups + webserver settings) lives only in the
|
||||
# collections per-pc-type dir - UDC is the "C" of "collections". On nocoll
|
||||
# bays the dir doesn't exist; Test-Path skips silently.
|
||||
$udcCollDir = Join-Path (Split-Path $PSScriptRoot -Parent) 'gea-shopfloor-collections'
|
||||
if ($machineNum -and $machineNum -ne '9999') {
|
||||
$udcBackupDir = 'C:\Enrollment\shopfloor-setup\Standard\udc-backups'
|
||||
$udcBackupDir = Join-Path $udcCollDir 'udc-backups'
|
||||
$udcBackup = Join-Path $udcBackupDir "udc_settings_$machineNum.json"
|
||||
$udcTarget = 'C:\ProgramData\UDC\udc_settings.json'
|
||||
if (Test-Path -LiteralPath $udcBackup) {
|
||||
@@ -176,11 +180,11 @@ if ($machineNum -and $machineNum -ne '9999') {
|
||||
Copy-Item -Path $udcBackup -Destination $udcTarget -Force
|
||||
Write-PreInstallLog "Pre-staged UDC settings from $udcBackup -> $udcTarget"
|
||||
} else {
|
||||
Write-PreInstallLog "No UDC settings backup for machine $machineNum in $udcBackupDir"
|
||||
Write-PreInstallLog "No UDC settings backup for machine $machineNum at $udcBackup (skipping - normal for nocoll bays)"
|
||||
}
|
||||
}
|
||||
|
||||
$udcWebSrc = 'C:\Enrollment\shopfloor-setup\Standard\udc_webserver_settings.json'
|
||||
$udcWebSrc = Join-Path $udcCollDir 'udc_webserver_settings.json'
|
||||
$udcWebDst = 'C:\ProgramData\UDC\udc_webserver_settings.json'
|
||||
if (Test-Path -LiteralPath $udcWebSrc) {
|
||||
if (-not (Test-Path 'C:\ProgramData\UDC')) {
|
||||
@@ -189,7 +193,7 @@ if (Test-Path -LiteralPath $udcWebSrc) {
|
||||
Copy-Item -Path $udcWebSrc -Destination $udcWebDst -Force
|
||||
Write-PreInstallLog "Pre-staged UDC webserver settings from $udcWebSrc -> $udcWebDst"
|
||||
} else {
|
||||
Write-PreInstallLog "No UDC webserver settings file at $udcWebSrc" "WARN"
|
||||
Write-PreInstallLog "No UDC webserver settings file at $udcWebSrc (skipping - normal for nocoll bays)"
|
||||
}
|
||||
|
||||
# --- Suppress Windows Defender Firewall "Allow access" prompts globally for
|
||||
@@ -326,8 +330,19 @@ foreach ($app in $config.Applications) {
|
||||
if ($g -icontains $n) { foreach ($x in $g) { [void]$myNames.Add($x) } }
|
||||
}
|
||||
}
|
||||
# PCTypesStrict=true bypasses the alias-expansion matcher and requires
|
||||
# the actual pcType (or composite pcProfileKey) to literally equal one
|
||||
# of the allowedTypes entries. Used by UDC because the alias graph
|
||||
# transitively connects gea-shopfloor-collections <-> nocollections via
|
||||
# the legacy 'Standard' group, which would otherwise cause UDC to install
|
||||
# on nocoll bays even with PCTypes=['gea-shopfloor-collections'].
|
||||
$matchesType = ($allowedTypes -contains '*')
|
||||
if (-not $matchesType) {
|
||||
if ($app.PCTypesStrict) {
|
||||
foreach ($t in $allowedTypes) {
|
||||
if (($pcType -ieq $t) -or ($pcProfileKey -ieq $t)) { $matchesType = $true; break }
|
||||
}
|
||||
} else {
|
||||
foreach ($t in $allowedTypes) {
|
||||
if ($myNames.Contains($t)) { $matchesType = $true; break }
|
||||
foreach ($g in $aliasGroups) {
|
||||
@@ -338,6 +353,7 @@ foreach ($app in $config.Applications) {
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if (-not $matchesType) {
|
||||
Write-PreInstallLog " PCTypes filter excludes '$pcProfileKey' (allowed: $($allowedTypes -join ', ')) - skipping"
|
||||
$skipped++
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
#
|
||||
# Reason: GE's Intune Proactive-Remediation "Report IP" script enumerates
|
||||
# Get-NetIPAddress and POSTs every IP it finds to a GE webhook. When a
|
||||
# shopfloor bay is still cabled to the air-gapped PXE LAN (10.9.100.0/24),
|
||||
# shopfloor bay is still cabled to the air-gapped PXE LAN (172.16.9.0/24),
|
||||
# the webhook sees 10.9.100.x as one of the device's IPs and tags the bay
|
||||
# "not on corp net". A dynamic group / assignment-filter at GE then excludes
|
||||
# the bay from receiving the SFLD ConfigurationProfile (Function + SasToken
|
||||
|
||||
@@ -66,6 +66,15 @@ if (Test-Path -LiteralPath $subtypeFile) {
|
||||
$pcSubtype = (Get-Content -LiteralPath $subtypeFile -First 1 -ErrorAction SilentlyContinue).Trim()
|
||||
}
|
||||
|
||||
# Display sub-type fallback: if pc-subtype.txt is absent (post-rename-reorg
|
||||
# default) but display-type.txt exists, use it as the subtype. Lets the
|
||||
# Display-Lobby / Display-Dashboard / gea-shopfloor-display-{lobby,dashboard}
|
||||
# profile keys resolve correctly for Display PCs.
|
||||
$displayTypeFile = 'C:\Enrollment\display-type.txt'
|
||||
if (-not $pcSubtype -and ($pcType -ieq 'gea-shopfloor-display' -or $pcType -ieq 'Display') -and (Test-Path -LiteralPath $displayTypeFile)) {
|
||||
$pcSubtype = (Get-Content -LiteralPath $displayTypeFile -First 1 -ErrorAction SilentlyContinue).Trim()
|
||||
}
|
||||
|
||||
# Build the profile key: "Standard-Machine", "CMM", "Display-Lobby", etc.
|
||||
$profileKey = if ($pcSubtype) { "$pcType-$pcSubtype" } else { $pcType }
|
||||
|
||||
@@ -82,6 +91,8 @@ $pcProfileAliasGroups = @(
|
||||
@('WaxAndTrace', 'gea-shopfloor-waxtrace'),
|
||||
@('Genspect', 'gea-shopfloor-genspect'),
|
||||
@('Display', 'gea-shopfloor-display'),
|
||||
@('Display-Lobby', 'gea-shopfloor-display-Lobby', 'gea-shopfloor-display-lobby'),
|
||||
@('Display-Dashboard', 'gea-shopfloor-display-Dashboard', 'gea-shopfloor-display-dashboard'),
|
||||
@('Heattreat', 'gea-shopfloor-heattreat')
|
||||
)
|
||||
|
||||
|
||||
@@ -19,7 +19,7 @@ function Send-PxeStatus {
|
||||
# Only available post-AAD-join; pass it from Monitor-IntuneProgress
|
||||
# once captured. The dashboard renders a QR of this value.
|
||||
[string]$IntuneDeviceId = '',
|
||||
[string]$PxeServer = '10.9.100.1',
|
||||
[string]$PxeServer = '172.16.9.1',
|
||||
[int]$Port = 9009,
|
||||
[int]$TimeoutSec = 5
|
||||
)
|
||||
|
||||
@@ -0,0 +1,44 @@
|
||||
# Set-OpenTextAutoStart.ps1 - place WJ Shopfloor.lnk in the All Users
|
||||
# Startup folder so HostExplorer's "WJ Shopfloor" session launches at
|
||||
# every login. Idempotent: re-running is a no-op when the .lnk already
|
||||
# exists at the same path.
|
||||
#
|
||||
# Used by per-pc-type 09-Setup scripts for shopfloor types whose only
|
||||
# business app is OpenText (common, waxtrace, genspect, heattreat).
|
||||
# collections + nocollections do NOT auto-start OpenText - their techs
|
||||
# pick which apps via Configure-PC.ps1.
|
||||
#
|
||||
# Source .lnk is created by the OpenText preinstall (Setup-OpenText.ps1)
|
||||
# on the public desktop. If the .lnk is missing, log a warning and exit
|
||||
# 0 - imaging chain still continues; auto-start can be re-attempted on a
|
||||
# subsequent login by re-running this script.
|
||||
|
||||
$ErrorActionPreference = 'Continue'
|
||||
|
||||
$startupDir = 'C:\ProgramData\Microsoft\Windows\Start Menu\Programs\StartUp'
|
||||
$publicDesktop = 'C:\Users\Public\Desktop'
|
||||
|
||||
$candidates = @(
|
||||
Join-Path $publicDesktop 'WJ Shopfloor.lnk'
|
||||
Join-Path (Join-Path $publicDesktop 'Shopfloor Tools') 'WJ Shopfloor.lnk'
|
||||
)
|
||||
$src = $candidates | Where-Object { Test-Path -LiteralPath $_ } | Select-Object -First 1
|
||||
|
||||
if (-not $src) {
|
||||
Write-Warning "WJ Shopfloor.lnk not found on public desktop - OpenText auto-start NOT configured."
|
||||
Write-Warning " Searched: $($candidates -join ' ; ')"
|
||||
Write-Warning " Setup-OpenText.ps1 should create it during preinstall - check OpenText install state."
|
||||
return
|
||||
}
|
||||
|
||||
if (-not (Test-Path -LiteralPath $startupDir)) {
|
||||
New-Item -Path $startupDir -ItemType Directory -Force | Out-Null
|
||||
}
|
||||
|
||||
$dst = Join-Path $startupDir 'WJ Shopfloor.lnk'
|
||||
try {
|
||||
Copy-Item -LiteralPath $src -Destination $dst -Force
|
||||
Write-Host "OpenText auto-start enabled: $dst (source: $src)"
|
||||
} catch {
|
||||
Write-Warning "Failed to copy WJ Shopfloor.lnk to startup: $_"
|
||||
}
|
||||
@@ -36,7 +36,7 @@ $siteConfig = Get-SiteConfig
|
||||
$siteName = if ($siteConfig) { $siteConfig.siteName } else { 'West Jefferson' }
|
||||
$siteNameCompact = if ($siteConfig) { $siteConfig.siteNameCompact } else { 'WestJefferson' }
|
||||
|
||||
$edncDir = "C:\Enrollment\shopfloor-setup\Standard\eDNC"
|
||||
$edncDir = Join-Path $PSScriptRoot 'eDNC'
|
||||
|
||||
if (-not (Test-Path $edncDir)) {
|
||||
Write-Warning "eDNC folder not found at $edncDir - skipping."
|
||||
|
||||
@@ -54,7 +54,11 @@ if (-not $machineNum -or $machineNum -eq '9999') {
|
||||
Write-Host "Machine number: $machineNum"
|
||||
|
||||
# ---- Locate local backup root (staged from PXE during imaging) ----
|
||||
$backupRoot = 'C:\Enrollment\shopfloor-setup\Standard\ntlars-backups'
|
||||
# Lives at C:\Enrollment\shopfloor-setup\_ntlars-backups (one shared dir
|
||||
# at the root of the staged shopfloor-setup tree, populated by Ansible
|
||||
# from playbook/shopfloor-setup/_ntlars-backups). Path is relative to
|
||||
# this script so it follows wherever per-pc-type dir is staged.
|
||||
$backupRoot = Join-Path $PSScriptRoot '..\_ntlars-backups'
|
||||
if (-not (Test-Path $backupRoot)) {
|
||||
Write-Host "ntlars-backups folder not staged at $backupRoot - skipping."
|
||||
try { Stop-Transcript | Out-Null } catch {}
|
||||
|
||||
@@ -6,7 +6,7 @@ REM 1. %~dp0Set-MachineNumber.ps1
|
||||
REM - .bat and .ps1 side-by-side (normal desktop-copied case, repo layout)
|
||||
REM 2. C:\Users\SupportUser\Desktop\Set-MachineNumber.ps1
|
||||
REM - dispatcher-copied location, if this .bat lives somewhere else
|
||||
REM 3. C:\Enrollment\shopfloor-setup\Standard\Set-MachineNumber.ps1
|
||||
REM 3. C:\Enrollment\shopfloor-setup\gea-shopfloor-collections\Set-MachineNumber.ps1
|
||||
REM - canonical enrollment staging copy
|
||||
REM
|
||||
REM Goto-based dispatch - no nested if blocks, no literal parens in echo lines.
|
||||
@@ -21,13 +21,13 @@ if exist "%PS1%" goto :run
|
||||
set "PS1=C:\Users\SupportUser\Desktop\Set-MachineNumber.ps1"
|
||||
if exist "%PS1%" goto :run
|
||||
|
||||
set "PS1=C:\Enrollment\shopfloor-setup\Standard\Set-MachineNumber.ps1"
|
||||
set "PS1=C:\Enrollment\shopfloor-setup\gea-shopfloor-collections\Set-MachineNumber.ps1"
|
||||
if exist "%PS1%" goto :run
|
||||
|
||||
echo ERROR: Set-MachineNumber.ps1 not found in any of:
|
||||
echo %~dp0Set-MachineNumber.ps1
|
||||
echo C:\Users\SupportUser\Desktop\Set-MachineNumber.ps1
|
||||
echo C:\Enrollment\shopfloor-setup\Standard\Set-MachineNumber.ps1
|
||||
echo C:\Enrollment\shopfloor-setup\gea-shopfloor-collections\Set-MachineNumber.ps1
|
||||
echo.
|
||||
pause
|
||||
exit /b 1
|
||||
|
||||
BIN
playbook/shopfloor-setup/gea-shopfloor-collections/eDNC/eDNC_6-4-5.msi
Executable file
@@ -1,12 +0,0 @@
|
||||
# 09-Setup-Lab.ps1 - Lab-specific setup (runs after Shopfloor baseline)
|
||||
#
|
||||
# PLACEHOLDER: add type-specific app installs when details are finalized.
|
||||
# This script will be called by Run-ShopfloorSetup.ps1 as part of the
|
||||
# type-specific phase, after all baseline scripts have completed.
|
||||
#
|
||||
# For share-based installs, copy the pattern from CMM/09-Setup-CMM.ps1
|
||||
# (credential lookup + share mount + install from share).
|
||||
|
||||
Write-Host "=== Lab Setup ==="
|
||||
Write-Host " (no type-specific apps configured yet)"
|
||||
Write-Host "=== Lab Setup Complete ==="
|
||||
@@ -36,7 +36,7 @@ $siteConfig = Get-SiteConfig
|
||||
$siteName = if ($siteConfig) { $siteConfig.siteName } else { 'West Jefferson' }
|
||||
$siteNameCompact = if ($siteConfig) { $siteConfig.siteNameCompact } else { 'WestJefferson' }
|
||||
|
||||
$edncDir = "C:\Enrollment\shopfloor-setup\Standard\eDNC"
|
||||
$edncDir = Join-Path $PSScriptRoot 'eDNC'
|
||||
|
||||
if (-not (Test-Path $edncDir)) {
|
||||
Write-Warning "eDNC folder not found at $edncDir - skipping."
|
||||
|
||||
@@ -54,7 +54,8 @@ if (-not $machineNum -or $machineNum -eq '9999') {
|
||||
Write-Host "Machine number: $machineNum"
|
||||
|
||||
# ---- Locate local backup root (staged from PXE during imaging) ----
|
||||
$backupRoot = 'C:\Enrollment\shopfloor-setup\Standard\ntlars-backups'
|
||||
# Lives at C:\Enrollment\shopfloor-setup\_ntlars-backups (shared root dir).
|
||||
$backupRoot = Join-Path $PSScriptRoot '..\_ntlars-backups'
|
||||
if (-not (Test-Path $backupRoot)) {
|
||||
Write-Host "ntlars-backups folder not staged at $backupRoot - skipping."
|
||||
try { Stop-Transcript | Out-Null } catch {}
|
||||
|
||||
@@ -6,7 +6,7 @@ REM 1. %~dp0Set-MachineNumber.ps1
|
||||
REM - .bat and .ps1 side-by-side (normal desktop-copied case, repo layout)
|
||||
REM 2. C:\Users\SupportUser\Desktop\Set-MachineNumber.ps1
|
||||
REM - dispatcher-copied location, if this .bat lives somewhere else
|
||||
REM 3. C:\Enrollment\shopfloor-setup\Standard\Set-MachineNumber.ps1
|
||||
REM 3. C:\Enrollment\shopfloor-setup\gea-shopfloor-nocollections\Set-MachineNumber.ps1
|
||||
REM - canonical enrollment staging copy
|
||||
REM
|
||||
REM Goto-based dispatch - no nested if blocks, no literal parens in echo lines.
|
||||
@@ -21,13 +21,13 @@ if exist "%PS1%" goto :run
|
||||
set "PS1=C:\Users\SupportUser\Desktop\Set-MachineNumber.ps1"
|
||||
if exist "%PS1%" goto :run
|
||||
|
||||
set "PS1=C:\Enrollment\shopfloor-setup\Standard\Set-MachineNumber.ps1"
|
||||
set "PS1=C:\Enrollment\shopfloor-setup\gea-shopfloor-nocollections\Set-MachineNumber.ps1"
|
||||
if exist "%PS1%" goto :run
|
||||
|
||||
echo ERROR: Set-MachineNumber.ps1 not found in any of:
|
||||
echo %~dp0Set-MachineNumber.ps1
|
||||
echo C:\Users\SupportUser\Desktop\Set-MachineNumber.ps1
|
||||
echo C:\Enrollment\shopfloor-setup\Standard\Set-MachineNumber.ps1
|
||||
echo C:\Enrollment\shopfloor-setup\gea-shopfloor-nocollections\Set-MachineNumber.ps1
|
||||
echo.
|
||||
pause
|
||||
exit /b 1
|
||||
|
||||
BIN
playbook/shopfloor-setup/gea-shopfloor-nocollections/eDNC/eDNC_6-4-5.msi
Executable file
@@ -98,6 +98,30 @@
|
||||
]
|
||||
},
|
||||
|
||||
"gea-shopfloor-nocollections": {
|
||||
"_comment": "Shopfloor PC running eDNC + NTLARS + Defect Tracker but no UDC (no Collections). Same as Standard-Machine minus UDC pin/desktop/startup. Direct profile lookup (line 92 in Get-PCProfile.ps1) finds this BEFORE the alias-group fallback to Standard-Machine, so Standard-Machine's UDC entries do not leak through.",
|
||||
"machineappsSharePath": "\\\\tsgwp00525.wjs.geaerospace.net\\shared\\dt\\shopfloor\\main\\machineapps",
|
||||
"ntlarsBackupSharePath": "\\\\tsgwp00525.wjs.geaerospace.net\\shared\\dt\\shopfloor\\main\\ntlars-backups",
|
||||
"startupItems": [
|
||||
{ "label": "WJ Shopfloor", "type": "existing", "sourceLnk": "WJ Shopfloor.lnk" },
|
||||
{ "label": "Plant Apps", "type": "url", "urlKey": "plantApps" },
|
||||
{ "label": "eDNC", "type": "exe", "target": "C:\\Program Files (x86)\\Dnc\\bin\\DncMain.exe" }
|
||||
],
|
||||
"taskbarPins": [
|
||||
{ "name": "Microsoft Edge", "lnkPath": "%ALLUSERSPROFILE%\\Microsoft\\Windows\\Start Menu\\Programs\\Microsoft Edge.lnk" },
|
||||
{ "name": "WJ Shopfloor", "lnkPath": "%PUBLIC%\\Desktop\\Shopfloor Tools\\WJ Shopfloor.lnk" },
|
||||
{ "name": "eDNC", "lnkPath": "%PUBLIC%\\Desktop\\Shopfloor Tools\\eDNC.lnk" },
|
||||
{ "name": "NTLARS", "lnkPath": "%PUBLIC%\\Desktop\\Shopfloor Tools\\NTLARS.lnk" },
|
||||
{ "name": "Defect_Tracker", "lnkPath": "%PUBLIC%\\Desktop\\Shopfloor Tools\\Defect_Tracker.lnk" }
|
||||
],
|
||||
"desktopApps": [
|
||||
{ "name": "eDNC", "kind": "exe", "exePath": "C:\\Program Files (x86)\\Dnc\\bin\\DncMain.exe" },
|
||||
{ "name": "NTLARS", "kind": "exe", "exePath": "C:\\Program Files (x86)\\Dnc\\Common\\NTLARS.exe" },
|
||||
{ "name": "WJ Shopfloor", "kind": "existing", "sourceName": "WJ Shopfloor.lnk" },
|
||||
{ "name": "Defect_Tracker", "kind": "exe", "exePath": "C:\\Program Files (x86)\\WJF_Defect_Tracker\\Defect_Tracker.exe" }
|
||||
]
|
||||
},
|
||||
|
||||
"CMM": {
|
||||
"_comment": "Hexagon CMM apps (CLM 1.8, goCMM, PC-DMIS 2016, PC-DMIS 2019 R2). At imaging time they install from a WinPE-staged local bootstrap at C:\\CMM-Install (put there by startnet.cmd when pc-type=CMM, source is the PXE server enrollment share). Post-imaging, the unified GE-Enforce dispatcher reads cmm/manifest.json on the tsgwp00525 share below and enforces versions on every user logon (the SFLD creds Azure DSC provisions unlock the mount). cmmSharePath is the ongoing-enforcement source, not the imaging-time source.",
|
||||
"cmmSharePath": "\\\\tsgwp00525.wjs.geaerospace.net\\shared\\dt\\shopfloor\\cmm\\machineapps",
|
||||
|
||||
@@ -6,7 +6,7 @@ powercfg /s 8c5e7fda-e8bf-4a96-9a85-a6e23a8c635c
|
||||
REM --- Wait for network (DHCP may take a moment after wpeinit) ---
|
||||
echo Waiting for network...
|
||||
:wait_net
|
||||
ping -n 2 10.9.100.1 >NUL 2>&1
|
||||
ping -n 2 172.16.9.1 >NUL 2>&1
|
||||
if errorlevel 1 goto wait_net
|
||||
echo Network ready.
|
||||
|
||||
@@ -17,7 +17,7 @@ REM CALLed scripts inside parens does not propagate BIOS_STATUS back to
|
||||
REM this script reliably. Use goto-flow instead so the CALL runs at the
|
||||
REM top scope and BIOS_STATUS persists.
|
||||
set BIOS_STATUS=No BIOS check (share unavailable)
|
||||
net use B: \\10.9.100.1\winpeapps_bios /user:pxe-upload pxe /persistent:no 2>NUL
|
||||
net use B: \\172.16.9.1\winpeapps_bios /user:pxe-upload pxe /persistent:no 2>NUL
|
||||
if not exist B:\check-bios.cmd goto :bios_check_done
|
||||
echo.
|
||||
echo Checking for BIOS updates...
|
||||
@@ -167,7 +167,7 @@ set NEED_ENROLL=0
|
||||
if not "%PPKG%"=="" set NEED_ENROLL=1
|
||||
if not "%PCTYPE%"=="" set NEED_ENROLL=1
|
||||
if "%NEED_ENROLL%"=="0" goto enroll_staged
|
||||
net use Y: \\10.9.100.1\enrollment /user:pxe-upload pxe /persistent:no
|
||||
net use Y: \\172.16.9.1\enrollment /user:pxe-upload pxe /persistent:no
|
||||
if "%PPKG%"=="" goto enroll_staged
|
||||
if not exist "Y:\ppkgs\%SOURCE_PPKG%" (
|
||||
echo WARNING: %SOURCE_PPKG% not found on server. Enrollment will be skipped.
|
||||
@@ -192,7 +192,7 @@ echo.
|
||||
echo Starting GEA Standard setup...
|
||||
start "FlatApp" %SYSTEMDRIVE%\GESetup\FlatSetupLoader.exe
|
||||
for /l %%i in (1,1,2000000) do rem
|
||||
net use Z: \\10.9.100.1\winpeapps\gea-standard /user:pxe-upload pxe /persistent:no
|
||||
net use Z: \\172.16.9.1\winpeapps\gea-standard /user:pxe-upload pxe /persistent:no
|
||||
goto end
|
||||
|
||||
:gea-engineer
|
||||
@@ -200,7 +200,7 @@ echo.
|
||||
echo Starting GEA Engineer setup...
|
||||
start "FlatApp" %SYSTEMDRIVE%\GESetup\FlatSetupLoader.exe
|
||||
for /l %%i in (1,1,2000000) do rem
|
||||
net use Z: \\10.9.100.1\winpeapps\gea-engineer /user:pxe-upload pxe /persistent:no
|
||||
net use Z: \\172.16.9.1\winpeapps\gea-engineer /user:pxe-upload pxe /persistent:no
|
||||
goto end
|
||||
|
||||
:gea-shopfloor
|
||||
@@ -208,7 +208,7 @@ echo.
|
||||
echo Starting GEA Shopfloor setup...
|
||||
start "FlatApp" %SYSTEMDRIVE%\GESetup\FlatSetupLoader.exe
|
||||
for /l %%i in (1,1,2000000) do rem
|
||||
net use Z: \\10.9.100.1\winpeapps\gea-shopfloor /user:pxe-upload pxe /persistent:no
|
||||
net use Z: \\172.16.9.1\winpeapps\gea-shopfloor /user:pxe-upload pxe /persistent:no
|
||||
goto end
|
||||
|
||||
:ge-standard
|
||||
@@ -216,7 +216,7 @@ echo.
|
||||
echo Starting GE Standard setup...
|
||||
start "FlatApp" %SYSTEMDRIVE%\GESetup\FlatSetupLoader.exe
|
||||
for /l %%i in (1,1,2000000) do rem
|
||||
net use Z: \\10.9.100.1\winpeapps\ge-standard /user:pxe-upload pxe /persistent:no
|
||||
net use Z: \\172.16.9.1\winpeapps\ge-standard /user:pxe-upload pxe /persistent:no
|
||||
goto end
|
||||
|
||||
:ge-engineer
|
||||
@@ -224,7 +224,7 @@ echo.
|
||||
echo Starting GE Engineer setup...
|
||||
start "FlatApp" %SYSTEMDRIVE%\GESetup\FlatSetupLoader.exe
|
||||
for /l %%i in (1,1,2000000) do rem
|
||||
net use Z: \\10.9.100.1\winpeapps\ge-engineer /user:pxe-upload pxe /persistent:no
|
||||
net use Z: \\172.16.9.1\winpeapps\ge-engineer /user:pxe-upload pxe /persistent:no
|
||||
goto end
|
||||
|
||||
:ge-shopfloor-lockdown
|
||||
@@ -232,7 +232,7 @@ echo.
|
||||
echo Starting GE Shopfloor Lockdown setup...
|
||||
start "FlatApp" %SYSTEMDRIVE%\GESetup\FlatSetupLoader.exe
|
||||
for /l %%i in (1,1,2000000) do rem
|
||||
net use Z: \\10.9.100.1\winpeapps\ge-shopfloor-lockdown /user:pxe-upload pxe /persistent:no
|
||||
net use Z: \\172.16.9.1\winpeapps\ge-shopfloor-lockdown /user:pxe-upload pxe /persistent:no
|
||||
goto end
|
||||
|
||||
:ge-shopfloor-mce
|
||||
@@ -240,7 +240,7 @@ echo.
|
||||
echo Starting GE Shopfloor MCE setup...
|
||||
start "FlatApp" %SYSTEMDRIVE%\GESetup\FlatSetupLoader.exe
|
||||
for /l %%i in (1,1,2000000) do rem
|
||||
net use Z: \\10.9.100.1\winpeapps\ge-shopfloor-mce /user:pxe-upload pxe /persistent:no
|
||||
net use Z: \\172.16.9.1\winpeapps\ge-shopfloor-mce /user:pxe-upload pxe /persistent:no
|
||||
goto end
|
||||
|
||||
:end
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
#
|
||||
# Copies the Hexagon installers + cmm-manifest.json from the local workstation
|
||||
# to /srv/samba/enrollment/cmm-installers on the PXE server. That directory
|
||||
# becomes visible as \\10.9.100.1\enrollment\cmm-installers so startnet.cmd
|
||||
# becomes visible as \\172.16.9.1\enrollment\cmm-installers so startnet.cmd
|
||||
# can xcopy it onto the target disk during WinPE phase.
|
||||
#
|
||||
# Run this on the workstation (not on the PXE server) any time:
|
||||
@@ -24,7 +24,7 @@ set -euo pipefail
|
||||
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
||||
PROJECT_ROOT="$(cd "$SCRIPT_DIR/.." && pwd)"
|
||||
|
||||
PXE_HOST="${PXE_HOST:-10.9.100.1}"
|
||||
PXE_HOST="${PXE_HOST:-172.16.9.1}"
|
||||
PXE_USER="${PXE_USER:-pxe}"
|
||||
PXE_PASS="${PXE_PASS:-pxe}"
|
||||
|
||||
|
||||
@@ -19,7 +19,7 @@ set -euo pipefail
|
||||
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
||||
PROJECT_ROOT="$(cd "$SCRIPT_DIR/.." && pwd)"
|
||||
|
||||
PXE_HOST="${PXE_HOST:-10.9.100.1}"
|
||||
PXE_HOST="${PXE_HOST:-172.16.9.1}"
|
||||
PXE_USER="${PXE_USER:-pxe}"
|
||||
PXE_PASS="${PXE_PASS:-pxe}"
|
||||
|
||||
|
||||
@@ -10,7 +10,7 @@
|
||||
# X:\Windows\Temp\winpe-status-push.log; failures are swallowed.
|
||||
|
||||
param(
|
||||
[string]$PxeServer = '10.9.100.1',
|
||||
[string]$PxeServer = '172.16.9.1',
|
||||
[int]$Port = 9009,
|
||||
[int]$TimeoutSec = 5,
|
||||
[string]$PCType = $env:PCTYPE
|
||||
|
||||
@@ -8,15 +8,15 @@
|
||||
# .\Upload-Image.ps1 (selected OS + packages, no drivers)
|
||||
# .\Upload-Image.ps1 -IncludeDrivers (also upload selected hardware drivers)
|
||||
# .\Upload-Image.ps1 -CachePath "D:\MCL\Cache" (custom cache location)
|
||||
# .\Upload-Image.ps1 -Server 10.9.100.1 (custom server IP)
|
||||
# .\Upload-Image.ps1 -Server 172.16.9.1 (custom server IP)
|
||||
#
|
||||
# After upload, use the PXE webapp (http://10.9.100.1:9009) to import
|
||||
# After upload, use the PXE webapp (http://172.16.9.1:9009) to import
|
||||
# the uploaded content into the desired image type.
|
||||
#
|
||||
|
||||
param(
|
||||
[string]$CachePath = "C:\ProgramData\GEAerospace\MediaCreator\Cache",
|
||||
[string]$Server = "10.9.100.1",
|
||||
[string]$Server = "172.16.9.1",
|
||||
[string]$User = "pxe-upload",
|
||||
[string]$Pass = "pxe",
|
||||
[switch]$IncludeDrivers
|
||||
|
||||
@@ -350,8 +350,8 @@ echo " - Network: Bridge connected to isolated PXE network"
|
||||
echo " 3. Attach ISO as CD-ROM and start the VM"
|
||||
echo " 4. Ubuntu auto-installs (~10-15 minutes, zero interaction)"
|
||||
echo " 5. After reboot, first-boot configures all PXE services"
|
||||
echo " 6. Access webapp at http://10.9.100.1:9009"
|
||||
echo " 6. Access webapp at http://172.16.9.1:9009"
|
||||
echo ""
|
||||
echo "NOTE: The VM's network bridge must be connected to your isolated PXE"
|
||||
echo " network. The server will use static IP 10.9.100.1/24."
|
||||
echo " network. The server will use static IP 172.16.9.1/24."
|
||||
echo ""
|
||||
|
||||
@@ -3,12 +3,12 @@
|
||||
# Copies Flash64W.exe, BIOS binaries, models.txt, and check-bios.cmd
|
||||
#
|
||||
# Usage: ./deploy-bios.sh [server-ip]
|
||||
# Default server: 10.9.100.1
|
||||
# Default server: 172.16.9.1
|
||||
|
||||
set -e
|
||||
|
||||
REPO_ROOT="$(cd "$(dirname "$0")"/.. && pwd)"
|
||||
PXE_SERVER="${1:-10.9.100.1}"
|
||||
PXE_SERVER="${1:-172.16.9.1}"
|
||||
PXE_USER="pxe"
|
||||
PXE_PASS="pxe"
|
||||
REMOTE_DIR="/srv/samba/enrollment/BIOS"
|
||||
|
||||
@@ -23,7 +23,7 @@
|
||||
|
||||
Output lands under C:\ProgramData\state-<stage>-<timestamp>\.
|
||||
Copy the whole folder back to the workstation
|
||||
(\\10.9.100.1\image-upload or dump to pxe-images manually) and diff.
|
||||
(\\172.16.9.1\image-upload or dump to pxe-images manually) and diff.
|
||||
|
||||
Diffing tips:
|
||||
pre-category -> post-category : what the category-driven Intune
|
||||
@@ -175,6 +175,189 @@ Step "dsregcmd /status" {
|
||||
dsregcmd /status 2>&1 | Out-File "$out\dsregcmd.txt"
|
||||
}
|
||||
|
||||
# --- Intune readiness probe (4-layer gate, frozen at this snapshot moment).
|
||||
# Aligned with Microsoft's documented IME / ESP gates - see:
|
||||
# https://learn.microsoft.com/en-us/windows/client-management/mdm-diagnose-enrollment
|
||||
# https://patchmypc.com/blog/intune-management-extension-esp-phases/
|
||||
#
|
||||
# Layer 1 - AAD + MDM enrollment object exists
|
||||
# AzureAdJoined, IntuneEnrolled (HKLM\Enrollments\<GUID> EnrollmentState=1)
|
||||
# Layer 2 - Microsoft's own success markers
|
||||
# MdmEnrollEvent75Found ("Auto MDM Enroll: Succeeded" in DeviceManagement-Enterprise-Diagnostics-Provider/Admin)
|
||||
# No MdmEnrollEvent76Found (failure) within last 7d
|
||||
# HasProvisioningCompleted=1 in OMADM\Accounts\<id>
|
||||
# FirstSync IsSyncDone=1 in Enrollments\<id>\FirstSync
|
||||
# Layer 3 - Policy actually delivered (CSP succeeded, not just provider registered)
|
||||
# PolicyManager\Providers\<EnrollmentId>\default\Device exists
|
||||
# PolicyManager\current\device has subkeys
|
||||
# Layer 4 - IME running (Win32App / PowerShell channel ready)
|
||||
# IME service running, IME log dir populated
|
||||
# Sidecar Policy Provider InstallationState=Completed (best-effort log grep)
|
||||
#
|
||||
# Pre-category snapshots that show layers 2-3 red = category assigned too
|
||||
# early -> reboot races the policy/payload pull -> stalled deploy -> re-image.
|
||||
Step "intune category-readiness probe" {
|
||||
$r = [ordered]@{
|
||||
# Layer 1
|
||||
AzureAdJoined = $false
|
||||
AzureAdTenant = $null
|
||||
DeviceId = $null
|
||||
IntuneEnrolled = $false
|
||||
EnrollmentId = $null
|
||||
# Layer 2
|
||||
MdmEnrollEvent75Found = $false
|
||||
MdmEnrollEvent75Time = $null
|
||||
MdmEnrollEvent76Found = $false
|
||||
MdmEnrollEvent76Time = $null
|
||||
HasProvisioningCompleted = $false
|
||||
FirstSyncIsSyncDone = $false
|
||||
# Layer 3
|
||||
PolicyManagerProviderForEnrollment = $false
|
||||
PolicyManagerCurrentDeviceSubkeys = 0
|
||||
# Layer 4
|
||||
ImeServiceRunning = $false
|
||||
ImeLogDirPopulated = $false
|
||||
SidecarInstallationState = $null # 'Completed' | 'InProgress' | $null
|
||||
# Misc
|
||||
LastSyncEventTime = $null
|
||||
Stage = $Stage
|
||||
SnapshotTime = $null
|
||||
}
|
||||
|
||||
# Layer 1: AAD + tenant + DeviceId
|
||||
try {
|
||||
$ds = & dsregcmd /status 2>&1 | Out-String
|
||||
if ($ds -match 'AzureAdJoined\s*:\s*YES') { $r.AzureAdJoined = $true }
|
||||
if ($ds -match 'TenantId\s*:\s*(\S+)') { $r.AzureAdTenant = $matches[1] }
|
||||
if ($ds -match '(?m)^\s*DeviceId\s*:\s*(\S+)') { $r.DeviceId = $matches[1] }
|
||||
} catch {}
|
||||
|
||||
# Layer 1: enrollment record
|
||||
try {
|
||||
$eks = Get-ChildItem 'HKLM:\SOFTWARE\Microsoft\Enrollments' -ErrorAction SilentlyContinue |
|
||||
Where-Object {
|
||||
$p = Get-ItemProperty $_.PSPath -ErrorAction SilentlyContinue
|
||||
$p -and $p.EnrollmentState -eq 1 -and $_.PSChildName -ne 'Context'
|
||||
}
|
||||
if ($eks) {
|
||||
$r.IntuneEnrolled = $true
|
||||
$r.EnrollmentId = $eks[0].PSChildName
|
||||
}
|
||||
} catch {}
|
||||
|
||||
# Layer 2: event 75 (success) + 76 (failure) in last 7d
|
||||
try {
|
||||
$cutoff = (Get-Date).AddDays(-7)
|
||||
$evts = Get-WinEvent -LogName 'Microsoft-Windows-DeviceManagement-Enterprise-Diagnostics-Provider/Admin' -MaxEvents 1000 -ErrorAction SilentlyContinue |
|
||||
Where-Object { $_.TimeCreated -gt $cutoff }
|
||||
$e75 = $evts | Where-Object { $_.Id -eq 75 } | Sort-Object TimeCreated -Descending | Select-Object -First 1
|
||||
$e76 = $evts | Where-Object { $_.Id -eq 76 } | Sort-Object TimeCreated -Descending | Select-Object -First 1
|
||||
if ($e75) { $r.MdmEnrollEvent75Found = $true; $r.MdmEnrollEvent75Time = $e75.TimeCreated.ToString('o') }
|
||||
if ($e76) { $r.MdmEnrollEvent76Found = $true; $r.MdmEnrollEvent76Time = $e76.TimeCreated.ToString('o') }
|
||||
$latest = $evts | Sort-Object TimeCreated -Descending | Select-Object -First 1
|
||||
if ($latest) { $r.LastSyncEventTime = $latest.TimeCreated.ToString('o') }
|
||||
} catch {}
|
||||
|
||||
# Layer 2 + 3: per-enrollment regs (only meaningful with an EnrollmentId)
|
||||
if ($r.EnrollmentId) {
|
||||
try {
|
||||
$omadm = "HKLM:\SOFTWARE\Microsoft\Provisioning\OMADM\Accounts\$($r.EnrollmentId)"
|
||||
if (Test-Path $omadm) {
|
||||
$v = (Get-ItemProperty -Path $omadm -Name HasProvisioningCompleted -ErrorAction SilentlyContinue).HasProvisioningCompleted
|
||||
if ($v -eq 1) { $r.HasProvisioningCompleted = $true }
|
||||
}
|
||||
} catch {}
|
||||
try {
|
||||
$fs = "HKLM:\SOFTWARE\Microsoft\Enrollments\$($r.EnrollmentId)\FirstSync"
|
||||
if (Test-Path $fs) {
|
||||
$v = (Get-ItemProperty -Path $fs -Name IsSyncDone -ErrorAction SilentlyContinue).IsSyncDone
|
||||
if ($v -eq 1) { $r.FirstSyncIsSyncDone = $true }
|
||||
}
|
||||
} catch {}
|
||||
try {
|
||||
$pp = "HKLM:\SOFTWARE\Microsoft\PolicyManager\Providers\$($r.EnrollmentId)\default\Device"
|
||||
if (Test-Path $pp) { $r.PolicyManagerProviderForEnrollment = $true }
|
||||
} catch {}
|
||||
}
|
||||
|
||||
# Layer 3: actual policy mirror under current\device
|
||||
try {
|
||||
$cur = Get-ChildItem 'HKLM:\SOFTWARE\Microsoft\PolicyManager\current\device' -ErrorAction SilentlyContinue
|
||||
$r.PolicyManagerCurrentDeviceSubkeys = if ($cur) { $cur.Count } else { 0 }
|
||||
} catch {}
|
||||
|
||||
# Layer 4: IME service + logs
|
||||
try {
|
||||
$svc = Get-Service -Name 'IntuneManagementExtension' -ErrorAction SilentlyContinue
|
||||
if ($svc -and $svc.Status -eq 'Running') { $r.ImeServiceRunning = $true }
|
||||
$imeLog = 'C:\ProgramData\Microsoft\IntuneManagementExtension\Logs'
|
||||
if ((Test-Path $imeLog) -and (Get-ChildItem $imeLog -ErrorAction SilentlyContinue | Select-Object -First 1)) {
|
||||
$r.ImeLogDirPopulated = $true
|
||||
}
|
||||
} catch {}
|
||||
|
||||
# Layer 4: Sidecar Policy Provider InstallationState (best-effort grep of IME log)
|
||||
try {
|
||||
$imeLogFile = 'C:\ProgramData\Microsoft\IntuneManagementExtension\Logs\IntuneManagementExtension.log'
|
||||
if (Test-Path $imeLogFile) {
|
||||
$hits = Select-String -Path $imeLogFile -Pattern 'Sidecar.*?[Ii]nstallation\s*[Ss]tate.*?(Completed|InProgress|NotStarted|Failed)' -ErrorAction SilentlyContinue |
|
||||
Select-Object -Last 1
|
||||
if ($hits -and $hits.Matches.Count -gt 0 -and $hits.Matches[0].Groups.Count -ge 2) {
|
||||
$r.SidecarInstallationState = $hits.Matches[0].Groups[1].Value
|
||||
}
|
||||
}
|
||||
} catch {}
|
||||
|
||||
# Verdict
|
||||
$r.SnapshotTime = (Get-Date).ToString('o')
|
||||
$r.ReadyForCategoryAssignment = (
|
||||
$r.AzureAdJoined -and
|
||||
$r.IntuneEnrolled -and
|
||||
$r.MdmEnrollEvent75Found -and
|
||||
(-not $r.MdmEnrollEvent76Found) -and
|
||||
$r.HasProvisioningCompleted -and
|
||||
$r.FirstSyncIsSyncDone -and
|
||||
$r.PolicyManagerProviderForEnrollment -and
|
||||
($r.PolicyManagerCurrentDeviceSubkeys -gt 0) -and
|
||||
$r.ImeServiceRunning -and
|
||||
$r.ImeLogDirPopulated
|
||||
)
|
||||
|
||||
[pscustomobject]$r | ConvertTo-Json -Depth 3 | Out-File "$out\intune-readiness.json"
|
||||
|
||||
# Human-readable summary (PS 5.1-safe: $(if ...) subexpressions, no inline-if-as-expression)
|
||||
@(
|
||||
"Intune category-readiness probe @ $($r.SnapshotTime) (stage=$Stage)"
|
||||
'------------------------------------------------------------------'
|
||||
' Layer 1 - AAD + MDM enrollment object'
|
||||
(" [{0}] AzureAdJoined tenant={1}" -f $(if ($r.AzureAdJoined) {'OK '} else {'FAIL'}), $r.AzureAdTenant)
|
||||
(" [{0}] IntuneEnrolled id={1}" -f $(if ($r.IntuneEnrolled) {'OK '} else {'FAIL'}), $r.EnrollmentId)
|
||||
' Layer 2 - Microsoft success markers'
|
||||
(" [{0}] Event 75 (Auto MDM Enroll: Succeeded) time={1}" -f $(if ($r.MdmEnrollEvent75Found) {'OK '} else {'FAIL'}), $r.MdmEnrollEvent75Time)
|
||||
(" [{0}] No event 76 in last 7d (no enroll failure) lastFail={1}" -f $(if ($r.MdmEnrollEvent76Found) {'FAIL'} else {'OK '}), $r.MdmEnrollEvent76Time)
|
||||
(" [{0}] OMADM HasProvisioningCompleted=1" -f $(if ($r.HasProvisioningCompleted) {'OK '} else {'FAIL'}))
|
||||
(" [{0}] Enrollments\<id>\FirstSync IsSyncDone=1" -f $(if ($r.FirstSyncIsSyncDone) {'OK '} else {'FAIL'}))
|
||||
' Layer 3 - policy actually delivered'
|
||||
(" [{0}] PolicyManager\Providers\<EnrollmentId>\default\Device exists" -f $(if ($r.PolicyManagerProviderForEnrollment) {'OK '} else {'FAIL'}))
|
||||
(" [{0}] PolicyManager\current\device subkey count={1}" -f $(if ($r.PolicyManagerCurrentDeviceSubkeys -gt 0) {'OK '} else {'FAIL'}), $r.PolicyManagerCurrentDeviceSubkeys)
|
||||
' Layer 4 - IME running (Win32App / PS1 channel)'
|
||||
(" [{0}] IME service running" -f $(if ($r.ImeServiceRunning) {'OK '} else {'FAIL'}))
|
||||
(" [{0}] IME log dir populated" -f $(if ($r.ImeLogDirPopulated) {'OK '} else {'FAIL'}))
|
||||
(" [--] Sidecar InstallationState (best-effort) value={0}" -f $(if ($r.SidecarInstallationState) { $r.SidecarInstallationState } else { '(unknown)' }))
|
||||
'------------------------------------------------------------------'
|
||||
("ReadyForCategoryAssignment: $($r.ReadyForCategoryAssignment)")
|
||||
("DeviceId: $($r.DeviceId)")
|
||||
("LastMDMEvent: $($r.LastSyncEventTime)")
|
||||
''
|
||||
'Notes:'
|
||||
' - All layers must be green before assigning device category in Intune.'
|
||||
' - Even when ready locally, allow >=15 min after adding the user/device'
|
||||
' to the target Entra group (server-side group eval delay, MS docs).'
|
||||
' - Pre-category snapshot with red Layer 2/3 = root cause for "imaging'
|
||||
' stalled and required re-image" (category raced the policy pull).'
|
||||
) | Out-File "$out\intune-readiness.txt"
|
||||
}
|
||||
|
||||
# --- SFLD credential manager YAML (identifies the Intune category)
|
||||
Step "snapshot SFLD CredentialManager dir" {
|
||||
$cmDir = 'C:\ProgramData\SFLD\CredentialManager'
|
||||
@@ -291,6 +474,6 @@ Write-Host ""
|
||||
Write-Host "Snapshot complete: $out"
|
||||
Write-Host ""
|
||||
Write-Host "Next: copy that folder to the workstation. Easiest:"
|
||||
Write-Host " net use Z: \\10.9.100.1\image-upload /user:pxe-upload pxe /persistent:no"
|
||||
Write-Host " net use Z: \\172.16.9.1\image-upload /user:pxe-upload pxe /persistent:no"
|
||||
Write-Host " robocopy `"$out`" `"Z:\state-$Stage-$stamp`" /E /NFL /NDL /NJH /NJS"
|
||||
Write-Host " net use Z: /delete /y"
|
||||
|
||||
142
scripts/diagnostics/Compare-LockdownStates.ps1
Normal file
@@ -0,0 +1,142 @@
|
||||
#Requires -RunAsAdministrator
|
||||
<#
|
||||
.SYNOPSIS
|
||||
Diff two snapshot dirs from Capture-LockdownState.ps1 to surface
|
||||
deltas (what arrived between the two checkpoints).
|
||||
|
||||
.DESCRIPTION
|
||||
Compares two state-* dirs (typically pre-category vs post-category,
|
||||
or post-category vs post-lockdown) along these axes:
|
||||
- intune-readiness.json (5 readiness signals, did they flip?)
|
||||
- dsregcmd.txt (AAD join state diff)
|
||||
- Reg dumps (.reg files): line-level diff
|
||||
- File inventories (*.csv): rows added/removed
|
||||
- Event log CSVs (DeviceManagement-Events, Tasks-RunHistory):
|
||||
new rows count
|
||||
|
||||
Output: human-readable summary to console + a delta-<stamp>.txt
|
||||
next to the second snapshot dir.
|
||||
|
||||
.PARAMETER Before
|
||||
Path to the earlier snapshot dir (e.g. state-pre-category-...)
|
||||
|
||||
.PARAMETER After
|
||||
Path to the later snapshot dir (e.g. state-post-category-...)
|
||||
|
||||
.EXAMPLE
|
||||
.\Compare-LockdownStates.ps1 -Before C:\ProgramData\state-pre-category-20260504-180000 -After C:\ProgramData\state-post-category-20260504-181500
|
||||
#>
|
||||
|
||||
[CmdletBinding()]
|
||||
param(
|
||||
[Parameter(Mandatory=$true)] [string]$Before,
|
||||
[Parameter(Mandatory=$true)] [string]$After
|
||||
)
|
||||
|
||||
$ErrorActionPreference = 'Continue'
|
||||
|
||||
if (-not (Test-Path $Before)) { throw "Before dir not found: $Before" }
|
||||
if (-not (Test-Path $After)) { throw "After dir not found: $After" }
|
||||
|
||||
$out = Join-Path $After ("delta-vs-" + (Split-Path $Before -Leaf) + ".txt")
|
||||
$lines = New-Object System.Collections.Generic.List[string]
|
||||
|
||||
function Add-Line { param([string]$s) $lines.Add($s); Write-Host $s }
|
||||
|
||||
Add-Line "=========================================================="
|
||||
Add-Line "Snapshot delta"
|
||||
Add-Line " Before: $Before"
|
||||
Add-Line " After: $After"
|
||||
Add-Line "=========================================================="
|
||||
Add-Line ""
|
||||
|
||||
# --- 1. Intune readiness signals delta ---
|
||||
Add-Line '--- Intune readiness signals (5-row gate) ---'
|
||||
$rb = $null; $ra = $null
|
||||
$rbPath = Join-Path $Before 'intune-readiness.json'
|
||||
$raPath = Join-Path $After 'intune-readiness.json'
|
||||
if ((Test-Path $rbPath) -and (Test-Path $raPath)) {
|
||||
$rb = Get-Content $rbPath -Raw | ConvertFrom-Json
|
||||
$ra = Get-Content $raPath -Raw | ConvertFrom-Json
|
||||
$signals = 'AzureAdJoined','IntuneEnrolled','MdmSyncRecent','ImeServiceRunning','ImeLogDirPopulated'
|
||||
foreach ($s in $signals) {
|
||||
$b = $rb.$s; $a = $ra.$s
|
||||
$tag = if ($b -eq $a) { ' same' } elseif ($a) { '+ flipped TRUE' } else { '- regressed FALSE' }
|
||||
Add-Line (" {0,-25} before={1,-5} after={2,-5} {3}" -f $s, $b, $a, $tag)
|
||||
}
|
||||
Add-Line (" {0,-25} before={1,-5} after={2,-5}" -f 'PolicyMgr providers', $rb.PolicyManagerProviders, $ra.PolicyManagerProviders)
|
||||
Add-Line (" ReadyForCategoryAssignment: before={0} after={1}" -f $rb.ReadyForCategoryAssignment, $ra.ReadyForCategoryAssignment)
|
||||
} else {
|
||||
Add-Line " (intune-readiness.json missing in one or both snapshots)"
|
||||
}
|
||||
Add-Line ''
|
||||
|
||||
# --- 2. dsregcmd diff (key boolean lines) ---
|
||||
Add-Line '--- dsregcmd state diff ---'
|
||||
$dsBefore = Get-Content (Join-Path $Before 'dsregcmd.txt') -ErrorAction SilentlyContinue
|
||||
$dsAfter = Get-Content (Join-Path $After 'dsregcmd.txt') -ErrorAction SilentlyContinue
|
||||
foreach ($key in 'AzureAdJoined','EnterpriseJoined','DomainJoined','TenantId','TenantName','MdmUrl','MdmTouUrl','MdmComplianceUrl','SettingsUrl') {
|
||||
$b = ($dsBefore | Select-String -Pattern "^\s*$key\s*:" -SimpleMatch).Line | Select-Object -First 1
|
||||
$a = ($dsAfter | Select-String -Pattern "^\s*$key\s*:" -SimpleMatch).Line | Select-Object -First 1
|
||||
if ($b -ne $a) {
|
||||
Add-Line " CHANGED $key"
|
||||
Add-Line " before: $(if ($b) { $b } else { '(missing)' })"
|
||||
Add-Line " after : $(if ($a) { $a } else { '(missing)' })"
|
||||
}
|
||||
}
|
||||
Add-Line ''
|
||||
|
||||
# --- 3. Registry .reg files - line-level diff (count lines added/removed) ---
|
||||
Add-Line '--- registry dump deltas (line counts) ---'
|
||||
$regsBefore = Get-ChildItem $Before -Filter '*.reg' -ErrorAction SilentlyContinue
|
||||
foreach ($rb in $regsBefore) {
|
||||
$rbName = $rb.Name
|
||||
$raPath = Join-Path $After $rbName
|
||||
if (-not (Test-Path $raPath)) { continue }
|
||||
$bLines = Get-Content $rb.FullName -ErrorAction SilentlyContinue
|
||||
$aLines = Get-Content $raPath -ErrorAction SilentlyContinue
|
||||
$added = (Compare-Object -ReferenceObject $bLines -DifferenceObject $aLines | Where-Object SideIndicator -eq '=>').Count
|
||||
$removed = (Compare-Object -ReferenceObject $bLines -DifferenceObject $aLines | Where-Object SideIndicator -eq '<=').Count
|
||||
if ($added -or $removed) {
|
||||
Add-Line (" {0,-30} +{1,-4} -{2}" -f $rbName, $added, $removed)
|
||||
}
|
||||
}
|
||||
Add-Line ''
|
||||
|
||||
# --- 4. CSV inventories - row count delta ---
|
||||
Add-Line '--- file inventory deltas (CSV row counts) ---'
|
||||
$csvsBefore = Get-ChildItem $Before -Filter '*.csv' -ErrorAction SilentlyContinue
|
||||
foreach ($cb in $csvsBefore) {
|
||||
$cbName = $cb.Name
|
||||
$caPath = Join-Path $After $cbName
|
||||
if (-not (Test-Path $caPath)) { continue }
|
||||
try {
|
||||
$bRows = (Import-Csv $cb.FullName).Count
|
||||
$aRows = (Import-Csv $caPath).Count
|
||||
if ($bRows -ne $aRows) {
|
||||
Add-Line (" {0,-35} before={1,-5} after={2,-5} delta={3:+#;-#;0}" -f $cbName, $bRows, $aRows, ($aRows - $bRows))
|
||||
}
|
||||
} catch {}
|
||||
}
|
||||
Add-Line ''
|
||||
|
||||
# --- 5. Newly-present + newly-absent files in the snapshot ---
|
||||
Add-Line '--- snapshot directory contents delta ---'
|
||||
$bf = Get-ChildItem $Before -File -Recurse | ForEach-Object { $_.FullName.Substring($Before.Length) }
|
||||
$af = Get-ChildItem $After -File -Recurse | ForEach-Object { $_.FullName.Substring($After.Length) }
|
||||
$onlyA = Compare-Object -ReferenceObject $bf -DifferenceObject $af -PassThru | Where-Object { $af -contains $_ -and $bf -notcontains $_ }
|
||||
$onlyB = Compare-Object -ReferenceObject $bf -DifferenceObject $af -PassThru | Where-Object { $bf -contains $_ -and $af -notcontains $_ }
|
||||
if ($onlyA) {
|
||||
Add-Line " NEW in After:"
|
||||
$onlyA | ForEach-Object { Add-Line " + $_" }
|
||||
}
|
||||
if ($onlyB) {
|
||||
Add-Line " REMOVED in After:"
|
||||
$onlyB | ForEach-Object { Add-Line " - $_" }
|
||||
}
|
||||
Add-Line ''
|
||||
|
||||
# Persist
|
||||
$lines | Out-File $out -Encoding utf8
|
||||
Write-Host ""
|
||||
Write-Host "Delta written to: $out" -ForegroundColor Cyan
|
||||
@@ -13,7 +13,7 @@ enrollment, and is enrolled to Intune but no device category assigned yet.
|
||||
0. Map share + stage script (run once, at the start)
|
||||
----------------------------------------
|
||||
|
||||
net use Z: \\10.9.100.1\image-upload /user:pxe-upload pxe /persistent:no
|
||||
net use Z: \\172.16.9.1\image-upload /user:pxe-upload pxe /persistent:no
|
||||
Copy-Item Z:\Capture-LockdownState.ps1 C:\Windows\Temp\
|
||||
Set-ExecutionPolicy -Scope Process Bypass -Force
|
||||
|
||||
@@ -83,7 +83,7 @@ Output: C:\ProgramData\state-post-lockdown-<stamp>\
|
||||
}
|
||||
net use Z: /delete /y
|
||||
|
||||
The three folders land at \\10.9.100.1\image-upload\state-*-<stamp>\.
|
||||
The three folders land at \\172.16.9.1\image-upload\state-*-<stamp>\.
|
||||
On the workstation: pull from /home/pxe/image-upload/ on the PXE server
|
||||
(scp or local mount) and diff against any prior baseline (e.g. the
|
||||
4/15 v1.3.1 working snapshot at pxe-images/state-post-lockdown-20260415-154705/).
|
||||
|
||||
@@ -31,7 +31,7 @@ import xml.etree.ElementTree as ET
|
||||
from pathlib import Path
|
||||
|
||||
REPO_DIR = Path(__file__).resolve().parent
|
||||
PXE_HOST = "10.9.100.1"
|
||||
PXE_HOST = "172.16.9.1"
|
||||
PXE_USER = "pxe"
|
||||
PXE_PASS = "pxe"
|
||||
UPLOAD_DEST = "/home/pxe/image-upload"
|
||||
@@ -715,7 +715,7 @@ def main():
|
||||
concurrent.futures.wait(futures)
|
||||
|
||||
# --- Download BIOS (goes to shared winpeapps dir, read by check-bios.cmd
|
||||
# in WinPE phase via \\10.9.100.1\winpeapps\_shared\BIOS\). Playbook
|
||||
# in WinPE phase via \\172.16.9.1\winpeapps\_shared\BIOS\). Playbook
|
||||
# task at pxe_server_setup.yml:485 deploys check-bios.cmd + Flash64W.exe
|
||||
# to this same directory. ---
|
||||
bios_ok = bios_err = 0
|
||||
|
||||
@@ -137,7 +137,7 @@ data = data.replace(
|
||||
)
|
||||
data = data.replace(
|
||||
b'<hostname></hostname>',
|
||||
b'<hostname>10.9.100.1</hostname>'
|
||||
b'<hostname>172.16.9.1</hostname>'
|
||||
)
|
||||
data = data.replace(
|
||||
b'<path></path>',
|
||||
@@ -190,7 +190,7 @@ PYEOF
|
||||
# Repack CPIO with exact 512-byte block alignment (194560 bytes)
|
||||
ls -1 "$CFGTMP" | (cd "$CFGTMP" && cpio -o -H newc 2>/dev/null) | \
|
||||
dd bs=512 conv=sync 2>/dev/null > "$OUT_DIR/blancco/config.img"
|
||||
echo " Reports: SMB blancco@10.9.100.1/blancco-reports, bootable report enabled"
|
||||
echo " Reports: SMB blancco@172.16.9.1/blancco-reports, bootable report enabled"
|
||||
fi
|
||||
cd "$REPO_ROOT"
|
||||
rm -rf "$CFGTMP"
|
||||
|
||||
@@ -6,7 +6,7 @@ set -e
|
||||
|
||||
REPO_ROOT="$(cd "$(dirname "$0")"/.. && pwd)"
|
||||
DEST="$REPO_ROOT/bios-staging"
|
||||
PXE_SERVER="10.9.100.1"
|
||||
PXE_SERVER="172.16.9.1"
|
||||
PXE_USER="pxe"
|
||||
PXE_PASS="pxe"
|
||||
|
||||
|
||||
@@ -6,7 +6,7 @@ powercfg /s 8c5e7fda-e8bf-4a96-9a85-a6e23a8c635c
|
||||
REM --- Wait for network (DHCP may take a moment after wpeinit) ---
|
||||
echo Waiting for network...
|
||||
:wait_net
|
||||
ping -n 2 10.9.100.1 >NUL 2>&1
|
||||
ping -n 2 172.16.9.1 >NUL 2>&1
|
||||
if errorlevel 1 goto wait_net
|
||||
echo Network ready.
|
||||
|
||||
@@ -17,7 +17,7 @@ REM CALLed scripts inside parens does not propagate BIOS_STATUS back to
|
||||
REM this script reliably. Use goto-flow instead so the CALL runs at the
|
||||
REM top scope and BIOS_STATUS persists.
|
||||
set BIOS_STATUS=No BIOS check (share unavailable)
|
||||
net use B: \\10.9.100.1\winpeapps_bios /user:pxe-upload pxe /persistent:no 2>NUL
|
||||
net use B: \\172.16.9.1\winpeapps_bios /user:pxe-upload pxe /persistent:no 2>NUL
|
||||
if not exist B:\check-bios.cmd goto :bios_check_done
|
||||
echo.
|
||||
echo Checking for BIOS updates...
|
||||
@@ -174,7 +174,7 @@ set NEED_ENROLL=0
|
||||
if not "%PPKG%"=="" set NEED_ENROLL=1
|
||||
if not "%PCTYPE%"=="" set NEED_ENROLL=1
|
||||
if "%NEED_ENROLL%"=="0" goto enroll_staged
|
||||
net use Y: \\10.9.100.1\enrollment /user:pxe-upload pxe /persistent:no
|
||||
net use Y: \\172.16.9.1\enrollment /user:pxe-upload pxe /persistent:no
|
||||
if "%PPKG%"=="" goto enroll_staged
|
||||
if not exist "Y:\ppkgs\%SOURCE_PPKG%" (
|
||||
echo WARNING: %SOURCE_PPKG% not found on server. Enrollment will be skipped.
|
||||
@@ -199,7 +199,7 @@ echo.
|
||||
echo Starting GEA Standard setup...
|
||||
start "FlatApp" %SYSTEMDRIVE%\GESetup\FlatSetupLoader.exe
|
||||
for /l %%i in (1,1,2000000) do rem
|
||||
net use Z: \\10.9.100.1\winpeapps\gea-standard /user:pxe-upload pxe /persistent:no
|
||||
net use Z: \\172.16.9.1\winpeapps\gea-standard /user:pxe-upload pxe /persistent:no
|
||||
goto end
|
||||
|
||||
:gea-engineer
|
||||
@@ -207,7 +207,7 @@ echo.
|
||||
echo Starting GEA Engineer setup...
|
||||
start "FlatApp" %SYSTEMDRIVE%\GESetup\FlatSetupLoader.exe
|
||||
for /l %%i in (1,1,2000000) do rem
|
||||
net use Z: \\10.9.100.1\winpeapps\gea-engineer /user:pxe-upload pxe /persistent:no
|
||||
net use Z: \\172.16.9.1\winpeapps\gea-engineer /user:pxe-upload pxe /persistent:no
|
||||
goto end
|
||||
|
||||
:gea-shopfloor
|
||||
@@ -215,7 +215,7 @@ echo.
|
||||
echo Starting GEA Shopfloor setup...
|
||||
start "FlatApp" %SYSTEMDRIVE%\GESetup\FlatSetupLoader.exe
|
||||
for /l %%i in (1,1,2000000) do rem
|
||||
net use Z: \\10.9.100.1\winpeapps\gea-shopfloor /user:pxe-upload pxe /persistent:no
|
||||
net use Z: \\172.16.9.1\winpeapps\gea-shopfloor /user:pxe-upload pxe /persistent:no
|
||||
goto end
|
||||
|
||||
:ge-standard
|
||||
@@ -223,7 +223,7 @@ echo.
|
||||
echo Starting GE Standard setup...
|
||||
start "FlatApp" %SYSTEMDRIVE%\GESetup\FlatSetupLoader.exe
|
||||
for /l %%i in (1,1,2000000) do rem
|
||||
net use Z: \\10.9.100.1\winpeapps\ge-standard /user:pxe-upload pxe /persistent:no
|
||||
net use Z: \\172.16.9.1\winpeapps\ge-standard /user:pxe-upload pxe /persistent:no
|
||||
goto end
|
||||
|
||||
:ge-engineer
|
||||
@@ -231,7 +231,7 @@ echo.
|
||||
echo Starting GE Engineer setup...
|
||||
start "FlatApp" %SYSTEMDRIVE%\GESetup\FlatSetupLoader.exe
|
||||
for /l %%i in (1,1,2000000) do rem
|
||||
net use Z: \\10.9.100.1\winpeapps\ge-engineer /user:pxe-upload pxe /persistent:no
|
||||
net use Z: \\172.16.9.1\winpeapps\ge-engineer /user:pxe-upload pxe /persistent:no
|
||||
goto end
|
||||
|
||||
:ge-shopfloor-lockdown
|
||||
@@ -239,7 +239,7 @@ echo.
|
||||
echo Starting GE Shopfloor Lockdown setup...
|
||||
start "FlatApp" %SYSTEMDRIVE%\GESetup\FlatSetupLoader.exe
|
||||
for /l %%i in (1,1,2000000) do rem
|
||||
net use Z: \\10.9.100.1\winpeapps\ge-shopfloor-lockdown /user:pxe-upload pxe /persistent:no
|
||||
net use Z: \\172.16.9.1\winpeapps\ge-shopfloor-lockdown /user:pxe-upload pxe /persistent:no
|
||||
goto end
|
||||
|
||||
:ge-shopfloor-mce
|
||||
@@ -247,7 +247,7 @@ echo.
|
||||
echo Starting GE Shopfloor MCE setup...
|
||||
start "FlatApp" %SYSTEMDRIVE%\GESetup\FlatSetupLoader.exe
|
||||
for /l %%i in (1,1,2000000) do rem
|
||||
net use Z: \\10.9.100.1\winpeapps\ge-shopfloor-mce /user:pxe-upload pxe /persistent:no
|
||||
net use Z: \\172.16.9.1\winpeapps\ge-shopfloor-mce /user:pxe-upload pxe /persistent:no
|
||||
goto end
|
||||
|
||||
:end
|
||||
|
||||
42
webapp/static/qr-render.js
Normal file
@@ -0,0 +1,42 @@
|
||||
// QR render helper. Scans for any element with data-qr="<text>" and renders
|
||||
// a Kazuhiko Arase qrcode-generator QR into it as inline <img>. Size is
|
||||
// controlled via data-qr-size="N" (px square, default 96). Error-correction
|
||||
// level via data-qr-ec="L|M|Q|H" (default M).
|
||||
//
|
||||
// The qrcode-generator lib (loaded before this script) exposes a global
|
||||
// `qrcode()` factory: typeNumber 0 = auto, ec = 'L'|'M'|'Q'|'H'.
|
||||
(function () {
|
||||
function render(el) {
|
||||
var text = el.getAttribute('data-qr') || '';
|
||||
if (!text) return;
|
||||
if (el.dataset.qrRendered === '1') return;
|
||||
var size = parseInt(el.getAttribute('data-qr-size') || '96', 10);
|
||||
var ec = el.getAttribute('data-qr-ec') || 'M';
|
||||
try {
|
||||
var qr = qrcode(0, ec);
|
||||
qr.addData(text);
|
||||
qr.make();
|
||||
// createImgTag(cellSize, margin)
|
||||
// 4-cell margin keeps the QR scannable per spec; cell size derived from
|
||||
// requested pixel size and module count.
|
||||
var modules = qr.getModuleCount();
|
||||
var cellSize = Math.max(1, Math.floor(size / (modules + 8)));
|
||||
el.innerHTML = qr.createImgTag(cellSize, 4);
|
||||
el.dataset.qrRendered = '1';
|
||||
el.title = 'Scan: ' + text;
|
||||
} catch (e) {
|
||||
el.textContent = '[QR error]';
|
||||
}
|
||||
}
|
||||
|
||||
function scan() {
|
||||
var nodes = document.querySelectorAll('[data-qr]');
|
||||
for (var i = 0; i < nodes.length; i++) render(nodes[i]);
|
||||
}
|
||||
|
||||
if (document.readyState === 'loading') {
|
||||
document.addEventListener('DOMContentLoaded', scan);
|
||||
} else {
|
||||
scan();
|
||||
}
|
||||
})();
|
||||
8
webapp/static/qrcode.min.js
vendored
Normal file
@@ -221,6 +221,8 @@
|
||||
|
||||
<script src="{{ url_for('static', filename='bootstrap.bundle.min.js') }}"></script>
|
||||
<script src="{{ url_for('static', filename='app.js') }}"></script>
|
||||
<script src="{{ url_for('static', filename='qrcode.min.js') }}"></script>
|
||||
<script src="{{ url_for('static', filename='qr-render.js') }}"></script>
|
||||
{% block extra_scripts %}{% endblock %}
|
||||
</body>
|
||||
</html>
|
||||
|
||||
@@ -116,7 +116,7 @@
|
||||
<div class="card mt-3">
|
||||
<div class="card-body small text-muted">
|
||||
<strong>How to push status from an imaging client:</strong>
|
||||
<pre class="mb-0 mt-2">POST http://10.9.100.1:9009/imaging/status
|
||||
<pre class="mb-0 mt-2">POST http://172.16.9.1:9009/imaging/status
|
||||
Content-Type: application/json
|
||||
|
||||
{
|
||||
|
||||
@@ -25,7 +25,7 @@
|
||||
{% endfor %}
|
||||
</select>
|
||||
<div class="form-text">
|
||||
Files uploaded via SMB to <code>\\10.9.100.1\image-upload</code>
|
||||
Files uploaded via SMB to <code>\\172.16.9.1\image-upload</code>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -66,7 +66,7 @@
|
||||
<div class="text-center py-4">
|
||||
<h5 class="mt-3 text-muted">No Upload Content Found</h5>
|
||||
<p class="text-muted mb-0">
|
||||
Map <code>\\10.9.100.1\image-upload</code> on your Windows PC and copy
|
||||
Map <code>\\172.16.9.1\image-upload</code> on your Windows PC and copy
|
||||
the Deploy directory contents there.
|
||||
</p>
|
||||
<button class="btn btn-outline-secondary btn-sm mt-3" onclick="location.reload()">
|
||||
|
||||
@@ -70,7 +70,7 @@
|
||||
<h6 class="card-title">Report Storage</h6>
|
||||
<p class="card-text mb-1">
|
||||
Blancco Drive Eraser saves erasure certificates to the network share
|
||||
<code>\\10.9.100.1\blancco-reports</code>.
|
||||
<code>\\172.16.9.1\blancco-reports</code>.
|
||||
</p>
|
||||
<p class="card-text mb-0 text-muted">
|
||||
Reports are generated automatically after each drive wipe and contain proof of erasure for compliance and audit purposes.
|
||||
|
||||
@@ -75,7 +75,7 @@
|
||||
<div class="col-md-6">
|
||||
<code class="d-block mb-1">wpeinit</code>
|
||||
<small class="text-muted d-block mb-2">Initialize WinPE networking</small>
|
||||
<code class="d-block mb-1">net use Z: \\10.9.100.1\winpeapps</code>
|
||||
<code class="d-block mb-1">net use Z: \\172.16.9.1\winpeapps</code>
|
||||
<small class="text-muted d-block mb-2">Map Samba share for deployment</small>
|
||||
</div>
|
||||
<div class="col-md-6">
|
||||
|
||||