Private/New-Win32ToolkitHyperVSession.ps1

function New-Win32ToolkitHyperVSession {
    <#
    .SYNOPSIS
        Reverts the test VM to its warm checkpoint and opens a PowerShell Direct session to it.
    .DESCRIPTION
        The Hyper-V backend's "initialize" step. Restores the standard (memory-state) checkpoint — which
        returns the guest to a running, logged-in desktop with no boot — waits until PowerShell Direct is
        reachable, and returns an open PSSession for the run. HOST-ONLY (Hyper-V + elevation).
        See knowledge-base/designs/hyperv-backend-plan.md.
    .PARAMETER VMName
        The test VM name.
    .PARAMETER Credential
        The guest local-admin credential (PowerShell Direct).
    .PARAMETER CheckpointName
        The warm checkpoint to revert to (default 'clean-base').
    .PARAMETER SkipRevert
        Connect to the VM as-is without reverting (e.g. when it is already clean).
    .OUTPUTS
        A PSSession (System.Management.Automation.Runspaces.PSSession).
    #>

    [CmdletBinding()]
    [OutputType([object])]
    param(
        [Parameter(Mandatory)] [ValidateNotNullOrEmpty()] [string]$VMName,
        [Parameter(Mandatory)] [ValidateNotNull()]        [pscredential]$Credential,
        [string]$CheckpointName = 'clean-base',
        [switch]$SkipRevert,

        # Interactive GUI runs need a real logged-in desktop; if the checkpoint landed on the login
        # screen, recover by rebooting to trigger AutoLogon (Confirm-Win32ToolkitGuestDesktop).
        [switch]$EnsureDesktop
    )

    if (-not $SkipRevert) {
        # Skip the open-revert only when THIS process verified a teardown revert of the SAME VM+checkpoint
        # moments ago (Remove-Win32ToolkitHyperVSession stamps $script:HyperVCleanMarker strictly AFTER a
        # successful restore; every VM-management cmdlet clears it). Back-to-back runs in one pipeline
        # otherwise revert twice with zero use in between. Fail-safe by construction: no marker, any
        # mismatch, or age > 10 min ⇒ revert exactly as before. The marker is deliberately PROCESS-LOCAL —
        # VM Notes have untested survive/erase semantics across a Standard-checkpoint restore, and
        # uptime/state checks detect nothing (a memory-state revert leaves the VM continuously Running).
        $m = $script:HyperVCleanMarker
        $markerFresh = $m -and ($m.VMName -eq $VMName) -and ($m.CheckpointName -eq $CheckpointName) -and
                       (((Get-Date) - $m.StampedAt).TotalMinutes -lt 10)
        if ($markerFresh) {
            Write-Verbose "'$VMName' was left verified-clean at '$CheckpointName' by this process — skipping the redundant open-revert."
        }
        else {
            Restore-VMCheckpoint -VMName $VMName -Name $CheckpointName -Confirm:$false -ErrorAction Stop
        }
    }
    # From here the VM is in use — it can no longer be presumed clean, whatever happens to this run.
    $script:HyperVCleanMarker = $null

    if ((Get-VM -Name $VMName -ErrorAction Stop).State -ne 'Running') {
        # A Standard (memory-state) checkpoint restores a RUNNING guest; landing here means the checkpoint
        # was taken powered-off or as a Production checkpoint — every run is paying a full boot.
        Write-Warning "VM '$VMName' was not Running after restoring '$CheckpointName' — the checkpoint is not a warm memory-state one, so every run pays a full boot. Re-take it with the VM running at a logged-in desktop (Standard checkpoint type) to restore warm-revert speed."
        Start-VM -Name $VMName -ErrorAction Stop
    }

    # Warm revert returns a running, logged-in guest; -SkipPrep because the golden image already set the
    # execution policy. The desktop check runs BEFORE the session is created: its recovery path REBOOTS
    # the guest, which would kill a session opened earlier — the returned session must postdate any reboot.
    if ($EnsureDesktop) {
        Wait-Win32ToolkitVMReady -VMName $VMName -Credential $Credential -SkipPrep | Out-Null
        if (-not (Confirm-Win32ToolkitGuestDesktop -VMName $VMName -Credential $Credential)) {
            Write-Warning 'Could not reach an interactive desktop even after a recovery reboot. Is guest AutoLogon configured (Set-Win32ToolkitGuestAutoLogon)? The PSADT GUI may not render — use -Unattended / Silent, or re-checkpoint a logged-in desktop.'
        }
    }

    # -ReturnSession: the connection that proves PowerShell Direct IS the run's session (the old shape
    # proved readiness with a throwaway ad-hoc connection, then built another session — 1-3 s wasted).
    return (Wait-Win32ToolkitVMReady -VMName $VMName -Credential $Credential -SkipPrep -ReturnSession)
}