Invoke-VMPilotCloudCleanup.ps1
|
<# .SYNOPSIS Removes a device's Intune, Windows Autopilot, and Entra ID records, keyed on BIOS serial number, using Mark Orr's AutopilotCleanup module (PSGallery). .DESCRIPTION Called by VM-Pilot's VM Cleanup dialog when "Also remove tenant records" is ticked, so deleting a local Hyper-V VM also offboards the cloud identity it enrolled. It hands the serial(s) straight to the module's own orchestrator, Invoke-AutopilotCleanup, rather than calling the low-level Remove-* functions itself. That matters: the orchestrator resolves each serial across all three services (Autopilot -> Intune by serial -> Entra ID by the Autopilot record's Azure AD Device ID), deletes them in the dependency-safe order, and then runs its monitoring loop in the terminal ("Waiting for 1 of 1 to be removed from Intune... removed... Autopilot... Entra ID..."). Driving the Remove-* verbs directly does NOT delete from Entra (that function needs the resolved device object, not a serial) and skips the monitoring, which is why this defers to Invoke-AutopilotCleanup. Requires PowerShell 7+ (the AutopilotCleanup manifest pins PowerShellVersion 7.0), so the GUI launches this in a pwsh child window. At the module's action menu, choose [1] Remove records only - the VM is being destroyed locally, so there is nothing to wipe. .EXAMPLE pwsh -File .\Invoke-VMPilotCloudCleanup.ps1 -SerialNumber '1234-5678-...' .EXAMPLE # Preview (WhatIf): resolves and reports what would be deleted, deletes nothing. pwsh -File .\Invoke-VMPilotCloudCleanup.ps1 -SerialNumber 'A','B' -Preview #> [CmdletBinding()] param( [Parameter(Mandatory)] [string[]]$SerialNumber, # Preview only: forwards -WhatIf to Invoke-AutopilotCleanup so nothing is deleted. [switch]$Preview ) $ErrorActionPreference = 'Stop' # --- PowerShell 7 gate -------------------------------------------------- # The AutopilotCleanup module manifest requires PowerShellVersion 7.0. The GUI # resolves pwsh before enabling the cloud-cleanup option, but guard here too so # a manual run under 5.1 fails clearly instead of on an obscure import error. if ($PSVersionTable.PSVersion.Major -lt 7) { Write-Host "This cleanup requires PowerShell 7+ (pwsh). Current: $($PSVersionTable.PSVersion)" -ForegroundColor Red Read-Host "Press Enter to close" exit 2 } # Normalize: trim, drop blanks, de-dupe. $serials = $SerialNumber | ForEach-Object { "$_".Trim() } | Where-Object { $_ } | Select-Object -Unique if (-not $serials) { Write-Host "No serial numbers supplied - nothing to remove." -ForegroundColor Yellow Read-Host "Press Enter to close" exit 0 } Write-Host "" Write-Host "VM-Pilot - Tenant record cleanup (Intune / Autopilot / Entra ID)" -ForegroundColor Cyan Write-Host ("Devices ({0}): {1}" -f $serials.Count, ($serials -join ', ')) if ($Preview) { Write-Host "PREVIEW MODE - nothing will be deleted." -ForegroundColor Yellow } Write-Host "" Write-Host "At the action menu below, choose [1] Remove records only." -ForegroundColor Yellow Write-Host "(The VM is being deleted locally, so there is no need to wipe.)" -ForegroundColor DarkGray Write-Host "" # --- Ensure the AutopilotCleanup module --------------------------------- if (-not (Get-Module -ListAvailable -Name AutopilotCleanup)) { Write-Host "Installing AutopilotCleanup module from PSGallery (first run)..." -ForegroundColor Yellow try { [Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12 if (-not (Get-PackageProvider -Name NuGet -ErrorAction SilentlyContinue)) { Install-PackageProvider -Name NuGet -MinimumVersion 2.8.5.201 -Scope CurrentUser -Force | Out-Null } Install-Module AutopilotCleanup -Scope CurrentUser -Force -AllowClobber -ErrorAction Stop } catch { Write-Host "Failed to install AutopilotCleanup: $($_.Exception.Message)" -ForegroundColor Red Read-Host "Press Enter to close" exit 3 } } Import-Module AutopilotCleanup -Force -ErrorAction Stop # --- Hand off to the module's monitored flow ---------------------------- # Invoke-AutopilotCleanup connects to Graph (interactive sign-in, Intune admin # required), enriches each serial across all three services, deletes, and then # monitors removal in this terminal until each service confirms the record is # gone. -WhatIf drives its preview path. try { if ($Preview) { Invoke-AutopilotCleanup -SerialNumber $serials -WhatIf } else { Invoke-AutopilotCleanup -SerialNumber $serials } } catch { Write-Host "" Write-Host "Cleanup failed: $($_.Exception.Message)" -ForegroundColor Red Read-Host "Press Enter to close" exit 4 } Write-Host "" Read-Host "Press Enter to close" |