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