How to Force Unmount a VHD in Windows 7 When Standard Methods Fail (C# PowerShell Solutions)


25 views

html

Many Windows 7 developers encounter situations where mounted VHDs refuse to unmount through conventional methods. The Disk Management console provides no explicit unmount option, and the system often incorrectly reports the VHD as being in use when it's actually idle.

When Task Manager shows SYSTEM processes holding handles to your VHD, this typically indicates:

  • Explorer.exe maintaining directory previews
  • Indexing services scanning the volume
  • Antivirus software performing background scans

Try these methods in sequence:

1. Clean ejection through Safe Removal icon
2. Disk Management → Right-click disk → Detach VHD
3. Diskpart command-line utility:
   
diskpart select vdisk file="C:\path\to\your.vhd" detach vdisk

For stubborn VHDs, use this PowerShell script that clears system handles:


# PowerShell VHD Force Unmount Script
$vhdPath = "C:\VMs\problem.vhd"

# Get disk number
$disk = Get-Disk | Where-Object { $_.Location -eq $vhdPath }

if ($disk) {
    # Offline the disk first
    Set-Disk -Number $disk.Number -IsOffline $true
    
    # Dismount using WMI
    $wmiQuery = "SELECT * FROM MSFT_VirtualDisk WHERE Path='$vhdPath'"
    $vhd = Get-CimInstance -Query $wmiQuery -Namespace root\Microsoft\Windows\Storage
    if ($vhd) {
        Remove-VirtualDisk -InputObject $vhd -Confirm:$false
        Write-Host "Successfully force-unmounted $vhdPath"
    }
} else {
    Write-Host "VHD not found or already unmounted"
}

For programmatic solutions in your applications:


// C# example using Windows API
[DllImport("kernel32.dll", SetLastError = true)]
static extern bool CloseHandle(IntPtr hObject);

public static void ForceUnmountVHD(string path)
{
    var handles = FindOpenHandles(path);
    foreach (var handle in handles)
    {
        if (!CloseHandle(handle))
        {
            // Log error using Marshal.GetLastWin32Error()
        }
    }
    
    // Now attempt normal dismount
    Process.Start("diskpart", $"/s unmount_script.txt");
}
  • Mount VHDs as read-only when possible
  • Disable Windows Search indexing on VHD volumes
  • Add VHD folders to antivirus exclusions
  • Use the /noforce option when initially attaching

Many Windows 7 developers encounter this frustrating scenario: you mount a Virtual Hard Disk (VHD) for testing or data access, but when attempting to unmount it, Windows stubbornly claims the device is "in use" despite no apparent active handles. This behavior persists even with the Disk Manager closed and no visible file operations.

The SYSTEM process typically maintains several handles to mounted VHDs for various purposes:

// Sample output from Handle.exe (Sysinternals)
System pid: 4 NT AUTHORITY\SYSTEM
   A0: File          \Device\HarddiskVolume3\VHDs\test.vhd
   B4: File          \Device\HarddiskVolume3\VHDs\test.vhd

Try these methods in sequence when standard ejection fails:

Method 1: Diskpart Force Removal

diskpart
list volume
select volume X (where X is your VHD volume number)
remove all dismount

Method 2: Using PowerShell

$vhdPath = "C:\VHDs\development.vhd"
Dismount-VHD -Path $vhdPath -ErrorAction SilentlyContinue
if ($?) {
    Write-Host "VHD successfully dismounted"
} else {
    Write-Warning "Forcing dismount..."
    Get-Disk | Where-Object {$_.Location -eq $vhdPath} | 
    Set-Disk -IsOffline $true
}

Method 3: Handle Termination

For stubborn cases, use Sysinternals tools:

handle.exe -p System -a vhd | findstr /i "vhd"
for /f "tokens=3" %i in ('handle.exe -p System -a vhd ^| findstr /i "vhd"') do (
    handle.exe -p System -c %i -y
)

Developers working frequently with VHDs should consider:

  • Creating batch scripts for clean unmount sequences
  • Setting VHDs to read-only when possible
  • Monitoring handles with Process Explorer during operations

Here's a complete PowerShell script that combines multiple approaches:

function Force-DismountVHD {
    param (
        [Parameter(Mandatory=$true)]
        [string]$VHDPath
    )
    
    try {
        # Try clean dismount first
        Dismount-VHD -Path $VHDPath -ErrorAction Stop
        return "Clean dismount successful"
    }
    catch {
        Write-Warning "Standard dismount failed, attempting force methods..."
        
        # Offline the disk
        $disk = Get-Disk | Where-Object {$_.Location -eq $VHDPath}
        if ($disk) {
            Set-Disk -Number $disk.Number -IsOffline $true
        }
        
        # Use diskpart as last resort
        $diskpartScript = @"
select vdisk file="$VHDPath"
detach vdisk
"@
        $diskpartScript | diskpart | Out-Null
        
        return "Force dismount completed"
    }
}