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"
}
}