The other morning I was reviewing my hyper-v estate for VM’s running with VHD’s in the legacy VHD format. I thought to myself that a script to convert all of the VHD’s but also taking in several other important steps such as shutting down the VM, optimising the new VHDX, shrink the VHD (where possible), connecting the new VHDX and starting the machine would be nice.
The result is the below script, which only requires the name of your cluster. Once this is specified the script will connect to each of your cluster hosts in sequence, get a list of VM’s with VHD’s and proceed with the conversion process.
There is a section within the script which you can uncomment (AT YOUR OWN RISK) to remove the legacy VHD disks post conversion. As always make sure you have backup’s, allow for downtime and also make sure you have sufficient space on your LUN’s to facilitate the conversion process. The scripts are provided as is and without support.
Cluster Script :
$Cluster = "ENTER CLUSTER NAME IN HERE" $HVNodes = Get-ClusterNode -Cluster $Cluster ForEach ($HVNode in $HVNodes) { $HVPS = New-PSSession -ComputerName $HVNode Write-Host "" Write-Host "===========================================================" Write-Host "Connecting to $HVNode to read VM settings" Write-Host "===========================================================" Write-Host "" Invoke-Command -Session $HVPS -ScriptBlock { ForEach ($VM in (Get-VM)){ $VMName = $VM.name $VMDetails = Get-VM -Name $VMName | Select-Object VMID | get-vhd | Where-Object {$_.vhdFormat -eq "VHD"} If($VMStatus.State -eq "Running"){ Write-Host "" Write-Host -ForegroundColor Red "===========================================================" Write-Host "Stopping VM $VMName" Write-Host -ForegroundColor Red "===========================================================" Write-Host "" Stop-VM -VMName $VMName } ForEach ($VHD in $VMDetails){ $VMVHDDetails = $VHD.Path $VMStatus = Get-VM -name $VMName Write-Host "" Write-Host "===========================================================" Write-Host "Beginning VHD conversion process for VM $VMName" Write-Host "===========================================================" Write-Host "" ForEach ($VHD in $VMVHDDetails){ $NewVHD = ($VHD + "x") if(!(Test-Path $NewVHD)) { Write-Host "" Write-Host "Step 1." Write-Host -ForegroundColor Green "Converting $VHD to fixed VHDX format" Convert-VHD -Path $VHD -DestinationPath $NewVHD -VHDType Fixed -verbose sleep 10 Write-Host "" Write-Host "Step 2." Write-Host -ForegroundColor Green "Changing $NewVHD Sector Size (4096k)" Set-VHD -Path $NewVHD -PhysicalSectorSize 4096 sleep 10 Write-Host "" Write-Host "Step 3." Write-Host -ForegroundColor Green "Modifying VM Settings To Use $NewVHD" Get-VMHardDiskDrive -VMName $VMName | Where-object {$_.path -eq "$VHD"} | Set-VMHardDiskDrive -Path $NewVHD #sleep 10 Write-Host "" Write-Host "Step 4." Write-Host -ForegroundColor Cyan "Shrinking VHDX to minimal file size" Resize-VHD -Path $NewVHD -ToMinimumSize #Uncomment this section if you wish to remove the old VHD drives post conversion. DO SO AT YOUR OWN RISK #Write-Host "" #Write-Host "Step 5." #Write-Host -ForegroundColor Red "Removing old VHD" #Remove-VHHardDiskDrive $VHD #sleep 10 Write-Host "" } Else { Write-Host -ForegroundColor Gray "Skipping $VHD as virtual disk already exists in the target location" } } Write-Host "" Write-Host -ForegroundColor Green "===========================================================" Write-Host "Starting VM $VMName" Write-Host -ForegroundColor Green "===========================================================" Write-Host "" Start-VM -VMName $VMName } } } }
Cluster Script (With minimal screen feedback):
$Cluster = "Enter your cluster name here" $HVNodes = Get-ClusterNode -Cluster $Cluster ForEach ($HVNode in $HVNodes) { $HVPS = New-PSSession -ComputerName $HVNode Write-Host "" Write-Host "Checking $HVNode" Invoke-Command -Session $HVPS -ScriptBlock { ForEach ($VM in (Get-VM)){ $VMName = $VM.name $VMDetails = Get-VM -Name $VMName | Select-Object VMID | get-vhd | Where-Object {$_.vhdFormat -eq "VHD"} If($VMStatus.State -eq "Running"){ Write-Host "Stopping $VMName" Write-Host "" Stop-VM -VMName $VMName } ForEach ($VHD in $VMDetails){ $VMVHDDetails = $VHD.Path $VMStatus = Get-VM -name $VMName Write-Host "" Write-Host "Beginning VHD conversion process for VM $VMName" ForEach ($VHD in $VMVHDDetails){ $NewVHD = ($VHD + "x") if(!(Test-Path $NewVHD)) { Write-Host "" Write-Host "Converting $VHD to fixed VHDX format" Convert-VHD -Path $VHD -DestinationPath $NewVHD -VHDType Fixed -verbose sleep 10 Write-Host "Changing $NewVHD Sector Size" Set-VHD -Path $NewVHD -PhysicalSectorSize 4096 sleep 10 Write-Host "Modifying VM Settings To Use $NewVHD" Get-VMHardDiskDrive -VMName $VMName| Where-object {$_.path -eq "$VHD"} | Set-VMHardDiskDrive -Path $NewVHD sleep 10 Write-Host "Shrinking VHDX to minimal file size" Resize-VHD -Path $NewVHD -ToMinimumSize #Uncomment this section if you wish to remove the old VHD drives post conversion. DO SO AT YOUR OWN RISK #Write-Host "Removing old VHD" #Remove-VHHardDiskDrive $VHD #sleep 10 Write-Host "" } Else { Write-Host "Skipping $VHD as virtual disk already exists in the target location" } } Start-VM -VM $VMName } } } }
Single Host Script:
ForEach ($VM in (Get-VM)){ $VMName = $VM.name $VMDetails = Get-VM -Name $VMName | Select-Object VMID | get-vhd | Where-Object {$_.vhdFormat -eq "VHD"} ForEach ($VHD in $VMDetails){ $VMVHDDetails = $VHD.Path $VMStatus = Get-VM -name $VMName If($VMStatus.State -eq "Running"){ Write-Host "Stopping $VMName" Stop-VM -VMName $VMName } ForEach ($VHD in $VMVHDDetails){ $NewVHD = ($VHD + "x") if(!(Test-Path $NewVHD)) { Write-Host "" Write-Host "Converting $VHD to fixed VHDX format" Convert-VHD -Path $VHD -DestinationPath $NewVHD -VHDType Fixed -verbose sleep 10 Write-Host "Changing $NewVHD Sector Size" Set-VHD -Path $NewVHD -PhysicalSectorSize 4096 sleep 10 Write-Host "Modifying VM Settings To Use $NewVHD" Get-VMHardDiskDrive -VMName $VMName | Where-object {$_.path -eq "$VHD"} | Set-VMHardDiskDrive -Path $NewVHD sleep 10 Write-Host "Shrinking VHDX to minimal file size" Resize-VHD -Path $NewVHD -ToMinimumSize #Uncomment this section if you wish to remove the old VHD drives post conversion. DO SO AT YOUR OWN RISK #Write-Host "Removing old VHD" #Remove-VHHardDiskDrive $VHD sleep 10 Write-Host "" } Else { Write-Host "Skipping $VHD as virtual disk already exists in the target location" } } Start-VM -VM $VMName } }
Reblogged this on Alan Doran IT Ramblings.
Nice. If I may make some suggestions, use a Foreground color with Write-Host so it is clear what are messages and what is output. Even better would be to use Write-Progress. You could also use cmdlet binding and support shouldProcess which would let you use -WhatIf with your script.
Thanks for the feedback Jeffery, much appreciated. I did originally include foreground colour outputs on the various stages but I removed them in an attempt to be as clean as possible but I take your point. I’ll throw up a modified version later which provides better feedback to the user.