In this case, I wanted a quick analysis on my Hyper-V VM’s vhd files and get the disk size and free disk space before upgrading to Server 2012 R2 Hyper-V.
The snippet basically loops trough all VM’s on a host (or in a cluster if you would want that), and gives you output as below.
If you want information on all disks for all VM’s in a cluster you can get that with Get-VHDStat -Cluster ClusterName
.
Get-VHDStat
function Get-VHDStat { param( [Parameter(Mandatory=$false)] [string] $Cluster ) if ($Cluster) { $VMs = Get-ClusterGroup -Cluster $cluster | where grouptype -eq 'virtualmachine' | Get-VM } else { $VMs = Get-VM } foreach ($VM in $VMs){ $VHDs=Get-VHD $vm.harddrives.path -ComputerName $vm.computername foreach ($VHD in $VHDs) { New-Object PSObject -Property @{ Name = $VM.name Type = $VHD.VhdType Path = $VHD.Path 'Total(GB)' = [math]::Round($VHD.Size/1GB) 'Used(GB)' = [math]::Round($VHD.FileSize/1GB) 'Free(GB)' = [math]::Round($VHD.Size/1GB- $VHD.FileSize/1GB) } } } }
Enjoy!
/Johan
Adding “path” to the statement “Get-VHDStat | select name, Path, Type, Total*,Free* | sort-object Free* ” but now it does not display in a list view. It comes out more like your first screen shot, how can I keep all info for each VHD/VHDX file on one line?
Hi,
Thanks for Reading!
Get-VHDStat | select name,path,Type,Total*,Free* | sort-object Free* | Format-Table -AutoSize
Will give you what you want
If you instead want to export it to a csv file, replace Format-Table -AutoSize with Export-csv filename.csv -NoTypeInformation
/Johan
Thank you, this helps very much!
Hi, I have copy your script and tried to use this script but it wont show anything, two questions:
1. Should this be executed on any host server or vmm server?
2. where in the code do you add?
Get-VHDStat | select name,path,Type,Total*,Free* | sort-object Free* | Format-Table -AutoSize
Hi Pär,
Since it’s a function, you just load the code on any machine that has the cluster / hyper-v powershell modules. After loading the code (you do it by just putting it in a file and run it by doing ‘. .\Code.ps1’, or simply copy-paste it in to a powershell window running as administrator).
After doing that, you can run the line ‘
Get-VHDStat | select name,path,Type,Total*,Free* | sort-object Free* | Format-Table -AutoSize
‘Let me know if you have further questions!
/Johan
Thanks for this, very helpful1
Hey sir.. im getting lots of errors from your script..
Im trying to run on windows 8 but don’t thinks is related
At line:20 char:49
+ ‘Total(GB)’ = [math]::Round($<span class="skimlinks-unlinked …
+ ~
Missing ')' in method call.
At line:20 char:49
+ 'Total(GB)' = [math]::Round($<span class="skimlinks-unlinked …
+ ~~~~~~
Unexpected token '$<span' in expression or statement.
At line:20 char:49
+ 'Total(GB)' = [math]::Round($<span class="skimlinks-unlinked …
+ ~
The hash literal was incomplete.
At line:15 char:37
+ foreach ($VHD in $VHDs) {
+ ~
Missing closing '}' in statement block.
At line:13 char:26
+ foreach ($VM in $VMs){
+ ~
Missing closing '}' in statement block.
At line:1 char:22
+ function Get-VHDStat {
+ ~
Missing closing '}' in statement block.
At line:20 char:102
+ … Size/1GB)
+ ~
Unexpected token ‘)’ in expression or statement.
At line:22 char:49
+ ‘Free(GB)’ = [math]::Round($<span class="skimlinks-unlinked …
+ ~
Missing ')' in method call.
At line:22 char:49
+ 'Free(GB)' = [math]::Round($<span class="skimlinks-unlinked …
+ ~~~~~~
Unexpected token '$<span' in expression or statement.
At line:22 char:121
+ … HD.FileSize/1GB)
+ ~
Unexpected token ')' in expression or statement.
Not all parse errors were reported. Correct the reported errors and try again.
+ CategoryInfo : ParserError: (:) [], ParseException
+ FullyQualifiedErrorId : MissingEndParenthesisInMethodCall
Thanks
Hi Jose,
Thanks for Reading!
It looks like you are getting the html highlighting formatting when copying the code. Please try to copy the code from http://1drv.ms/1jEN896 instead, and let me know if you still get any errors.
/Johan
That was it.. Thanks a lot Johan, now its working.. I have another question.. how can I put all disks within a server on the same line?? I was thinking about separate them by – or , but I don’t know how to do it..
I would like to see something like this
Name Type Total Free
Server1 Dynamic 500 10
Server2 – Server2 Dynamic – Differential – 250 – 100 15 -25
I need that because im adding to a csv and I need all info per server on one line
Thanks one more time
Thank you Johan; it really helped us.
Added Totals:
function Get-VHDStat {
param(
[Parameter(Mandatory=$false)]
[string]
$Cluster
)
$TotalGB = 0
$UsedGB = 0
$FreeGB = 0
if ($Cluster) {
$VMs = Get-ClusterGroup -Cluster $cluster | where grouptype -eq ‘virtualmachine’ | Get-VM
}
else {
$VMs = Get-VM
}
foreach ($VM in $VMs){
# write-host ‘VM:’ $VM.name ‘PATH:CLS’ $VM.harddrives.path
$VHDs=Get-VHD $VM.harddrives.path -ComputerName $VM.computername
foreach ($VHD in $VHDs) {
$TotalGB += [math]::Round($VHD.Size/1GB)
$UsedGB += [math]::Round($VHD.FileSize/1GB)
New-Object PSObject -Property @{
Name = $VM.name
Type = $VHD.VhdType
Path = $VHD.Path
‘Total(GB)’ = [math]::Round($VHD.Size/1GB)
‘Used(GB)’ = [math]::Round($VHD.FileSize/1GB)
‘Free(GB)’ = [math]::Round($VHD.Size/1GB- $VHD.FileSize/1GB)
}
}
}
New-Object PSObject -Property @{
Name =’Total’
‘Total(GB)’ = $TotalGB
‘Used(GB)’ = $UsedGB
‘Free(GB)’ = ($TotalGB – $UsedGB)
}
}
Nice!
Hi. Thanks for sharing a nice bit of script. I have an environment with a mix of ClusterSharedVolume storage and SMI-S integrated storage. This script doesn’t currently have any ability to look in to the state of the VHDs on the SMI-S integrated LUNs.
SCVMM uses SMI-S to dynamically assign LUNs to the Hyper-V hosts currently running whatever VM is storing VHDs in that LUN. I’m therefore imagining that I’m going to need to connect to each host in the cluster and enumerate LUNs for the non-CSV-based VMs on that host, and interrogate the VHDXs on those LUNs.
I think I’m going to have to do a bit of work to extend this for that specific requirement, but just thought I’d check in here to see if you’ve already run into the same requirement and figured out a way to do this?
Hi,
I can have a look at it, should not be too hard.
/Johan
Thanks for the post Johan, I tried to make a line of code that retrieves basically the same as your script but it doesn’t return what I wanted, as far as I can tell Size and FileSize are only useful with dynamic disks, with fixed disk I can’t get how much of it is actually used, do you know any way of accomplish the task with fixed disks? Below is the one liner just in case someone is interested, regards.
Get-VM | select @{l=”ComputerName”;e={$_.Name}},@{l=”Path”;e={$_.harddrives.path}} | Get-VHD | select @{l=”Path”;e={$_.Path}},@{l=”FileSize(GB)”;e={$_.FileSize / 1GB}},@{l=”Size(GB)”;e={$_.Size / 1GB}},@{l=”PercentUsage”;e={$_.FileSize * 100 / $_.Size}}
Thanks Johan, I made a line of code based on your script to check data on some vhd files, but for me it only works if the disk is dynamic, is there a way to inspect the usage of a fixed disk? Below is the one liner in case someone is interested, thank you.
Get-VM | select @{l=”ComputerName”;e={$_.Name}},@{l=”Path”;e={$_.harddrives.path}} | Get-VHD | select @{l=”Path”;e={$_.Path}},@{l=”FileSize(GB)”;e={$_.FileSize / 1GB}},@{l=”Size(GB)”;e={$_.Size / 1GB}},@{l=”PercentUsage”;e={$_.FileSize * 100 / $_.Size}}
Antonio
Thanks for sharing!
Hi John,
I wonder if you could teach me to these as well:
– current storage size
– maximum storage size
– current cpu usage
– maximum cpu usage
– current memory usage
– maximum memory usage
of all the VM’s
Hello, I’m a newbie on Powershell….. i don’t seem to get this working. After having saved your code to a .ps1 file, I can’t call it up in powershell.. What do I have to do?
Thanks for your help
WOW!
Awesome!
I’m looking for some vhdx “lost” on CSV and find with Vm is using him
Thnks a lot!
Hi Johan,
I get an error followed by “some” results …
PS C:\Windows\system32> Get-VHDStat | select name,path,Type,Total*,Free* | sort-object Free* | Format-Table -AutoSize
Get-VHD : Cannot validate argument on parameter ‘Path’. The argument is null or empty. Provide an argument that is not null or empty, and then try the command again.
At line:13 char:23
+ $VHDs=Get-VHD $vm.harddrives.path -ComputerName $vm.computername
+ ~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : InvalidData: (:) [Get-VHD], ParameterBindingValidationException
+ FullyQualifiedErrorId : ParameterArgumentValidationError,Microsoft.Vhd.PowerShell.GetVhdCommand
Name Path Type Total(GB) Free(GB)
—- —- —- ——— ——–
SDC-DEVVSRP02 C:\ClusterStorage\Volume1\SDC-DEVVSRP02\SDC-DEVVSRP02_F.vhdx Fixed 20 0
SDC-CDLTVSQ01 C:\ClusterStorage\DevVOL10\SDC-CDLTVSQ01\SDC-CDLTVSQ01_disk_d.vhdx Fixed 300 0
SDC-DEVVSRP02 C:\ClusterStorage\volume1\sdc-devvsrp02\SDC-DEVVSRP02_C.vhdx Fixed 80 0
SDC-DEVVBNK02 C:\ClusterStorage\DevVOL03\SDC-DEVVBNK02\c_drive.vhd Dynamic 140 0
Hi there,
Something seems to be missing when running this script on a cluster. The variable $Cluster does not seem to get any kind of output assigned to it?
When I run this on one node I only get output for that node.
I got it figured out. The updated version is:
function Get-VHDStat {
param(
[Parameter(Mandatory=$false)]
[string]
$Cluster = (Get-Cluster)
)
if ($Cluster) {
$VMs = Get-ClusterGroup -Cluster $cluster | Where-Object grouptype -eq ‘virtualmachine’ | Get-VM
} else {
$VMs = Get-VM
}
foreach ($VM in $VMs){
$VHDs=Get-VHD $vm.harddrives.path -ComputerName $vm.computername
foreach ($VHD in $VHDs) {
New-Object PSObject -Property @{
Name = $VM.name
Type = $VHD.VhdType
Path = $VHD.Path
‘Total(GB)’ = [math]::Round($VHD.Size/1GB)
‘Used(GB)’ = [math]::Round($VHD.FileSize/1GB)
‘Free(GB)’ = [math]::Round($VHD.Size/1GB- $VHD.FileSize/1GB)
}
}
}
}