Files
awoooi/scripts/reboot-recovery/windows99-vmware-autostart.ps1
Your Name c6ec7a3b71
Some checks failed
CD Pipeline / workflow-shape (push) Successful in 0s
CD Pipeline / cancel-stale-cd (push) Has been skipped
CD Pipeline / build-and-deploy (push) Has been cancelled
CD Pipeline / post-deploy-checks (push) Has been cancelled
CD Pipeline / tests (push) Has been cancelled
fix(recovery): detect all-host reboot recovery gaps
2026-06-30 18:21:56 +08:00

163 lines
5.6 KiB
PowerShell

param(
[ValidateSet("Verify", "DryRun", "Apply")]
[string]$Mode = "Verify",
[string]$VmrunPath = "C:\Program Files (x86)\VMware\VMware Workstation\vmrun.exe",
[string]$Host111Vmx = "",
[string]$Host188Vmx = "",
[string]$Host120Vmx = "",
[string]$Host121Vmx = "",
[string]$Host112Vmx = "",
[string[]]$DiscoveryRoot = @("D:\VMs", "E:\VMs", "C:\VMs", "C:\Users\Public\Documents\Virtual Machines")
)
$ErrorActionPreference = "Stop"
$TaskName = "AWOOOI-Start-VMware-VMs"
$ProgramDataDir = "C:\ProgramData\AWOOOI"
$StartScript = Join-Path $ProgramDataDir "Start-AWOOOI-VMs.ps1"
$VmOrder = @("111", "188", "120", "121", "112")
$SuppliedVmx = @{
"111" = $Host111Vmx
"188" = $Host188Vmx
"120" = $Host120Vmx
"121" = $Host121Vmx
"112" = $Host112Vmx
}
function Resolve-VmxPath {
param([string]$HostAlias)
$supplied = $SuppliedVmx[$HostAlias]
if ($supplied -and (Test-Path -LiteralPath $supplied)) {
return (Resolve-Path -LiteralPath $supplied).Path
}
foreach ($root in $DiscoveryRoot) {
if (-not (Test-Path -LiteralPath $root)) {
continue
}
$match = Get-ChildItem -LiteralPath $root -Recurse -Filter "*.vmx" -ErrorAction SilentlyContinue |
Where-Object { $_.FullName -match "(^|[\\_\-\s])$HostAlias([\\_\-\s]|$)" } |
Select-Object -First 1
if ($match) {
return $match.FullName
}
}
return ""
}
function Get-VmMap {
$map = [ordered]@{}
foreach ($alias in $VmOrder) {
$map[$alias] = Resolve-VmxPath -HostAlias $alias
}
return $map
}
function Write-StartupScript {
param([hashtable]$VmMap)
New-Item -ItemType Directory -Path $ProgramDataDir -Force | Out-Null
$vmRows = foreach ($alias in $VmOrder) {
" @{ Alias = `"$alias`"; Path = `"$($VmMap[$alias])`" }"
}
$body = @"
`$ErrorActionPreference = "Continue"
`$VmrunPath = "$VmrunPath"
`$VMs = @(
$($vmRows -join ",`n")
)
Start-Service -Name "VMAuthdService" -ErrorAction SilentlyContinue
Start-Service -Name "VMnetDHCP" -ErrorAction SilentlyContinue
Start-Service -Name "VMware NAT Service" -ErrorAction SilentlyContinue
Start-Sleep -Seconds 30
foreach (`$vm in `$VMs) {
if (-not (Test-Path -LiteralPath `$vm.Path)) {
Write-Output "VMX_MISSING alias=`$(`$vm.Alias) path=`$(`$vm.Path)"
continue
}
& `$VmrunPath -T ws start `$vm.Path nogui
Write-Output "VM_START_REQUESTED alias=`$(`$vm.Alias) path=`$(`$vm.Path) exit=`$LASTEXITCODE"
Start-Sleep -Seconds 20
}
"@
Set-Content -LiteralPath $StartScript -Value $body -Encoding UTF8
}
function Apply-WindowsUpdatePolicy {
$auPath = "HKLM:\SOFTWARE\Policies\Microsoft\Windows\WindowsUpdate\AU"
New-Item -Path $auPath -Force | Out-Null
New-ItemProperty -Path $auPath -Name "NoAutoRebootWithLoggedOnUsers" -Value 1 -PropertyType DWord -Force | Out-Null
New-ItemProperty -Path $auPath -Name "AlwaysAutoRebootAtScheduledTime" -Value 0 -PropertyType DWord -Force | Out-Null
New-ItemProperty -Path $auPath -Name "AUOptions" -Value 3 -PropertyType DWord -Force | Out-Null
New-ItemProperty -Path $auPath -Name "ScheduledInstallDay" -Value 0 -PropertyType DWord -Force | Out-Null
New-ItemProperty -Path $auPath -Name "ScheduledInstallTime" -Value 3 -PropertyType DWord -Force | Out-Null
New-ItemProperty -Path $auPath -Name "AUPowerManagement" -Value 0 -PropertyType DWord -Force | Out-Null
}
function Apply-ScheduledTask {
$action = New-ScheduledTaskAction `
-Execute "powershell.exe" `
-Argument "-NoProfile -ExecutionPolicy Bypass -File `"$StartScript`""
$trigger = New-ScheduledTaskTrigger -AtStartup
$principal = New-ScheduledTaskPrincipal -UserId "SYSTEM" -RunLevel Highest
$settings = New-ScheduledTaskSettingsSet `
-AllowStartIfOnBatteries `
-DontStopIfGoingOnBatteries `
-MultipleInstances IgnoreNew `
-RestartCount 3 `
-RestartInterval (New-TimeSpan -Minutes 2) `
-StartWhenAvailable
Register-ScheduledTask `
-TaskName $TaskName `
-Action $action `
-Trigger $trigger `
-Principal $principal `
-Settings $settings `
-Force | Out-Null
}
$vmMap = Get-VmMap
$missing = @($VmOrder | Where-Object { -not $vmMap[$_] })
$vmrunPresent = Test-Path -LiteralPath $VmrunPath
Write-Output "AWOOOI_WINDOWS99_VMWARE_AUTOSTART=1"
Write-Output "MODE=$Mode"
Write-Output "VMRUN_PRESENT=$([int]$vmrunPresent)"
foreach ($alias in $VmOrder) {
Write-Output "VMX alias=$alias path=$($vmMap[$alias]) present=$([int][bool]$vmMap[$alias])"
}
if (-not $vmrunPresent) {
Write-Error "vmrun.exe not found at $VmrunPath"
}
if ($missing.Count -gt 0) {
Write-Output "MISSING_VMX_ALIASES=$($missing -join ',')"
if ($Mode -eq "Apply") {
throw "Apply requires explicit or discoverable VMX paths for every required VM."
}
}
if ($Mode -eq "Verify") {
exit 0
}
if ($Mode -eq "DryRun") {
Write-Output "DRY_RUN would_write_start_script=$StartScript"
Write-Output "DRY_RUN would_register_task=$TaskName"
Write-Output "DRY_RUN would_apply_windows_update_no_auto_reboot_policy=1"
exit 0
}
Write-StartupScript -VmMap $vmMap
Set-Service -Name "VMAuthdService" -StartupType Automatic -ErrorAction SilentlyContinue
Set-Service -Name "VMnetDHCP" -StartupType Automatic -ErrorAction SilentlyContinue
Set-Service -Name "VMware NAT Service" -StartupType Automatic -ErrorAction SilentlyContinue
Apply-ScheduledTask
Apply-WindowsUpdatePolicy
Write-Output "APPLIED scheduled_task=$TaskName start_script=$StartScript windows_update_no_auto_reboot_policy=1"