Last year I wrote a script that would allow you to specify a virtual machine, and the script would:
- Shut down the VM if running
- Seek out any VHD files attached to any of the VM’s controllers
- Create VHDX files from those VHD files
- Replace the VHD files by attaching the VHDX files to the same controllers and locations in the VM settings
- Delete the VHD files
In my tests, the script had some issues. But that was nearly a year ago and it was on WS2012 in my lab. The script remained untouched until yesterday. I was chatting with my fellow Hyper-V MVP, Didier Van Hoye (aka @workinghardinit). He told me he was in the process of migrating VMs from an old W2008 R2 cluster to WS2012 and was going to be converting VHD files. Aha! This might be a time for a solution to speed up the process.
I sent the script over to Didier to have a look-see. Would it work. Well, Didier ran a series of tests this morning with guest OSs including W2003 R2 and WS2012. The tests ran flawlessly.
So … here is the script. FYI there are few things to note:
- You might consider putting in a delay loop to test if the VM is actually shut down if you need to shut it down. Put a timeout of 3 minutes in that. The stop-vm cmdlet is async so it shouldn’t cause an issue as it is below, but you might want to take the extra step, just in case.
- You might want to comment out the line Remove-VMHardDiskDrive $VHD for your test or pilot runs.
- I do not support this script 🙂
- Run the script and specify the VM name as a parameter.
CREDIT: A big thank you to Didier Van Hoye (aka @workinghardinit) for checking my work.
#—-
[CmdletBinding ()]
Param (
[Parameter(Mandatory=$True)]
[string]$VMName
)
#Disable error reporting – comment out the following line if you need to troubleshoot the script
$ErrorActionPreference = "SilentlyContinue"
cls
$VM = Get-VM $VMName
$VMStatus = $VM.State
if ($VM.VMid -ne $NULL)
{
if ($VMStatus -eq "Running")
{
#Shut down the VM if it is running
Write-Host "Shutting down" $VMName
Stop-VM $VMName
}
#Get the disks in the VM
$AllVHD = Get-VMHardDiskDrive $VMName
if ($AllVHD -eq $NULL)
{
Write-Host "There are no virtual hard disks to convert"
Exit
}
foreach ($VHD in $AllVHD)
{
#Get the VM path and create a VHDX file path
[string]$VHDFile = Get-Item $VHD.Path
$VHDFormat = (Get-VHD $VHDFile).VhdFormat
if ($VHDFormat -eq "VHD")
{
[string]$VHDXFile = $VHDFile + "x"
[string]$ControllerType = $VHD.ControllerType
[string]$ControllerNumber = $VHD.ControllerNumber
[string]$ControllerLocation = $VHD.ControllerLocation
Write-Host "Converting: " $VHDFile "to" $VHDXFile
Convert-VHD –Path $VHDFile –DestinationPath $VHDXFile
Sleep 10
#Reconfigure the Physical Sector Size of the VHDX file to 4 K
Set-VHD -Path $VHDXFile -PhysicalSectorSizeBytes 4096
Sleep 10
#Remove the old VHD
Write-Host "Removing $VHDFile from $VMName"
Remove-VMHardDiskDrive $VHD
Sleep 10
#Replace the VHD with the VHDX
Write-Host "Adding $VHDXFile to $VMName"
Add-VMHardDiskDrive -VMName $VMName -Path $VHDXFile -ControllerType $ControllerType -ControllerNumber $ControllerNumber -ControllerLocation $ControllerLocation
#Danger Will Robinson – we are going to delete the original VHD – we hope you have a tested VM backup!
Write-Host "Deleting $VHDFile"
Remove-Item $VHDFile -Force
}
else
{
Write-Host "$VHDFile is already a VHDX file: skipping"
}
}
if ($VMStatus -eq "Running")
{
#Restart the VM if it was running before the conversion
Write-Host "Starting" $VMName
Start-VM $VMName
#Wait for 10 seconds
Write-Host "Waiting for 10 seconds to verify the virtual machine …"
Sleep 10
$VMStatus = $VM.State
if ($VMStatus -ne "Running")
{
#Something went wrong
Write-Host "$VMName could not reboot – please restore the VM from backup"
}
}
}
else
{
Write-Host $VMName "does not exist on this host"
Exit
}
Write-Host "Processing of $VMName has completed"
Consider a particular case, in a Windows 8 environment, when you can’t attach a .vhd file to a Hyper-V machine. It just won’t find any .vhds to work, so a version to offline vhds would be handy.
Anyway thank you, great work!
I have no idea what you’re talking about.