Note
Access to this page requires authorization. You can try signing in or changing directories.
Access to this page requires authorization. You can try changing directories.
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 been compacted."}
Else
{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
set Job = WMIService.Get(OutParam.Job)
Wend
'Provide details if the job fails (7 == complete)
if (Job.JobState <> 7) then
Wscript.Echo "The virtual hard disk has not been compacted."
Wscript.Echo "ErrorCode:" & Job.ErrorCode
Wscript.Echo "ErrorDescription:" & Job.ErrorDescription
else
Wscript.Echo "The virtual hard disk has been compacted."
end If
end if
Cheers,
Ben
Comments
Anonymous
June 12, 2008
What is the purpose of compacting the VHDs though Ben?Anonymous
June 24, 2008
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?Anonymous
June 26, 2008
I have just compacted a VHD Size before compaction: 9,524,588,032 Size After compaction: 9,355,077,632Anonymous
July 08, 2008
Do I need to run pre-compactor tool (precompact.exe in VirtualServer) before compacting VHDs in Hyper-V?Anonymous
July 07, 2010
A nice addition would be a before/after report as an option.Anonymous
May 19, 2011
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?Anonymous
February 17, 2012
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.Anonymous
September 04, 2012
Modification of the above Powershell script to compact VHD's in bulk without any user intervention $strComputers = @( "F:VMStoreCS1SRXCS1SRX.vhd", "F:VMStoreCS1SRVCS1SRV.vhd", "F:VMStoreCS1SQLCS1SQL.vhd", ) foreach($files in $strComputers) { $ImageManagementService = gwmi Msvm_ImageManagementService -namespace "rootvirtualization" -computername machinename $result = $ImageManagementService.CompactVirtualHardDisk($files) 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 been compacted."} Else {write-host "The virtual hard disk has not been compacted." write-host "ErrorCode:" $job.ErrorCode write-host "ErrorDescription" $job.ErrorDescription} } }Anonymous
January 07, 2014
The comment has been removedAnonymous
April 09, 2014
What the heck does "Specify the name of the virtual had disk to compact" even mean? Specifically "virtual had disk". And Windows 2012 R2 and non R2's WMI namespace is located at "rootvisualizationv2" if you need that info.