f090365d57
- WinRM MaxProcessesPerShell: apply 100 if below threshold before asserting - DesktopHeap SharedSection: apply 4096 KB registry value if below threshold before asserting - Replace cleanmgr (hangs in WinRM Session 0, no window station) with direct PowerShell cleanup for dumps, WER files and Recycle Bin; DISM already covers component store and WU cache - vcpkg git clone/checkout: wrap with EAP=Continue to suppress PS5.1 NativeCommandError on git stderr (gotcha #3 from AGENTS.md) - template.py: filter CI_EXITCODE:N marker from displayed output - ci-static-ip.ps1: switch from vmware-rpctool (removed in recent Tools) to vmtoolsd --cmd; use temp-file redirect to capture output from native cmd Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
116 lines
4.6 KiB
PowerShell
116 lines
4.6 KiB
PowerShell
#Requires -Version 5.1
|
|
<#
|
|
.SYNOPSIS
|
|
Applies a pre-assigned static IP from VMware guestinfo at boot.
|
|
|
|
.DESCRIPTION
|
|
Called by the CI-StaticIp Task Scheduler task at system startup (SYSTEM
|
|
account). Reads guestinfo.ip-assignment written by the host orchestrator
|
|
before vmrun start. If present, disables DHCP and applies the static IP
|
|
before WinRM has a chance to start on a DHCP address, eliminating the
|
|
20-180 s VMware-Tools IP-detect polling loop.
|
|
|
|
If guestinfo.ip-assignment is absent (template used standalone or
|
|
ip_pool not configured), exits 0 immediately — DHCP runs normally.
|
|
|
|
Install into the template VM:
|
|
1. Copy this script to C:\CI\ci-static-ip.ps1
|
|
2. Create a Task Scheduler task:
|
|
Name: CI-StaticIp
|
|
Trigger: At System Startup
|
|
Action: powershell.exe -NoProfile -NonInteractive
|
|
-ExecutionPolicy Bypass -File C:\CI\ci-static-ip.ps1
|
|
Run As: SYSTEM
|
|
Run with highest privileges: Yes
|
|
3. Take the BaseClean snapshot from powered-OFF state.
|
|
|
|
The VMCI channel (vmware-rpctool) does not require TCP/IP — it works
|
|
via the VMware virtual hardware interface, so guestinfo is readable
|
|
before the NIC is configured.
|
|
#>
|
|
Set-StrictMode -Version Latest
|
|
$ErrorActionPreference = 'Stop'
|
|
|
|
# vmware-rpctool.exe was removed in recent VMware Tools versions; use vmtoolsd --cmd instead.
|
|
$vmtoolsd = 'C:\Program Files\VMware\VMware Tools\vmtoolsd.exe'
|
|
if (-not (Test-Path $vmtoolsd -PathType Leaf)) { exit 0 }
|
|
|
|
function Read-GuestInfo {
|
|
param([string]$Key)
|
|
# vmtoolsd writes to a file handle but not to a PS pipeline — use cmd.exe redirection.
|
|
$tmp = [System.IO.Path]::GetTempFileName()
|
|
try {
|
|
$savedEap = $ErrorActionPreference; $ErrorActionPreference = 'Continue'
|
|
cmd /c "`"$vmtoolsd`" --cmd `"info-get guestinfo.$Key`" > `"$tmp`" 2>&1"
|
|
$ErrorActionPreference = $savedEap
|
|
$text = (Get-Content $tmp -ErrorAction SilentlyContinue | Out-String).Trim()
|
|
if ($text -and $text -notmatch 'No value found|Error') {
|
|
return $text
|
|
}
|
|
} finally {
|
|
Remove-Item $tmp -ErrorAction SilentlyContinue
|
|
}
|
|
return ''
|
|
}
|
|
|
|
$ip = Read-GuestInfo 'ip-assignment'
|
|
$netmask = Read-GuestInfo 'netmask'
|
|
$gateway = Read-GuestInfo 'gateway'
|
|
|
|
# No pre-assigned IP — let DHCP run normally.
|
|
if (-not ($ip -match '^\d{1,3}(\.\d{1,3}){3}$')) { exit 0 }
|
|
|
|
# Convert dotted-decimal netmask to prefix length (default /24).
|
|
function Get-PrefixLength {
|
|
param([string]$Mask)
|
|
if (-not ($Mask -match '^\d{1,3}(\.\d{1,3}){3}$')) { return 24 }
|
|
$bits = 0
|
|
foreach ($octet in $Mask.Split('.')) {
|
|
$b = [int]$octet
|
|
while ($b -gt 0) { $bits += ($b -band 1); $b = $b -shr 1 }
|
|
}
|
|
return $bits
|
|
}
|
|
$prefix = Get-PrefixLength $netmask
|
|
|
|
# Target the first Up adapter (skip loopback / Teredo / Bluetooth).
|
|
$adapter = Get-NetAdapter |
|
|
Where-Object { $_.Status -eq 'Up' -and $_.InterfaceDescription -notmatch 'Loopback|Bluetooth|Teredo' } |
|
|
Select-Object -First 1
|
|
if (-not $adapter) {
|
|
Write-EventLog -LogName Application -Source 'ci-static-ip' -EventId 1 `
|
|
-EntryType Error -Message 'No Up adapter found.' -ErrorAction SilentlyContinue
|
|
exit 1
|
|
}
|
|
|
|
# Disable DHCP and remove any existing IPv4 addresses and routes.
|
|
$adapter | Set-NetIPInterface -Dhcp Disabled -ErrorAction SilentlyContinue
|
|
Get-NetRoute -InterfaceAlias $adapter.Name -AddressFamily IPv4 -ErrorAction SilentlyContinue |
|
|
Remove-NetRoute -Confirm:$false -ErrorAction SilentlyContinue
|
|
$adapter | Get-NetIPAddress -AddressFamily IPv4 -ErrorAction SilentlyContinue |
|
|
Remove-NetIPAddress -Confirm:$false -ErrorAction SilentlyContinue
|
|
|
|
# Apply static IP (no DefaultGateway here — add route separately to avoid conflicts).
|
|
New-NetIPAddress -InterfaceAlias $adapter.Name -IPAddress $ip `
|
|
-PrefixLength $prefix -ErrorAction Stop | Out-Null
|
|
|
|
# Add default route if gateway supplied.
|
|
if ($gateway -match '^\d{1,3}(\.\d{1,3}){3}$') {
|
|
New-NetRoute -InterfaceAlias $adapter.Name -DestinationPrefix '0.0.0.0/0' `
|
|
-NextHop $gateway -ErrorAction SilentlyContinue | Out-Null
|
|
}
|
|
|
|
# Use the gateway as DNS (fallback: Google DNS).
|
|
$dns = @()
|
|
if ($gateway -match '^\d{1,3}(\.\d{1,3}){3}$') { $dns += $gateway }
|
|
$dns += '8.8.8.8'
|
|
Set-DnsClientServerAddress -InterfaceAlias $adapter.Name `
|
|
-ServerAddresses $dns -ErrorAction SilentlyContinue
|
|
|
|
# Report IP back via guestinfo.ci-ip so the host also has it.
|
|
$savedEap = $ErrorActionPreference; $ErrorActionPreference = 'Continue'
|
|
& $vmtoolsd --cmd "info-set guestinfo.ci-ip $ip" 2>&1 | Out-Null
|
|
$ErrorActionPreference = $savedEap
|
|
|
|
exit 0
|