# 04-SetControllerNicIP.ps1 - Auto-configure the controller-facing Realtek NIC # at imaging time on gea-shopfloor-collections bays. # # Standard config (per post-deploy-debug-flowchart.md, section 2B): # IP: 192.168.1.2 # Mask: 255.255.255.0 (/24) # Gateway: (blank) # DNS: (none - cleared) # # Logic: # 1. Find physical Ethernet adapters whose vendor description contains # 'Realtek'. (Shopfloor PCs ship with a Realtek PCIe GbE add-in card # for the controller; the corp LAN NIC is typically Intel.) # 2. Skip any candidate that already has a DHCP-assigned default gateway # (that's the corp LAN NIC, not the controller). # 3. Skip any candidate that already has 192.168.1.2 - already configured. # 4. For the single remaining candidate, set manual IP / mask, clear DNS. # 5. If multiple Realtek NICs remain after filtering, log + bail (manual # investigation needed; the script will NOT guess which is controller). # # Imaging-time only - run once during Run-ShopfloorSetup for collections # bays. Not registered as a GE-Enforce drift-catcher because once set, # manual changes by the tech are intentional and should not be reverted. # # Log: C:\Logs\Shopfloor\controller-nic.log $ErrorActionPreference = 'Continue' $logDir = 'C:\Logs\Shopfloor' if (-not (Test-Path $logDir)) { New-Item -ItemType Directory -Path $logDir -Force | Out-Null } $logFile = Join-Path $logDir 'controller-nic.log' function Write-NicLog { param([string]$Message, [string]$Level = 'INFO') $line = '[{0}] [{1}] {2}' -f (Get-Date -Format 'yyyy-MM-dd HH:mm:ss'), $Level, $Message Add-Content -Path $logFile -Value $line -ErrorAction SilentlyContinue Write-Host $line } $targetIP = '192.168.1.2' $prefixLen = 24 Write-NicLog "=== 04-SetControllerNicIP start ===" # Enumerate physical Ethernet adapters with Realtek in the vendor description. $candidates = Get-NetAdapter -Physical -ErrorAction SilentlyContinue | Where-Object { $_.InterfaceDescription -match 'Realtek' -and $_.MediaType -eq '802.3' } if (-not $candidates) { Write-NicLog "No Realtek physical Ethernet adapters found - nothing to configure (PC may have no controller NIC)." exit 0 } Write-NicLog "Found $($candidates.Count) Realtek adapter(s):" foreach ($c in $candidates) { Write-NicLog " $($c.Name) ($($c.InterfaceDescription)) [status=$($c.Status)]" } # Filter out anything that already looks like the corp LAN NIC (has a # DHCP-assigned default gateway -- corp DHCP servers always hand one out). $filtered = @() foreach ($c in $candidates) { $ipCfg = Get-NetIPConfiguration -InterfaceIndex $c.ifIndex -ErrorAction SilentlyContinue $gw = $null if ($ipCfg -and $ipCfg.IPv4DefaultGateway) { $gw = ($ipCfg.IPv4DefaultGateway | Select-Object -First 1).NextHop } if ($gw) { Write-NicLog " Skipping $($c.Name) - has IPv4 default gateway $gw (likely corp LAN, not controller)" continue } # Skip if it already has 192.168.1.2 - already configured. $existing = Get-NetIPAddress -InterfaceIndex $c.ifIndex -AddressFamily IPv4 -ErrorAction SilentlyContinue | Where-Object { $_.IPAddress -eq $targetIP } if ($existing) { Write-NicLog " Skipping $($c.Name) - already has $targetIP/$prefixLen (configured previously)" continue } $filtered += $c } if ($filtered.Count -eq 0) { Write-NicLog "After filtering, no candidate remains - either already configured or all Realtek adapters look like corp LAN. Nothing to do." exit 0 } if ($filtered.Count -gt 1) { Write-NicLog "Multiple unconfigured Realtek adapters found ($($filtered.Count)). Refusing to guess which is the controller NIC. Manual configuration required." 'WARN' foreach ($f in $filtered) { Write-NicLog " Ambiguous: $($f.Name) ($($f.InterfaceDescription))" 'WARN' } exit 0 } $target = $filtered[0] Write-NicLog "Selected controller NIC: $($target.Name) ($($target.InterfaceDescription)) [ifIndex=$($target.ifIndex)]" # Wipe any existing IPv4 addresses + gateways on this interface so the new # static doesn't conflict with stale DHCP leases or APIPA addresses. try { Get-NetIPAddress -InterfaceIndex $target.ifIndex -AddressFamily IPv4 -ErrorAction SilentlyContinue | Remove-NetIPAddress -Confirm:$false -ErrorAction SilentlyContinue Get-NetRoute -InterfaceIndex $target.ifIndex -AddressFamily IPv4 -ErrorAction SilentlyContinue | Where-Object { $_.DestinationPrefix -eq '0.0.0.0/0' } | Remove-NetRoute -Confirm:$false -ErrorAction SilentlyContinue Write-NicLog "Cleared existing IPv4 addresses + default route on $($target.Name)" } catch { Write-NicLog "Failed to clear existing IPv4 state on $($target.Name): $_" 'WARN' } # Switch the interface to manual IP assignment + set the static. try { Set-NetIPInterface -InterfaceIndex $target.ifIndex -Dhcp Disabled -ErrorAction Stop New-NetIPAddress -InterfaceIndex $target.ifIndex -IPAddress $targetIP ` -PrefixLength $prefixLen -ErrorAction Stop | Out-Null Write-NicLog "Set $targetIP/$prefixLen on $($target.Name) (no gateway)" } catch { Write-NicLog "Failed to set static IP on $($target.Name): $_" 'ERROR' exit 1 } # Clear DNS so the corp resolver doesn't get queried for controller-side hostnames. try { Set-DnsClientServerAddress -InterfaceIndex $target.ifIndex -ResetServerAddresses -ErrorAction Stop Write-NicLog "Cleared DNS servers on $($target.Name)" } catch { Write-NicLog "Failed to clear DNS on $($target.Name): $_" 'WARN' } # Verify what landed. try { $finalCfg = Get-NetIPConfiguration -InterfaceIndex $target.ifIndex -ErrorAction SilentlyContinue $finalIPs = ($finalCfg.IPv4Address | ForEach-Object { "$($_.IPAddress)/$($_.PrefixLength)" }) -join ', ' $finalGw = if ($finalCfg.IPv4DefaultGateway) { ($finalCfg.IPv4DefaultGateway | Select-Object -First 1).NextHop } else { '(none)' } $finalDns = ($finalCfg.DNSServer | Where-Object AddressFamily -eq 2 | Select-Object -ExpandProperty ServerAddresses) -join ', ' if (-not $finalDns) { $finalDns = '(none)' } Write-NicLog "Verify: $($target.Name) IPs=$finalIPs Gateway=$finalGw DNS=$finalDns" } catch { Write-NicLog "Verification readback failed: $_" 'WARN' } Write-NicLog "=== 04-SetControllerNicIP end ===" exit 0