Hyper-V Program Manager
Continuing on with my walk through the storage WMI API - here are some scripts for compacting VHDs with Hyper-V. Note that Hyper-V allows you to compact both differencing and dynamically expanding virtual hard disks.
PowerShell:
# Prompt for the Hyper-V Server to use
$HyperVServer = Read-Host "Specify the Hyper-V Server to use (enter '.' for the local computer)"
# Get name for VHD
$VHDName = Read-Host "Specify the name of the virtual had disk to compact"
# Get the Msvm_ImageManagementService object
$ImageManagementService = gwmi Msvm_ImageManagementService -namespace "root\virtualization" -computername $HyperVServer
# Compact the VHD
$result = $ImageManagementService.CompactVirtualHardDisk($VHDName)
#Return success if the return value is "0"
if ($Result.ReturnValue -eq 0)
{write-host "The virtual hard disk has been compacted."}
#If the return value is not "0" or "4096" then the operation failed
ElseIf ($Result.ReturnValue -ne 4096)
{write-host "The virtual hard disk has not been compacted. Error value:" $Result.ReturnValue}
Else
{#Get the job object
$job=[WMI]$Result.job
#Provide updates if the jobstate is "3" (starting) or "4" (running)
while ($job.JobState -eq 3 -or $job.JobState -eq 4)
{write-host "Compacting. "$job.PercentComplete "% complete"
start-sleep 1
#Refresh the job object
$job=[WMI]$Result.job}
#A jobstate of "7" means success
if ($job.JobState -eq 7)
{write-host "The virtual hard disk has not been compacted."
write-host "ErrorCode:" $job.ErrorCode
write-host "ErrorDescription" $job.ErrorDescription}
}
VBScript:
Option Explicit
Dim HyperVServer
Dim VHDName
Dim WMIService
Dim Msvm_ImageManagementService
Dim Result
Dim Job
Dim InParam
Dim OutParam
'Prompt for the Hyper-V Server to use
HyperVServer = InputBox("Specify the Hyper-V Server to create the virtual machine on:")
'Get name for VHD
VHDName = InputBox("Specify the name of the virtual had disk to compact:")
'Get an instance of the WMI Service in the virtualization namespace.
Set WMIService = GetObject("winmgmts:\\" & HyperVServer & "\root\virtualization")
'Get the Msvm_ImageManagementService object
Set Msvm_ImageManagementService = WMIService.ExecQuery("SELECT * FROM Msvm_ImageManagementService").ItemIndex(0)
'Setup the input parameter list
Set InParam = Msvm_ImageManagementService.Methods_("CompactVirtualHardDisk").InParameters.SpawnInstance_()
InParam.Path = VHDName
'Execute the method and store the results in OutParam
Set OutParam = Msvm_ImageManagementService.ExecMethod_("CompactVirtualHardDisk", InParam)
'Check to see if the job completed synchronously
if (OutParam.ReturnValue = 0) then
Wscript.Echo "The virtual hard disk has been compacted."
elseif (OutParam.ReturnValue <> 4096) then
Wscript.Echo "The virtual hard disk has not been compacted."
else
'Get the job object
set Job = WMIService.Get(OutParam.Job)
'Wait for the job to complete (3 == starting, 4 == running)
while (Job.JobState = 3) or (Job.JobState = 4)
Wscript.Echo "Compacting. " & Job.PercentComplete & "% complete"
WScript.Sleep(1000)
'Refresh the job object
Wend
'Provide details if the job fails (7 == complete)
if (Job.JobState <> 7) then
Wscript.Echo "ErrorCode:" & Job.ErrorCode
Wscript.Echo "ErrorDescription:" & Job.ErrorDescription
end If
end if
What is the purpose of compacting the VHDs though Ben?
Thanks for all the great tips, they've been exceptionally helpful.
I have a server that is not hyper-v capable, but I would like to install the hyper-v tools to mount/defrag/compact vhds. Is there a way to do this?
I have just compacted a VHD
Size before compaction: 9,524,588,032
Size After compaction: 9,355,077,632
Do I need to run pre-compactor tool (precompact.exe in VirtualServer) before compacting VHDs in Hyper-V?
A nice addition would be a before/after report as an option.
There seems to be some issues here. The powershell script won't run at all, and the VBS script is vague. I can't tell if it actually ran or not. When running the script it immediately says the drive is compacted but there is no difference at all. How am I supposed to know if it really worked or not?
Specify the name of the virtual had disk to compact? Had disk? Are you by any chance from Boston?
I assume that the Virtual Server has to be shut down?
I just compared Usage stats from File Server Resource Manager to .VHD sizes. I was quite surprised at the difference, on a dynamic disk.
Modification of the above Powershell script to compact VHD's in bulk without any user intervention
$strComputers = @(
"F:\VMStore\CS1SRX\CS1SRX.vhd",
"F:\VMStore\CS1SRV\CS1SRV.vhd",
"F:\VMStore\CS1SQL\CS1SQL.vhd",
)
foreach($files in $strComputers)
{
$ImageManagementService = gwmi Msvm_ImageManagementService -namespace "root\virtualization" -computername machinename
$result = $ImageManagementService.CompactVirtualHardDisk($files)