f373c0c24b
P0 bugs: - Invoke-CIJob.ps1: skip --depth 1 when $Commit specified (shallow clone + checkout specific commit was silently failing) - Get-BuildArtifacts.ps1: check .Length -eq 0 not rounded sizeKB (false fail on artifacts smaller than 50 bytes) - build-nsis.yml: upgrade upload-artifact v3 -> v4 (v3 deprecated) P0 security: - Remove hardcoded default password CIBuild!ChangeMe2026 from all scripts, README, TODO; prompt Read-Host -AsSecureString at runtime instead - Setup-TemplateVM.ps1: replace `net user $u $p /add` (password in argv / audit log 4688) with New-LocalUser + local ConvertTo-SecureString - Prepare-TemplateSetup.ps1: save and restore WSMan AllowUnencrypted + TrustedHosts in finally block (was permanently mutating host WinRM config) - Setup-TemplateVM.ps1: remove duplicate MaxMemoryPerShellMB (winrm set + Set-Item both setting same value) P1 doc (stale Host-Only / VMnet11 era): - Setup-TemplateVM.ps1: rewrite NETWORK REQUIREMENT block + final steps (system uses VMnet8 NAT permanently, not VMnet11 Host-Only) - Invoke-CIJob.ps1 Phase 1 comment: correct network model - ARCHITECTURE.md: remove Git from toolchain list (not installed); clarify zip-transfer rationale (no PAT in VM, not network isolation) - BEST-PRACTICES.md: rewrite Step 8 as NAT topology verification P1 minor: - Invoke-RemoteBuild.ps1: remove wasted first New-Item (created then immediately removed and recreated) - Wait-VMReady.ps1: remove unused $elapsed; simplify try/catch around native command (exit codes don't throw) - Install-Runner.ps1: add deprecation notice pointing to Setup-Host.ps1 P2 operational: - Add scripts/Cleanup-OrphanedBuildVMs.ps1 with -WhatIf support - Get-BuildArtifacts.ps1 -IncludeLogs: add -Recurse (msbuild logs in subdir) - Add gitea/workflows/lint.yml (PSScriptAnalyzer on .ps1 push/PR) Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
129 lines
4.2 KiB
PowerShell
129 lines
4.2 KiB
PowerShell
#Requires -Version 5.1
|
|
<#
|
|
.SYNOPSIS
|
|
Waits until a build VM is fully ready to accept WinRM connections.
|
|
|
|
.DESCRIPTION
|
|
Performs a three-phase readiness check in a polling loop:
|
|
1. vmrun getState returns "running"
|
|
2. ICMP ping succeeds
|
|
3. Test-WSMan (WinRM) responds without error
|
|
|
|
Throws if the VM does not become ready within the timeout period.
|
|
|
|
.PARAMETER VMPath
|
|
Full path to the clone VM's .vmx file.
|
|
|
|
.PARAMETER IPAddress
|
|
IP address of the VM on the build network (e.g. 192.168.11.101).
|
|
|
|
.PARAMETER TimeoutSeconds
|
|
Maximum seconds to wait for the VM to become ready.
|
|
Default: 300 (5 minutes)
|
|
|
|
.PARAMETER PollIntervalSeconds
|
|
Seconds between readiness checks.
|
|
Default: 5
|
|
|
|
.PARAMETER VmrunPath
|
|
Full path to vmrun.exe.
|
|
Default: C:\Program Files (x86)\VMware\VMware Workstation\vmrun.exe
|
|
|
|
.EXAMPLE
|
|
.\Wait-VMReady.ps1 `
|
|
-VMPath "F:\CI\BuildVMs\Clone_run-42_20260508_143022\Clone_run-42_20260508_143022.vmx" `
|
|
-IPAddress "192.168.11.101"
|
|
#>
|
|
[CmdletBinding()]
|
|
param(
|
|
[Parameter(Mandatory)]
|
|
[string] $VMPath,
|
|
|
|
[Parameter(Mandatory)]
|
|
[ValidatePattern('^(\d{1,3}\.){3}\d{1,3}$')]
|
|
[string] $IPAddress,
|
|
|
|
[ValidateRange(30, 600)]
|
|
[int] $TimeoutSeconds = 300,
|
|
|
|
[ValidateRange(3, 30)]
|
|
[int] $PollIntervalSeconds = 5,
|
|
|
|
[string] $VmrunPath = 'C:\Program Files (x86)\VMware\VMware Workstation\vmrun.exe',
|
|
|
|
# Skip ICMP ping phase (phase 2). Useful when the guest firewall blocks ICMP
|
|
# but WinRM (TCP 5985) is open. Phase 1 (vmrun state) and phase 3 (WinRM)
|
|
# are still checked.
|
|
[switch] $SkipPing
|
|
)
|
|
|
|
Set-StrictMode -Version Latest
|
|
$ErrorActionPreference = 'Stop'
|
|
|
|
if (-not (Test-Path $VmrunPath -PathType Leaf)) {
|
|
throw "vmrun.exe not found at: $VmrunPath"
|
|
}
|
|
|
|
$deadline = (Get-Date).AddSeconds($TimeoutSeconds)
|
|
$attempt = 0
|
|
$phase = 'vmrun-state' # tracks current phase for informative output
|
|
$lastPhase = ''
|
|
|
|
Write-Host "[Wait-VMReady] Waiting for VM ready (timeout: ${TimeoutSeconds}s, IP: $IPAddress)..."
|
|
|
|
while ((Get-Date) -lt $deadline) {
|
|
$attempt++
|
|
|
|
# ── Phase 1: VM must be running ─────────────────────────────────────
|
|
# vmrun has no getState; getGuestIPAddress exits non-zero when the VM
|
|
# is not powered on. Native commands don't throw — check exit code only.
|
|
& $VmrunPath getGuestIPAddress $VMPath 2>&1 | Out-Null
|
|
$isRunning = ($LASTEXITCODE -eq 0)
|
|
|
|
if (-not $isRunning) {
|
|
if ($phase -ne 'vmrun-state') {
|
|
$phase = 'vmrun-state'
|
|
}
|
|
if ($lastPhase -ne $phase) {
|
|
Write-Host "[Wait-VMReady] Phase 1/3: waiting for VM to enter running state..."
|
|
$lastPhase = $phase
|
|
}
|
|
Start-Sleep -Seconds $PollIntervalSeconds
|
|
continue
|
|
}
|
|
|
|
# ── Phase 2: Network ping (optional) ───────────────────────────────
|
|
if (-not $SkipPing) {
|
|
$pingOk = Test-Connection -ComputerName $IPAddress -Count 1 -Quiet -ErrorAction SilentlyContinue
|
|
|
|
if (-not $pingOk) {
|
|
$phase = 'ping'
|
|
if ($lastPhase -ne $phase) {
|
|
Write-Host "[Wait-VMReady] Phase 2/3: VM running, waiting for network (ping $IPAddress)..."
|
|
$lastPhase = $phase
|
|
}
|
|
Start-Sleep -Seconds $PollIntervalSeconds
|
|
continue
|
|
}
|
|
}
|
|
|
|
# ── Phase 3: WinRM responsive ────────────────────────────────────────
|
|
try {
|
|
Test-WSMan -ComputerName $IPAddress -ErrorAction Stop | Out-Null
|
|
# Success — VM is ready
|
|
Write-Host "[Wait-VMReady] VM ready after ~$([int]($attempt * $PollIntervalSeconds))s (attempt $attempt)."
|
|
return
|
|
}
|
|
catch {
|
|
$phase = 'winrm'
|
|
if ($lastPhase -ne $phase) {
|
|
Write-Host "[Wait-VMReady] Phase 3/3: ping OK, waiting for WinRM on port 5985..."
|
|
$lastPhase = $phase
|
|
}
|
|
Start-Sleep -Seconds $PollIntervalSeconds
|
|
continue
|
|
}
|
|
}
|
|
|
|
throw "[Wait-VMReady] Timed out after ${TimeoutSeconds}s waiting for VM at $IPAddress to become ready. Last phase: $phase"
|