I was reading a thread at Facebook in our user group, someone was trying to compress/compact/optimize a VHD(VHDX files but the result was depressing, the amount of reclaimed space was zero and that is kind of low… Now there is a good explanation for that, when using the UI there is no way to configure it and the UI also don’t inform you that the ONLY way to get it small is to mount it in Read Only mode. It really has to be mounted, otherwise there is now way to see “inside” the disk and to get rid of all the Zero blocks. It does not hurt if you also run defrag and cleanup inside the VM before, but the most important thing is that it needs to be mounted.
The documentation for the PowerShell command says:
The Script:
So, to make things easy for my friends in the User Group I created a simple script that will find the disks for the VM, check if the VM is running and if not mount each file in read only mode with no drive letter, optimize the VDH and dismount it. So the output of the script looks like this when running using –verbose
and here is how the script looks like:
and you can download the script here…http://1drv.ms/1IES3pB
/mike
Categories: Hyper-V, PowerShell
This doesn’t seem to work if the VM has a snapshot.
Hi Mike,
Nice PowerShell Script, very much needed.
Works nice but have two questions:
“It does not hurt if you also run defrag and cleanup inside the VM before”
This seems to be a must to be able to shrink volumes.
1. Is there a way to perform a defrag as well from Powershell when the VM is shutdown (in this script), or how is this solved in the real life?
2. I have modified the script so I have a TXT file that have all the VMnames in it, but is there a way to put the “-Verbose” parameter from the “command line” into the script instead?
If you always want the output to be written, change write-verbose to write-host
Hi Memphisrayz,
Worked Great, Thanks!!!
I will test your code below as soon as I can!
Is there no way to perform the Defrag of the VHD aswell?
I know this is now bit of an old article but I have issues with a lot of the objects not existing.
I made a few changes so this can also be run from the System Center host for a clustered environment.
Hope it is able to help someone else out.
#Dont put any code above this Commandlet
[CmdletBinding()]
Param(
$VMnames
)
Import-Module hyper-v
Import-Module virtualmachinemanager
foreach($VMname in $VMnames){
#Check if VM is running
Write-host “Checking $VMname”
if((Get-VM -Name $VMname).VirtualMachineState -eq “PowerOff” -and (Get-VMCheckpoint -VM $VMname) -eq $null){
$VMHost = (Get-VM -Name $VMname).HostName
#Find the disks
foreach($VHD in ((Get-SCVirtualHardDisk -VM $VMname).Location)){
$arguments = @($VHD)
Write-host “Working on $VHD, please wait”
$VHDFileSize = Invoke-Command -ComputerName $VMHost -ArgumentList $arguments -ScriptBlock {Param($VHD) (Get-VHD -Path $VHD).FileSize/ 1GB}
Write-host “Current size $([math]::truncate($($VHDFileSize))) GB”
Invoke-Command -ComputerName $VMHost -ArgumentList $arguments -ScriptBlock {Param($VHD) Mount-VHD -Path $VHD -NoDriveLetter -ReadOnly}
Invoke-Command -ComputerName $VMHost -ArgumentList $arguments -ScriptBlock {Param($VHD) Optimize-VHD -Path $VHD -Mode Full}
$VHDFileSize = Invoke-Command -ComputerName $VMHost -ArgumentList $arguments -ScriptBlock {Param($VHD) (Get-VHD -Path $VHD).FileSize/ 1GB}
Write-host “Optimize size $([math]::truncate($($VHDFileSize))) GB”
Invoke-Command -ComputerName $VMHost -ArgumentList $arguments -ScriptBlock {Param($VHD) Dismount-VHD -Path $VHD}
Write-host “If size has not changed please run a disk defrag”
Write-host “”
}
}
else{Write-Warning “$VMname is not turned off or has a snapshot, will not be fixed”
Write-host “”}
}
How can I achieve this without shutting the VM down, if I move the VM to another Cluster Shared Volume it releases the white space…..so if this cant be achieved without shutting down, anyone got a good script to report on white space (the difference between used space in a VM and VHD size)?
Visit this site again, at 2.01 PM and you will have a very shiny script that grabs data about every VHD file in your SCVMM environment, let me know if you don’t use SCVMM and I’ll write a new function that does the same thing but directly for Hyper-V
We do use SCVMM so would greatly appreciate!
Great!, It will be published soon…
https://deploymentbunny.com/2016/11/25/working-in-the-datacenter-i-need-to-know-everything-about-my-vhds-in-my-scvmm-environment/
Sorry I need to backtrack, can you show the function just directly for Hyper-V?
Thank you!
I need to re-write it, but sure, i’ll work on that