Reset-VMPilot.ps1
|
<#
.SYNOPSIS Wipes VM-Pilot state so the next run exercises the full pipeline from zero. .DESCRIPTION Removes: - All Hyper-V VMs except a known "keep" list (your pre-existing VMs). - Their C:\VMs\<name>\ folders. - Every cached parent VHDX (C:\VMs\Win11-*.vhdx -- one per release). - The cached community AutoPilot script (C:\Tools\VMPilot\...), left behind by VM-Pilot 0.5.0 and earlier. Current versions install the import GUI from PSGallery inside the VM and cache nothing on the host. Optionally also removes the cached Windows install media (forces a fresh ~5 GB download on the next run -- omit -ResetISO unless you specifically want to test that path). Self-elevates to Administrator. Prompts for confirmation before destroying anything (skip with -Force). .PARAMETER ResetISO Also delete the cached Windows install media under C:\Tools\WinVHDX so the next run re-downloads it. Adds ~10-30 min depending on connection. The builder names its download after Microsoft's catalog entry (a long .esd filename), so this matches on extension rather than a fixed name -- which also catches ISOs cached by older VM-Pilot versions. .PARAMETER Force Skip the interactive confirmation prompt. Useful for scripted CI. .PARAMETER Keep Array of VM names to preserve. Default keeps the pre-existing VMs from the original test environment. Pass your own list to override. .EXAMPLE PS> .\Reset-VMPilot.ps1 Wipes all session VMs + parent VHDX + cached community script. Asks first. .EXAMPLE PS> .\Reset-VMPilot.ps1 -ResetISO -Force Full nuke including the ISO. No confirmation. Next launch downloads everything from scratch. .EXAMPLE PS> .\Reset-VMPilot.ps1 -Keep @('APT','MORR','MyImportantVM') Override the preserve list. .LINK https://github.com/markorr321/VM-Pilot #> [CmdletBinding()] param( [Alias('ResetMedia')] [switch]$ResetISO, [switch]$Force, [string[]]$Keep = @( 'APT','AutopilotTest','AutopilotTest-01','AutopilotTest-02', 'MHO','MHO-24H2-0502-6368','MORR' ) ) # ----- Self-elevate ----- if (-not ([Security.Principal.WindowsPrincipal][Security.Principal.WindowsIdentity]::GetCurrent()).IsInRole([Security.Principal.WindowsBuiltInRole]::Administrator)) { Write-Host 'Elevating to Administrator...' -ForegroundColor Yellow $psExe = if ($PSVersionTable.PSEdition -eq 'Core') { 'pwsh.exe' } else { 'powershell.exe' } $argList = @('-NoExit','-ExecutionPolicy','Bypass','-File',"`"$PSCommandPath`"") if ($ResetISO) { $argList += '-ResetISO' } if ($Force) { $argList += '-Force' } Start-Process $psExe -ArgumentList $argList -Verb RunAs return } $separator = '=' * 70 # ----- Known paths ----- # One parent VHDX per Windows release (Win11-25H2.vhdx, Win11-24H2.vhdx, ...), # so glob rather than naming a single file. $parentVhdx = @(Get-ChildItem -Path 'C:\VMs\Win11-*.vhdx' -File -ErrorAction SilentlyContinue) $communityCache = 'C:\Tools\VMPilot\Get-WindowsAutopilotInfoCommunity.ps1' $mediaDir = 'C:\Tools\WinVHDX' # The builder's download is named by Microsoft's catalog (e.g. # 26200.8653.<...>_CLIENTCONSUMER_RET_x64FRE_en-us.esd), so glob by extension. # *.iso also sweeps up media cached by VM-Pilot's older Fido-based builder. $mediaCache = @(Get-ChildItem -Path $mediaDir -File -Include '*.esd','*.iso' -Recurse -ErrorAction SilentlyContinue) # ----- Inventory ----- Write-Host "`n$separator" -ForegroundColor Cyan Write-Host ' VM-Pilot Reset - inventory' -ForegroundColor Cyan Write-Host "$separator" -ForegroundColor Cyan $victims = @(Get-VM | Where-Object { $_.Name -notin $Keep }) Write-Host "`nVMs to REMOVE:" -ForegroundColor Yellow if ($victims.Count -eq 0) { Write-Host ' (none)' -ForegroundColor DarkGray } else { $victims | ForEach-Object { " - {0,-30} {1}" -f $_.Name, $_.State } } Write-Host "`nVMs to KEEP:" -ForegroundColor Green $kept = @(Get-VM | Where-Object { $_.Name -in $Keep }) if ($kept.Count -eq 0) { Write-Host ' (none in keep list exist)' -ForegroundColor DarkGray } else { $kept | ForEach-Object { " - {0,-30} {1}" -f $_.Name, $_.State } } Write-Host "`nFiles to delete:" -ForegroundColor Yellow $fileActions = @() foreach ($v in $parentVhdx) { $fileActions += $v.FullName; Write-Host " - $($v.FullName)" } if (Test-Path $communityCache) { $fileActions += $communityCache; Write-Host " - $communityCache" } if ($ResetISO) { foreach ($m in $mediaCache) { $fileActions += $m.FullName Write-Host (" - {0} (~{1:N1} GB)" -f $m.FullName, ($m.Length / 1GB)) -ForegroundColor Red } } if ($fileActions.Count -eq 0) { Write-Host ' (none)' -ForegroundColor DarkGray } # ----- Confirm ----- if (-not $Force) { Write-Host "`nThis cannot be undone." -ForegroundColor Red $ans = Read-Host 'Type YES to proceed' if ($ans -ne 'YES') { Write-Host 'Aborted.' -ForegroundColor Yellow return } } # ----- Remove VMs ----- foreach ($vm in $victims) { $n = $vm.Name Write-Host "Removing VM '$n'..." -ForegroundColor Yellow Stop-VM -Name $n -TurnOff -Force -ErrorAction SilentlyContinue Remove-VM -Name $n -Force -ErrorAction SilentlyContinue Remove-Item -LiteralPath "C:\VMs\$n" -Recurse -Force -ErrorAction SilentlyContinue } # ----- Remove cached files ----- foreach ($f in $fileActions) { Write-Host "Deleting $f..." -ForegroundColor Yellow Remove-Item -LiteralPath $f -Force -ErrorAction SilentlyContinue } # ----- Verify ----- Write-Host "`n$separator" -ForegroundColor Cyan Write-Host ' Done. Current state:' -ForegroundColor Cyan Write-Host "$separator" -ForegroundColor Cyan Write-Host "`nVMs remaining:" -ForegroundColor Green Get-VM | Sort-Object Name | Format-Table Name, State, Uptime -AutoSize Write-Host 'Cache file presence:' -ForegroundColor Green $vhdxLeft = @(Get-ChildItem -Path 'C:\VMs\Win11-*.vhdx' -File -ErrorAction SilentlyContinue) " parent VHDX : $(if ($vhdxLeft.Count) { ($vhdxLeft.Name -join ', ') } else { 'False' })" " community PS : $(Test-Path $communityCache)" $remaining = @(Get-ChildItem -Path $mediaDir -File -Include '*.esd','*.iso' -Recurse -ErrorAction SilentlyContinue) " Windows media: $(if ($remaining.Count) { "$($remaining.Count) file(s) in $mediaDir" } else { 'False' })" Write-Host "`nReady for a clean VM-Pilot run." -ForegroundColor Green |