diff --git a/Binary/Binary.NewBinary1 b/Binary/Binary.NewBinary1 new file mode 100644 index 0000000..71f4845 Binary files /dev/null and b/Binary/Binary.NewBinary1 differ diff --git a/Binary/Binary.NewBinary10 b/Binary/Binary.NewBinary10 new file mode 100644 index 0000000..e9302c9 Binary files /dev/null and b/Binary/Binary.NewBinary10 differ diff --git a/Binary/Binary.NewBinary11 b/Binary/Binary.NewBinary11 new file mode 100644 index 0000000..8463c10 Binary files /dev/null and b/Binary/Binary.NewBinary11 differ diff --git a/Binary/Binary.NewBinary12 b/Binary/Binary.NewBinary12 new file mode 100644 index 0000000..9aaa757 Binary files /dev/null and b/Binary/Binary.NewBinary12 differ diff --git a/Binary/Binary.NewBinary13 b/Binary/Binary.NewBinary13 new file mode 100644 index 0000000..cfc6087 Binary files /dev/null and b/Binary/Binary.NewBinary13 differ diff --git a/Binary/Binary.NewBinary14 b/Binary/Binary.NewBinary14 new file mode 100644 index 0000000..e7136d0 Binary files /dev/null and b/Binary/Binary.NewBinary14 differ diff --git a/Binary/Binary.NewBinary15 b/Binary/Binary.NewBinary15 new file mode 100644 index 0000000..2eb32be Binary files /dev/null and b/Binary/Binary.NewBinary15 differ diff --git a/Binary/Binary.NewBinary16 b/Binary/Binary.NewBinary16 new file mode 100644 index 0000000..b9d1927 Binary files /dev/null and b/Binary/Binary.NewBinary16 differ diff --git a/Binary/Binary.NewBinary17 b/Binary/Binary.NewBinary17 new file mode 100644 index 0000000..bd57679 Binary files /dev/null and b/Binary/Binary.NewBinary17 differ diff --git a/Binary/Binary.NewBinary18 b/Binary/Binary.NewBinary18 new file mode 100644 index 0000000..e864493 Binary files /dev/null and b/Binary/Binary.NewBinary18 differ diff --git a/Binary/Binary.NewBinary19 b/Binary/Binary.NewBinary19 new file mode 100644 index 0000000..e8d3984 --- /dev/null +++ b/Binary/Binary.NewBinary19 @@ -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 \ No newline at end of file diff --git a/Binary/Binary.NewBinary2 b/Binary/Binary.NewBinary2 new file mode 100644 index 0000000..27881df Binary files /dev/null and b/Binary/Binary.NewBinary2 differ diff --git a/Binary/Binary.NewBinary20 b/Binary/Binary.NewBinary20 new file mode 100644 index 0000000..c4c048b --- /dev/null +++ b/Binary/Binary.NewBinary20 @@ -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 \ No newline at end of file diff --git a/Binary/Binary.NewBinary21 b/Binary/Binary.NewBinary21 new file mode 100644 index 0000000..ce06ae8 --- /dev/null +++ b/Binary/Binary.NewBinary21 @@ -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 \ No newline at end of file diff --git a/Binary/Binary.NewBinary3 b/Binary/Binary.NewBinary3 new file mode 100644 index 0000000..86f6b5a Binary files /dev/null and b/Binary/Binary.NewBinary3 differ diff --git a/Binary/Binary.NewBinary4 b/Binary/Binary.NewBinary4 new file mode 100644 index 0000000..ac96181 Binary files /dev/null and b/Binary/Binary.NewBinary4 differ diff --git a/Binary/Binary.NewBinary5 b/Binary/Binary.NewBinary5 new file mode 100644 index 0000000..43bff8b Binary files /dev/null and b/Binary/Binary.NewBinary5 differ diff --git a/Binary/Binary.NewBinary6 b/Binary/Binary.NewBinary6 new file mode 100644 index 0000000..8463c10 Binary files /dev/null and b/Binary/Binary.NewBinary6 differ diff --git a/Binary/Binary.NewBinary7 b/Binary/Binary.NewBinary7 new file mode 100644 index 0000000..a567bc2 Binary files /dev/null and b/Binary/Binary.NewBinary7 differ diff --git a/Binary/Binary.NewBinary8 b/Binary/Binary.NewBinary8 new file mode 100644 index 0000000..557788c Binary files /dev/null and b/Binary/Binary.NewBinary8 differ diff --git a/Binary/Binary.NewBinary9 b/Binary/Binary.NewBinary9 new file mode 100644 index 0000000..8027940 Binary files /dev/null and b/Binary/Binary.NewBinary9 differ diff --git a/Binary/Binary.SetAllUsers.dll b/Binary/Binary.SetAllUsers.dll new file mode 100644 index 0000000..d9593d4 Binary files /dev/null and b/Binary/Binary.SetAllUsers.dll differ diff --git a/Icon/Icon.ARPPRODUCTICON.exe b/Icon/Icon.ARPPRODUCTICON.exe new file mode 100644 index 0000000..7776e43 Binary files /dev/null and b/Icon/Icon.ARPPRODUCTICON.exe differ diff --git a/Icon/Icon.NewShortcut1_AB8E7834205C40DE9AD7D94845255E55.exe b/Icon/Icon.NewShortcut1_AB8E7834205C40DE9AD7D94845255E55.exe new file mode 100644 index 0000000..7776e43 Binary files /dev/null and b/Icon/Icon.NewShortcut1_AB8E7834205C40DE9AD7D94845255E55.exe differ diff --git a/Icon/Icon.NewShortcut2_1E955C7F522448028AA8419A487CA996.exe b/Icon/Icon.NewShortcut2_1E955C7F522448028AA8419A487CA996.exe new file mode 100644 index 0000000..7776e43 Binary files /dev/null and b/Icon/Icon.NewShortcut2_1E955C7F522448028AA8419A487CA996.exe differ diff --git a/Icon/Icon._052C53DD_2BAF_4769_A1A0_1519CA2B23FB b/Icon/Icon._052C53DD_2BAF_4769_A1A0_1519CA2B23FB new file mode 100644 index 0000000..e836814 Binary files /dev/null and b/Icon/Icon._052C53DD_2BAF_4769_A1A0_1519CA2B23FB differ diff --git a/Icon/Icon._173060F8_E06D_4B06_B289_4656D92A595E b/Icon/Icon._173060F8_E06D_4B06_B289_4656D92A595E new file mode 100644 index 0000000..d559422 Binary files /dev/null and b/Icon/Icon._173060F8_E06D_4B06_B289_4656D92A595E differ diff --git a/Icon/Icon._3336CEAD_1861_4B26_A1C1_2D2F75C36A27 b/Icon/Icon._3336CEAD_1861_4B26_A1C1_2D2F75C36A27 new file mode 100644 index 0000000..05fff68 Binary files /dev/null and b/Icon/Icon._3336CEAD_1861_4B26_A1C1_2D2F75C36A27 differ diff --git a/Icon/Icon._59497049_1008_4427_84DF_744B04B0F075 b/Icon/Icon._59497049_1008_4427_84DF_744B04B0F075 new file mode 100644 index 0000000..743ecc3 Binary files /dev/null and b/Icon/Icon._59497049_1008_4427_84DF_744B04B0F075 differ diff --git a/Icon/Icon._5EF3CFE6_6B6A_49D5_A54E_95222360D405 b/Icon/Icon._5EF3CFE6_6B6A_49D5_A54E_95222360D405 new file mode 100644 index 0000000..4ac91eb Binary files /dev/null and b/Icon/Icon._5EF3CFE6_6B6A_49D5_A54E_95222360D405 differ diff --git a/Icon/Icon._823D3F96_4702_483C_BE0E_6CF23CAA78AD b/Icon/Icon._823D3F96_4702_483C_BE0E_6CF23CAA78AD new file mode 100644 index 0000000..b31dd29 Binary files /dev/null and b/Icon/Icon._823D3F96_4702_483C_BE0E_6CF23CAA78AD differ diff --git a/Icon/Icon._90919B36_D3D7_437D_B050_7D5620C88056 b/Icon/Icon._90919B36_D3D7_437D_B050_7D5620C88056 new file mode 100644 index 0000000..f615a85 Binary files /dev/null and b/Icon/Icon._90919B36_D3D7_437D_B050_7D5620C88056 differ diff --git a/Icon/Icon._E7806B4E_27A4_4270_8F13_3E9E01192773 b/Icon/Icon._E7806B4E_27A4_4270_8F13_3E9E01192773 new file mode 100644 index 0000000..c959f48 Binary files /dev/null and b/Icon/Icon._E7806B4E_27A4_4270_8F13_3E9E01192773 differ diff --git a/README.md b/README.md index 04628e7..6c66479 100644 --- a/README.md +++ b/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 diff --git a/SETUP.md b/SETUP.md index edcaab9..16f5d72 100644 --- a/SETUP.md +++ b/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 diff --git a/autoinstall/user-data b/autoinstall/user-data index f8ad1ac..e45de6e 100644 --- a/autoinstall/user-data +++ b/autoinstall/user-data @@ -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 diff --git a/docs/ARCHITECTURE.md b/docs/ARCHITECTURE.md index 7e5da8f..acb1ff1 100644 --- a/docs/ARCHITECTURE.md +++ b/docs/ARCHITECTURE.md @@ -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) | diff --git a/docs/SITE-CUSTOMIZATION.md b/docs/SITE-CUSTOMIZATION.md index b795564..bec4a33 100644 --- a/docs/SITE-CUSTOMIZATION.md +++ b/docs/SITE-CUSTOMIZATION.md @@ -22,9 +22,9 @@ contribute a `config/sites/.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/.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: diff --git a/docs/ge-enforce-v2-architecture.md b/docs/ge-enforce-v2-architecture.md index 62d659c..f205a05 100644 --- a/docs/ge-enforce-v2-architecture.md +++ b/docs/ge-enforce-v2-architecture.md @@ -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 `\\` | 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 diff --git a/docs/geastandardpbr-overrides.md b/docs/geastandardpbr-overrides.md index 56e16f4..1e95f47 100644 --- a/docs/geastandardpbr-overrides.md +++ b/docs/geastandardpbr-overrides.md @@ -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. diff --git a/docs/shopfloor-machine-imaging-guide.md b/docs/shopfloor-machine-imaging-guide.md index 3b04d0e..cb90e6c 100644 --- a/docs/shopfloor-machine-imaging-guide.md +++ b/docs/shopfloor-machine-imaging-guide.md @@ -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` diff --git a/playbook/FlatUnattendW10-shopfloor.xml b/playbook/FlatUnattendW10-shopfloor.xml index c387037..52011fa 100644 --- a/playbook/FlatUnattendW10-shopfloor.xml +++ b/playbook/FlatUnattendW10-shopfloor.xml @@ -166,11 +166,16 @@ 6 + 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 + Install PowerShell 7 BEFORE PPKG so Intune SetupCredentials Win32App finds pwsh.exe (race fix) + + + 7 powershell.exe -ExecutionPolicy Bypass -File "C:\run-enrollment.ps1" Run GCCH Enrollment - 7 + 8 powershell.exe -ExecutionPolicy Bypass -File "C:\Enrollment\Run-ShopfloorSetup.ps1" Run shopfloor PC type setup diff --git a/playbook/blancco-init.sh b/playbook/blancco-init.sh index 55f2791..90432e8 100644 --- a/playbook/blancco-init.sh +++ b/playbook/blancco-init.sh @@ -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)..." diff --git a/playbook/blancco-preferences.xml b/playbook/blancco-preferences.xml index a6fb778..ca8991c 100644 --- a/playbook/blancco-preferences.xml +++ b/playbook/blancco-preferences.xml @@ -176,7 +176,7 @@ blancco blancco - 10.9.100.1 + 172.16.9.1 blancco-reports smb diff --git a/playbook/migrate-to-wifi.ps1 b/playbook/migrate-to-wifi.ps1 index babf163..9a3ddec 100644 --- a/playbook/migrate-to-wifi.ps1 +++ b/playbook/migrate-to-wifi.ps1 @@ -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 diff --git a/playbook/preinstall/installers/powershell7/PowerShell-7.5.4-win-x64.msi b/playbook/preinstall/installers/powershell7/PowerShell-7.5.4-win-x64.msi new file mode 100644 index 0000000..5bce297 Binary files /dev/null and b/playbook/preinstall/installers/powershell7/PowerShell-7.5.4-win-x64.msi differ diff --git a/playbook/preinstall/preinstall.json b/playbook/preinstall/preinstall.json index 3545423..d7fc0c1 100644 --- a/playbook/preinstall/preinstall.json +++ b/playbook/preinstall/preinstall.json @@ -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.", diff --git a/playbook/pxe-server-helpers/pxe-dhcp-hook.sh b/playbook/pxe-server-helpers/pxe-dhcp-hook.sh index 5162266..df454db 100755 --- a/playbook/pxe-server-helpers/pxe-dhcp-hook.sh +++ b/playbook/pxe-server-helpers/pxe-dhcp-hook.sh @@ -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. diff --git a/playbook/pxe-server-helpers/smb-soft-reset.sh b/playbook/pxe-server-helpers/smb-soft-reset.sh index bc3b9d7..388956e 100755 --- a/playbook/pxe-server-helpers/smb-soft-reset.sh +++ b/playbook/pxe-server-helpers/smb-soft-reset.sh @@ -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 diff --git a/playbook/pxe_server_setup.yml b/playbook/pxe_server_setup.yml index 80ad051..ccc9782 100644 --- a/playbook/pxe_server_setup.yml +++ b/playbook/pxe_server_setup.yml @@ -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 '10.9.100.1' "{{ web_root }}/blancco/preferences.xml" + grep -q '172.16.9.1' "{{ web_root }}/blancco/preferences.xml" grep -q 'blancco-reports' "{{ 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: diff --git a/playbook/shopfloor-setup/Run-ShopfloorSetup.ps1 b/playbook/shopfloor-setup/Run-ShopfloorSetup.ps1 index 461b85b..2c8072b 100644 --- a/playbook/shopfloor-setup/Run-ShopfloorSetup.ps1 +++ b/playbook/shopfloor-setup/Run-ShopfloorSetup.ps1 @@ -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) { diff --git a/playbook/shopfloor-setup/Shopfloor/00-PreInstall-MachineApps.ps1 b/playbook/shopfloor-setup/Shopfloor/00-PreInstall-MachineApps.ps1 index 079c85c..e3954e8 100644 --- a/playbook/shopfloor-setup/Shopfloor/00-PreInstall-MachineApps.ps1 +++ b/playbook/shopfloor-setup/Shopfloor/00-PreInstall-MachineApps.ps1 @@ -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,15 +330,27 @@ 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) { - foreach ($t in $allowedTypes) { - if ($myNames.Contains($t)) { $matchesType = $true; break } - foreach ($g in $aliasGroups) { - if ($g -icontains $t) { - foreach ($x in $g) { if ($myNames.Contains($x)) { $matchesType = $true; break } } + 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) { + if ($g -icontains $t) { + foreach ($x in $g) { if ($myNames.Contains($x)) { $matchesType = $true; break } } + } + if ($matchesType) { break } } - if ($matchesType) { break } } } } diff --git a/playbook/shopfloor-setup/Shopfloor/lib/Disable-WiredNics.ps1 b/playbook/shopfloor-setup/Shopfloor/lib/Disable-WiredNics.ps1 index 78d1ddc..0e922b8 100644 --- a/playbook/shopfloor-setup/Shopfloor/lib/Disable-WiredNics.ps1 +++ b/playbook/shopfloor-setup/Shopfloor/lib/Disable-WiredNics.ps1 @@ -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 diff --git a/playbook/shopfloor-setup/Shopfloor/lib/Get-PCProfile.ps1 b/playbook/shopfloor-setup/Shopfloor/lib/Get-PCProfile.ps1 index ac9f991..09d54a6 100644 --- a/playbook/shopfloor-setup/Shopfloor/lib/Get-PCProfile.ps1 +++ b/playbook/shopfloor-setup/Shopfloor/lib/Get-PCProfile.ps1 @@ -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') ) diff --git a/playbook/shopfloor-setup/Shopfloor/lib/Send-PxeStatus.ps1 b/playbook/shopfloor-setup/Shopfloor/lib/Send-PxeStatus.ps1 index 461ef6f..fb95072 100644 --- a/playbook/shopfloor-setup/Shopfloor/lib/Send-PxeStatus.ps1 +++ b/playbook/shopfloor-setup/Shopfloor/lib/Send-PxeStatus.ps1 @@ -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 ) diff --git a/playbook/shopfloor-setup/Shopfloor/lib/Set-OpenTextAutoStart.ps1 b/playbook/shopfloor-setup/Shopfloor/lib/Set-OpenTextAutoStart.ps1 new file mode 100644 index 0000000..27c16df --- /dev/null +++ b/playbook/shopfloor-setup/Shopfloor/lib/Set-OpenTextAutoStart.ps1 @@ -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: $_" +} diff --git a/playbook/shopfloor-setup/gea-shopfloor-collections/01-eDNC.ps1 b/playbook/shopfloor-setup/gea-shopfloor-collections/01-eDNC.ps1 index c8f0cf5..f6e7c42 100644 --- a/playbook/shopfloor-setup/gea-shopfloor-collections/01-eDNC.ps1 +++ b/playbook/shopfloor-setup/gea-shopfloor-collections/01-eDNC.ps1 @@ -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." diff --git a/playbook/shopfloor-setup/gea-shopfloor-collections/03-RestoreEDncConfig.ps1 b/playbook/shopfloor-setup/gea-shopfloor-collections/03-RestoreEDncConfig.ps1 index 6ea5e68..c9b8e95 100644 --- a/playbook/shopfloor-setup/gea-shopfloor-collections/03-RestoreEDncConfig.ps1 +++ b/playbook/shopfloor-setup/gea-shopfloor-collections/03-RestoreEDncConfig.ps1 @@ -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 {} diff --git a/playbook/shopfloor-setup/gea-shopfloor-collections/Set-MachineNumber.bat b/playbook/shopfloor-setup/gea-shopfloor-collections/Set-MachineNumber.bat index c6531a4..ee1fd75 100644 --- a/playbook/shopfloor-setup/gea-shopfloor-collections/Set-MachineNumber.bat +++ b/playbook/shopfloor-setup/gea-shopfloor-collections/Set-MachineNumber.bat @@ -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 diff --git a/playbook/shopfloor-setup/gea-shopfloor-collections/eDNC/eDNC_6-4-5.msi b/playbook/shopfloor-setup/gea-shopfloor-collections/eDNC/eDNC_6-4-5.msi new file mode 100755 index 0000000..5f52acf Binary files /dev/null and b/playbook/shopfloor-setup/gea-shopfloor-collections/eDNC/eDNC_6-4-5.msi differ diff --git a/playbook/shopfloor-setup/gea-shopfloor-common/09-Setup-Lab.ps1 b/playbook/shopfloor-setup/gea-shopfloor-common/09-Setup-Lab.ps1 deleted file mode 100644 index c92aecb..0000000 --- a/playbook/shopfloor-setup/gea-shopfloor-common/09-Setup-Lab.ps1 +++ /dev/null @@ -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 ===" diff --git a/playbook/shopfloor-setup/gea-shopfloor-nocollections/01-eDNC.ps1 b/playbook/shopfloor-setup/gea-shopfloor-nocollections/01-eDNC.ps1 index c8f0cf5..f6e7c42 100644 --- a/playbook/shopfloor-setup/gea-shopfloor-nocollections/01-eDNC.ps1 +++ b/playbook/shopfloor-setup/gea-shopfloor-nocollections/01-eDNC.ps1 @@ -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." diff --git a/playbook/shopfloor-setup/gea-shopfloor-nocollections/03-RestoreEDncConfig.ps1 b/playbook/shopfloor-setup/gea-shopfloor-nocollections/03-RestoreEDncConfig.ps1 index 6ea5e68..3ab197d 100644 --- a/playbook/shopfloor-setup/gea-shopfloor-nocollections/03-RestoreEDncConfig.ps1 +++ b/playbook/shopfloor-setup/gea-shopfloor-nocollections/03-RestoreEDncConfig.ps1 @@ -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 {} diff --git a/playbook/shopfloor-setup/gea-shopfloor-nocollections/Set-MachineNumber.bat b/playbook/shopfloor-setup/gea-shopfloor-nocollections/Set-MachineNumber.bat index c6531a4..dd5ef5b 100644 --- a/playbook/shopfloor-setup/gea-shopfloor-nocollections/Set-MachineNumber.bat +++ b/playbook/shopfloor-setup/gea-shopfloor-nocollections/Set-MachineNumber.bat @@ -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 diff --git a/playbook/shopfloor-setup/gea-shopfloor-nocollections/eDNC/eDNC_6-4-5.msi b/playbook/shopfloor-setup/gea-shopfloor-nocollections/eDNC/eDNC_6-4-5.msi new file mode 100755 index 0000000..5f52acf Binary files /dev/null and b/playbook/shopfloor-setup/gea-shopfloor-nocollections/eDNC/eDNC_6-4-5.msi differ diff --git a/playbook/shopfloor-setup/site-config.json b/playbook/shopfloor-setup/site-config.json index 5e20120..6665d1a 100644 --- a/playbook/shopfloor-setup/site-config.json +++ b/playbook/shopfloor-setup/site-config.json @@ -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", diff --git a/playbook/startnet.cmd b/playbook/startnet.cmd index 475b413..28ef75f 100644 --- a/playbook/startnet.cmd +++ b/playbook/startnet.cmd @@ -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 diff --git a/playbook/sync-cmm.sh b/playbook/sync-cmm.sh index d2acb63..f90641a 100755 --- a/playbook/sync-cmm.sh +++ b/playbook/sync-cmm.sh @@ -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}" diff --git a/playbook/sync-preinstall.sh b/playbook/sync-preinstall.sh index ab86c1f..42050a6 100755 --- a/playbook/sync-preinstall.sh +++ b/playbook/sync-preinstall.sh @@ -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}" diff --git a/playbook/winpe-status-push.ps1 b/playbook/winpe-status-push.ps1 index 302b6a2..6d9eb9c 100644 --- a/playbook/winpe-status-push.ps1 +++ b/playbook/winpe-status-push.ps1 @@ -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 diff --git a/scripts/Upload-Image.ps1 b/scripts/Upload-Image.ps1 index d2e0011..0b5e625 100644 --- a/scripts/Upload-Image.ps1 +++ b/scripts/Upload-Image.ps1 @@ -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 diff --git a/scripts/build-proxmox-iso.sh b/scripts/build-proxmox-iso.sh index 2b27707..263afd4 100755 --- a/scripts/build-proxmox-iso.sh +++ b/scripts/build-proxmox-iso.sh @@ -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 "" diff --git a/scripts/deploy-bios.sh b/scripts/deploy-bios.sh index d461e7a..db07879 100755 --- a/scripts/deploy-bios.sh +++ b/scripts/deploy-bios.sh @@ -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" diff --git a/scripts/diagnostics/Capture-LockdownState.ps1 b/scripts/diagnostics/Capture-LockdownState.ps1 index d03d3e9..9e76a09 100644 --- a/scripts/diagnostics/Capture-LockdownState.ps1 +++ b/scripts/diagnostics/Capture-LockdownState.ps1 @@ -23,7 +23,7 @@ Output lands under C:\ProgramData\state--\. 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\ 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\ +# FirstSync IsSyncDone=1 in Enrollments\\FirstSync +# Layer 3 - Policy actually delivered (CSP succeeded, not just provider registered) +# PolicyManager\Providers\\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\\FirstSync IsSyncDone=1" -f $(if ($r.FirstSyncIsSyncDone) {'OK '} else {'FAIL'})) + ' Layer 3 - policy actually delivered' + (" [{0}] PolicyManager\Providers\\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" diff --git a/scripts/diagnostics/Compare-LockdownStates.ps1 b/scripts/diagnostics/Compare-LockdownStates.ps1 new file mode 100644 index 0000000..c62b402 --- /dev/null +++ b/scripts/diagnostics/Compare-LockdownStates.ps1 @@ -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-.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 diff --git a/scripts/diagnostics/snapshot-runbook.txt b/scripts/diagnostics/snapshot-runbook.txt index 16c19ef..1f90acc 100644 --- a/scripts/diagnostics/snapshot-runbook.txt +++ b/scripts/diagnostics/snapshot-runbook.txt @@ -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-\ } net use Z: /delete /y -The three folders land at \\10.9.100.1\image-upload\state-*-\. +The three folders land at \\172.16.9.1\image-upload\state-*-\. 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/). diff --git a/scripts/download-drivers.py b/scripts/download-drivers.py index b79d735..1005e80 100755 --- a/scripts/download-drivers.py +++ b/scripts/download-drivers.py @@ -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 diff --git a/scripts/prepare-boot-tools.sh b/scripts/prepare-boot-tools.sh index 5c728a8..7b499f3 100755 --- a/scripts/prepare-boot-tools.sh +++ b/scripts/prepare-boot-tools.sh @@ -137,7 +137,7 @@ data = data.replace( ) data = data.replace( b'', - b'10.9.100.1' + b'172.16.9.1' ) data = data.replace( b'', @@ -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" diff --git a/scripts/pull-bios.sh b/scripts/pull-bios.sh index be43054..397c6a8 100755 --- a/scripts/pull-bios.sh +++ b/scripts/pull-bios.sh @@ -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" diff --git a/startnet-template.cmd b/startnet-template.cmd index 3876179..a238ecf 100644 --- a/startnet-template.cmd +++ b/startnet-template.cmd @@ -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 diff --git a/webapp/static/qr-render.js b/webapp/static/qr-render.js new file mode 100644 index 0000000..097f96e --- /dev/null +++ b/webapp/static/qr-render.js @@ -0,0 +1,42 @@ +// QR render helper. Scans for any element with data-qr="" and renders +// a Kazuhiko Arase qrcode-generator QR into it as inline . 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(); + } +})(); diff --git a/webapp/static/qrcode.min.js b/webapp/static/qrcode.min.js new file mode 100644 index 0000000..c1215c7 --- /dev/null +++ b/webapp/static/qrcode.min.js @@ -0,0 +1,8 @@ +/** + * Minified by jsDelivr using Terser v5.37.0. + * Original file: /npm/qrcode-generator@1.4.4/qrcode.js + * + * Do NOT use SRI with dynamically generated files! More information: https://www.jsdelivr.com/using-sri-with-dynamic-files + */ +var qrcode=function(){var t=function(t,r){var e=t,n=g[r],o=null,i=0,a=null,u=[],f={},c=function(t,r){o=function(t){for(var r=new Array(t),e=0;e=7&&v(t),null==a&&(a=p(e,n,u)),w(a,r)},l=function(t,r){for(var e=-1;e<=7;e+=1)if(!(t+e<=-1||i<=t+e))for(var n=-1;n<=7;n+=1)r+n<=-1||i<=r+n||(o[t+e][r+n]=0<=e&&e<=6&&(0==n||6==n)||0<=n&&n<=6&&(0==e||6==e)||2<=e&&e<=4&&2<=n&&n<=4)},h=function(){for(var t=8;t>n&1);o[Math.floor(n/3)][n%3+i-8-3]=a}for(n=0;n<18;n+=1){a=!t&&1==(r>>n&1);o[n%3+i-8-3][Math.floor(n/3)]=a}},d=function(t,r){for(var e=n<<3|r,a=B.getBCHTypeInfo(e),u=0;u<15;u+=1){var f=!t&&1==(a>>u&1);u<6?o[u][8]=f:u<8?o[u+1][8]=f:o[i-15+u][8]=f}for(u=0;u<15;u+=1){f=!t&&1==(a>>u&1);u<8?o[8][i-u-1]=f:u<9?o[8][15-u-1+1]=f:o[8][15-u-1]=f}o[i-8][8]=!t},w=function(t,r){for(var e=-1,n=i-1,a=7,u=0,f=B.getMaskFunction(r),c=i-1;c>0;c-=2)for(6==c&&(c-=1);;){for(var g=0;g<2;g+=1)if(null==o[n][c-g]){var l=!1;u>>a&1)),f(n,c-g)&&(l=!l),o[n][c-g]=l,-1==(a-=1)&&(u+=1,a=7)}if((n+=e)<0||i<=n){n-=e,e=-e;break}}},p=function(t,r,e){for(var n=A.getRSBlocks(t,r),o=b(),i=0;i8*u)throw"code length overflow. ("+o.getLengthInBits()+">"+8*u+")";for(o.getLengthInBits()+4<=8*u&&o.put(0,4);o.getLengthInBits()%8!=0;)o.putBit(!1);for(;!(o.getLengthInBits()>=8*u||(o.put(236,8),o.getLengthInBits()>=8*u));)o.put(17,8);return function(t,r){for(var e=0,n=0,o=0,i=new Array(r.length),a=new Array(r.length),u=0;u=0?h.getAt(s):0}}var v=0;for(g=0;gn)&&(t=n,r=e)}return r}())},f.createTableTag=function(t,r){t=t||2;var e="";e+='',e+="";for(var n=0;n";for(var o=0;o';e+=""}return e+="",e+="
"},f.createSvgTag=function(t,r,e,n){var o={};"object"==typeof arguments[0]&&(t=(o=arguments[0]).cellSize,r=o.margin,e=o.alt,n=o.title),t=t||2,r=void 0===r?4*t:r,(e="string"==typeof e?{text:e}:e||{}).text=e.text||null,e.id=e.text?e.id||"qrcode-description":null,(n="string"==typeof n?{text:n}:n||{}).text=n.text||null,n.id=n.text?n.id||"qrcode-title":null;var i,a,u,c,g=f.getModuleCount()*t+2*r,l="";for(c="l"+t+",0 0,"+t+" -"+t+",0 0,-"+t+"z ",l+=''+y(n.text)+"":"",l+=e.text?''+y(e.text)+"":"",l+='',l+='":r+=">";break;case"&":r+="&";break;case'"':r+=""";break;default:r+=n}}return r};return f.createASCII=function(t,r){if((t=t||1)<2)return function(t){t=void 0===t?2:t;var r,e,n,o,i,a=1*f.getModuleCount()+2*t,u=t,c=a-t,g={"笆遺毎":"笆","笆 ":"笆"," 笆":"笆"," ":" "},l={"笆遺毎":"笆","笆 ":"笆"," 笆":" "," ":" "},h="";for(r=0;r=c?l[i]:g[i];h+="\n"}return a%2&&t>0?h.substring(0,h.length-a-1)+Array(a+1).join("笆"):h.substring(0,h.length-1)}(r);t-=1,r=void 0===r?2*t:r;var e,n,o,i,a=f.getModuleCount()*t+2*r,u=r,c=a-r,g=Array(t+1).join("笆遺毎"),l=Array(t+1).join(" "),h="",s="";for(e=0;e>>8),r.push(255&a)):r.push(n)}}return r}};var r,e,n,o,i,a=1,u=2,f=4,c=8,g={L:1,M:0,Q:3,H:2},l=0,h=1,s=2,v=3,d=4,w=5,p=6,y=7,B=(r=[[],[6,18],[6,22],[6,26],[6,30],[6,34],[6,22,38],[6,24,42],[6,26,46],[6,28,50],[6,30,54],[6,32,58],[6,34,62],[6,26,46,66],[6,26,48,70],[6,26,50,74],[6,30,54,78],[6,30,56,82],[6,30,58,86],[6,34,62,90],[6,28,50,72,94],[6,26,50,74,98],[6,30,54,78,102],[6,28,54,80,106],[6,32,58,84,110],[6,30,58,86,114],[6,34,62,90,118],[6,26,50,74,98,122],[6,30,54,78,102,126],[6,26,52,78,104,130],[6,30,56,82,108,134],[6,34,60,86,112,138],[6,30,58,86,114,142],[6,34,62,90,118,146],[6,30,54,78,102,126,150],[6,24,50,76,102,128,154],[6,28,54,80,106,132,158],[6,32,58,84,110,136,162],[6,26,54,82,110,138,166],[6,30,58,86,114,142,170]],e=1335,n=7973,i=function(t){for(var r=0;0!=t;)r+=1,t>>>=1;return r},(o={}).getBCHTypeInfo=function(t){for(var r=t<<10;i(r)-i(e)>=0;)r^=e<=0;)r^=n<5&&(e+=3+i-5)}for(n=0;n=256;)r-=255;return t[r]}};return n}();function k(t,r){if(void 0===t.length)throw t.length+"/"+r;var e=function(){for(var e=0;e>>7-r%8&1)},put:function(t,r){for(var n=0;n>>r-n-1&1))},getLengthInBits:function(){return r},putBit:function(e){var n=Math.floor(r/8);t.length<=n&&t.push(0),e&&(t[n]|=128>>>r%8),r+=1}};return e},M=function(t){var r=a,e=t,n={getMode:function(){return r},getLength:function(t){return e.length},write:function(t){for(var r=e,n=0;n+2>>8&255)+(255&n),t.put(n,13),e+=2}if(e>>8)},writeBytes:function(t,e,n){e=e||0,n=n||t.length;for(var o=0;o0&&(r+=","),r+=t[e];return r+="]"}};return r},S=function(t){var r=t,e=0,n=0,o=0,i={read:function(){for(;o<8;){if(e>=r.length){if(0==o)return-1;throw"unexpected end of file./"+o}var t=r.charAt(e);if(e+=1,"="==t)return o=0,-1;t.match(/^\s$/)||(n=n<<6|a(t.charCodeAt(0)),o+=6)}var i=n>>>o-8&255;return o-=8,i}},a=function(t){if(65<=t&&t<=90)return t-65;if(97<=t&&t<=122)return t-97+26;if(48<=t&&t<=57)return t-48+52;if(43==t)return 62;if(47==t)return 63;throw"c:"+t};return i},I=function(t,r,e){for(var n=function(t,r){var e=t,n=r,o=new Array(t*r),i={setPixel:function(t,r,n){o[r*e+t]=n},write:function(t){t.writeString("GIF87a"),t.writeShort(e),t.writeShort(n),t.writeByte(128),t.writeByte(0),t.writeByte(0),t.writeByte(0),t.writeByte(0),t.writeByte(0),t.writeByte(255),t.writeByte(255),t.writeByte(255),t.writeString(","),t.writeShort(0),t.writeShort(0),t.writeShort(e),t.writeShort(n),t.writeByte(0);var r=a(2);t.writeByte(2);for(var o=0;r.length-o>255;)t.writeByte(255),t.writeBytes(r,o,255),o+=255;t.writeByte(r.length-o),t.writeBytes(r,o,r.length-o),t.writeByte(0),t.writeString(";")}},a=function(t){for(var r=1<>>r!=0)throw"length over";for(;c+r>=8;)f.writeByte(255&(t<>>=8-c,g=0,c=0;g|=t<0&&f.writeByte(g)}});h.write(r,n);var s=0,v=String.fromCharCode(o[s]);for(s+=1;s=6;)i(t>>>r-6),r-=6},o.flush=function(){if(r>0&&(i(t<<6-r),t=0,r=0),e%3!=0)for(var o=3-e%3,a=0;a>6,128|63&n):n<55296||n>=57344?r.push(224|n>>12,128|n>>6&63,128|63&n):(e++,n=65536+((1023&n)<<10|1023&t.charCodeAt(e)),r.push(240|n>>18,128|n>>12&63,128|n>>6&63,128|63&n))}return r}(t)},function(t){"function"==typeof define&&define.amd?define([],t):"object"==typeof exports&&(module.exports=t())}((function(){return qrcode})); +//# sourceMappingURL=/sm/26b4b0d0b1e283d6b3ec9857ac597d7a60c76ac17be1ef4c965f03086de426bb.map \ No newline at end of file diff --git a/webapp/templates/base.html b/webapp/templates/base.html index e185823..1ce07db 100644 --- a/webapp/templates/base.html +++ b/webapp/templates/base.html @@ -221,6 +221,8 @@ + + {% block extra_scripts %}{% endblock %} diff --git a/webapp/templates/imaging.html b/webapp/templates/imaging.html index 378e5e7..c5c25e9 100644 --- a/webapp/templates/imaging.html +++ b/webapp/templates/imaging.html @@ -116,7 +116,7 @@
How to push status from an imaging client: -
POST http://10.9.100.1:9009/imaging/status
+    
POST http://172.16.9.1:9009/imaging/status
 Content-Type: application/json
 
 {
diff --git a/webapp/templates/import.html b/webapp/templates/import.html
index 7db92f9..27975a8 100644
--- a/webapp/templates/import.html
+++ b/webapp/templates/import.html
@@ -25,7 +25,7 @@
               {% endfor %}
             
             
- Files uploaded via SMB to \\10.9.100.1\image-upload + Files uploaded via SMB to \\172.16.9.1\image-upload
@@ -66,7 +66,7 @@
No Upload Content Found

- Map \\10.9.100.1\image-upload on your Windows PC and copy + Map \\172.16.9.1\image-upload on your Windows PC and copy the Deploy directory contents there.