Get VMware Disk Usage with Powershell

Using VMware seriously requires a lot of (shared) storage. This kind of storage (on a SAN for instance) is quite expensive. So you might want to check if you are wasting a lot of this space. When you look at the storage in VMware, it consists of multiple abstraction layers. A virtual machine has one or more Logical Disks, which are indicated by driveletters. You can use WMI to determine the amount of used and free space (Win32_LogicalDisk). One or more logical disks are contained in a partition. One or more partitions reside on a physical disk. That physical disk is really a virtual disk, a vmdk file to be precise. One or more vmdk files reside in a Datastore, which can be found on a LUN on your SAN.
The following script enumerates most of these layers (from logical disk to datastore) and calculates the used and free space. The final line exports the results to a csv file for use in Excel. And the script also helps you to calculate the average free space by showing the totals without the duplicates (don’t try to average the averages in excel, that’s not accurate because datastores contain duplicates and averages should be weighed).

UPDATE: I have modified the script, so no more matching of disks is done based on disk size. The match is made based on SCSI IDs and WMI relations. Thanks to adavidm on the VI Toolkit Community

#Get VMware Disk Usage
# Created by Hugo Peeters
# http://www.peetersonline.nl
# VARIABLES
$Decimals = 1
$VCServer = "MYVCSERVER"
# SCRIPT
# Connect to VC
Write-Progress "Gathering Information" "Connecting to Virtual Center" -Id 0
$VC = Connect-VIServer $VCServer
# Create Output Collection
$myCol = @()
# List Datastores (Datastore Name)
Write-Progress "Gathering Information" "Listing Datastores" -Id 0
$Datastores = Get-Datastore | Sort Name
# List vms
Write-Progress "Gathering Information" "Listing VMs and Disk Files" -Id 0
$VMSummaries = @()
ForEach ($vm in (Get-VM))
	{
	$VMView = $VM | Get-View
	ForEach ($VirtualSCSIController in ($VMView.Config.Hardware.Device | Where {$_.DeviceInfo.Label -match "SCSI Controller"}))
		{
		ForEach ($VirtualDiskDevice  in ($VMView.Config.Hardware.Device | Where {$_.ControllerKey -eq $VirtualSCSIController.Key}))
			{
			$VMSummary = "" | Select VM, HostName, PowerState, DiskFile, DiskName, DiskSize, SCSIController, SCSITarget
			$VMSummary.VM = $VM.Name
			$VMSummary.HostName = $VMView.Guest.HostName
			$VMSummary.PowerState = $VM.PowerState
			$VMSummary.DiskFile = $VirtualDiskDevice.Backing.FileName
			$VMSummary.DiskName = $VirtualDiskDevice.DeviceInfo.Label
			$VMSummary.DiskSize = $VirtualDiskDevice.CapacityInKB * 1KB
			$VMSummary.SCSIController = $VirtualSCSIController.BusNumber
			$VMSummary.SCSITarget = $VirtualDiskDevice.UnitNumber
			$VMSummaries += $VMSummary
			}
		}
	Clear-Variable VMView -ErrorAction SilentlyContinue
	}
# Loop through Datastores
ForEach ($Datastore in $Datastores)
	{
	# List vmdk files in datastore (vmdk Name)
	Write-Progress "Gathering Information" ("Processing Datastore {0}" -f $Datastore.Name) -Id 0
	$DSView = $Datastore | Get-View
	$fileQueryFlags = New-Object VMware.Vim.FileQueryFlags
	$fileQueryFlags.FileSize = $true
	$fileQueryFlags.FileType = $true
	$fileQueryFlags.Modification = $true
	$searchSpec = New-Object VMware.Vim.HostDatastoreBrowserSearchSpec
	$searchSpec.details = $fileQueryFlags
	$searchSpec.sortFoldersFirst = $true
	$dsBrowser = Get-View $DSView.browser
	$rootPath = "["+$DSView.summary.Name+"]"
	$searchResult = $dsBrowser.SearchDatastoreSubFolders($rootPath, $searchSpec)
	ForEach ($result in $searchResult)
		{
		ForEach ($vmdk in ($result.File | ?{$_.Path -like "*.vmdk"} | Sort Path))
			{
			Write-Progress "Gathering Information" ("Processing VMDK {0}" -f $vmdk.Path) -Id 1
			Write-Host "=============================================================================="
			# Find vm using the vmdk (VM Name)
			$VMRef = ($VMSummaries | ?{$_.DiskFile -match $Datastore.Name -and $_.DiskFile -match $vmdk.Path})
			"VMDK {0} belongs to VM {1}" -f $vmdk.Path, $VMRef.VM
			If ($VMRef.Powerstate -eq "PoweredOn")
				{
				Write-Host "VM is powered on" -ForegroundColor "yellow"
				$Partitions = Get-WmiObject -Class Win32_DiskPartition -ComputerName $VMRef.HostName
				If ($?)
					{
					$Disks = Get-WmiObject -Class Win32_DiskDrive -ComputerName $VMRef.HostName
					$LogicalDisks = Get-WmiObject -Class Win32_LogicalDisk -ComputerName $VMRef.HostName
					$DiskToPartition = Get-WmiObject -Class Win32_DiskDriveToDiskPartition -ComputerName $VMRef.HostName
					$LogicalDiskToPartition = Get-WmiObject -Class Win32_LogicalDiskToPartition -ComputerName $VMRef.HostName
					Write-Host "Read partition and disk information" -ForegroundColor "yellow"
					# Match disk based on SCSI ID's
					$DiskMatch = $Disks | ?{($_.SCSIPort - 1) -eq $VMRef.SCSIController -and $_.SCSITargetID -eq $VMRef.SCSITarget}
					If ($DiskMatch -eq $null){Write-Warning "NO MATCHES!"}
					Else
						{
						Write-Host "Found match:" -ForegroundColor "yellow"
						$DiskMatch
						# Find the Partition(s) on this disk
						$PartitionsOnDisk = ($DiskToPartition | ?{$_.Antecedent -eq $DiskMatch.__PATH})
						If ($PartitionsOnDisk -eq $null){Write-Warning "NO PARTITIONS!"}
						Else
							{
							ForEach ($PartitionOnDisk in $PartitionsOnDisk)
								{
								Write-Host "Disk contains partition" -ForegroundColor "yellow"
								$PartitionOnDisk.Dependent
								$PartitionMatches = $Partitions | ?{$_.__PATH -eq $PartitionOnDisk.Dependent}
								ForEach ($PartitionMatch in $PartitionMatches)
									{
									$LogicalDiskRefs = $LogicalDiskToPartition | ?{$_.Antecedent -eq $PartitionMatch.__PATH}
									If ($LogicalDiskRefs -eq $null)
										{
										Write-Warning "NO LOGICAL DISKS!"
										}
									Else
										{
										ForEach ($LogicalDiskRef in $LogicalDiskRefs)
											{
											$LogicalDiskMatches = $LogicalDisks | ?{$_.__PATH -eq $LogicalDiskRef.Dependent}
											ForEach ($LogicalDiskMatch in $LogicalDiskMatches)
												{
												Write-Host "Matching Logical Disk:" -ForegroundColor "yellow"
												$LogicalDiskMatch
												# Create Output Object
												$myObj = "" | Select Datastore, DSSizeGB, DSFreeGB, DSPercentFree, DiskFile, VM, HardDisk, DriveLetter, DiskSizeGB, DiskFreeGB, PercFree
												# List datastore name
												$myObj.Datastore = $Datastore.Name
												# Determine datastore size in GB
												$myObj.DSSizeGB = [Math]::Round(($Datastore.CapacityMB * 1MB / 1GB),$Decimals)
												$myObj.DSFreeGB = [Math]::Round(($Datastore.FreeSpaceMB * 1MB / 1GB),$Decimals)
												# Determine datastore free space (DS%Free)
												$myObj.DSPercentFree = [Math]::Round((100*($Datastore.FreeSpaceMB/$Datastore.CapacityMB)),$Decimals)
												# List disk file name
												$myObj.DiskFile = $vmdk.Path
												# List VM Name
												$myObj.VM = $VMRef.VM
												# Determine virtual hard disk / logical drive
												$myObj.HardDisk = $VMRef.DiskName
												# Report driveletter
												$myObj.DriveLetter = $LogicalDiskMatch.DeviceID
												# Report Size
												$myObj.DiskSizeGB = [Math]::Round(($LogicalDiskMatch.Size / 1GB),$Decimals)
												# Report Free Space
												$myObj.DiskFreeGB = [Math]::Round(($LogicalDiskMatch.FreeSpace / 1GB),$Decimals)
												# Calculate Percentage free space
												$myObj.PercFree = [Math]::Round((100 * ([int]($LogicalDiskMatch.FreeSpace / 1MB) / [int]($LogicalDiskMatch.Size / 1MB))),$Decimals)
												Write-Host "RESULT:" -ForegroundColor "yellow"
												$myObj
												# Add output object to output collection
												$myCol += $myObj
												}
											Clear-Variable LogicalDiskMatches -ErrorAction SilentlyContinue
											}
										}
									Clear-Variable LogicalDiskRefs -ErrorAction SilentlyContinue
									}
								Clear-Variable PartitionMatches -ErrorAction SilentlyContinue
								}
							}
						Clear-Variable PartitionsOnDisk -ErrorAction SilentlyContinue
						}
					Clear-Variable DiskMatch -ErrorAction SilentlyContinue
					Clear-Variable Disks -ErrorAction SilentlyContinue
					Clear-Variable LogicalDisks -ErrorAction SilentlyContinue
					Clear-Variable DiskToPartition -ErrorAction SilentlyContinue
					Clear-Variable LogicalDiskToPartition -ErrorAction SilentlyContinue
					}
				Clear-Variable Partitions -ErrorAction SilentlyContinue
				}
			Else
				{
				Write-Host "VM is powered off" -ForegroundColor "yellow"
				}
			Clear-Variable VMRef -ErrorAction SilentlyContinue
			Write-Progress "Gathering Information" ("Processing VMDK {0}" -f $vmdk.Path) -Id 1 -Completed
			}
		}
	}
# Disconnect from VC
Disconnect-VIServer -Confirm:$False
# OUTPUT
Write-Host "==================================================="
Write-Host "==================================================="
$TotalDSFree = ($myCol | Select Datastore, DSFreeGB -Unique | Measure-Object DSFreeGB -Sum).Sum
$TotalDSSize = ($myCol | Select Datastore, DSSizeGB -Unique | Measure-Object DSSizeGB -Sum).Sum
$AverageDSFree =  [Math]::Round(100 * ($TotalDSFree / $TotalDSSize),$Decimals)
$AverageDiskFree =  [Math]::Round(100 * (($myCol | Measure-Object DiskFreeGB -Sum).Sum / ($myCol | Measure-Object DiskSizeGB -Sum).Sum),$Decimals)
Write-Host "Total DS Free: $TotalDSFree"
Write-Host "Total DS Size: $TotalDSSize"
Write-Host "Average DS Free Percentage: $AverageDSFree"
Write-Host "Average Disk Free Percentage: $AverageDiskFree"
$myCol | Export-Csv -NoTypeInformation 'P:\#TEMP\VMwareDiskUsage.csv'
7 vampires around the world worse than the ones in twilightI just want a clear run now. http://www.wholesale-cheap-nfl-jerseys.com Welcome to the Twenty First Century Fox First Quarter 2017 Earnings Release Conference Call. Good morning, ladies and gentlemen. Both sides were ironed with each part and the final product was super glued for reinforcement. Gene Jelks, a former Alabama football player, says he was paid thousands of dollars by coaches and school boosters during his career with the Crimson Tide. Former Cheap Replica ray bans outlet businessman and lobbyist Jack Abramoff was sentenced to six years in prison in 2006 following the Indian lobbying scandal. All content of the Dow Jones branded indices S Dow Jones Indices LLC 2016 and/or its affiliates.. Last year, whole sales rose 14% to about $212 billion. And it should mean a New England victory.. According to his experience, your best bet at getting a girl is walking up to her group and completely ignoring her, while chatting away to her less attractive friends.. Enrollment for a Phase III trial should be complete by the fourth quarter of this year. To jam the receiver, you’re going to line up about two to three yards in front of him. Leading international UK based banks are in advanced stages of planning to shift operations to Paris as London braces for the impact of Brexit, France’s chief financial regulator has said. Former Oilers quarterback Warren Moon stated in the documentary that Ryan’s 46 defense couldn’t stop the team’s run and shoot offense, which was the catalyst for Ryan encouraging the intense practice battles. Wentz completed 32 of 43 passes, which sounds great until you consider the fact that those 32 completions went for only 202 yards. (AP Photo/Bill Boyce, File) ORG XMIT: NY158If you need a team to finish 7 9, Jeff Fisher is the man for the job. So, while vacationing in Central America, he took one look at the Cerro Negro, a volcano so dangerous that it’s erupted Replica Oakleys no fewer than 23 times in its 159 years of existence and said, “Same thing.”In his spare time, he shits continents.. Anti inflammatory medicines are often prescribed to alleviate swelling and to reduce pain. The block was legal. “I remember last year when I was drafted in the seventh round, and all of the emotions and happiness I felt when I received the call that gave me an opportunity to play for an NFL team, and I wish him all the best in his NFL career,” Jones said in a statement. So this is one to help aid in supporting the lower back. 21, 2009, the 15 year old strangled, stabbed and cut the throat of her 9 year old next door neighbor Elizabeth Olten because she wanted to know what it felt like. I will learn from it.”It was a far cry from just days earlier, where McGregor had told the Herald of his plans http://cheapjerseysupply.com to be the UFC’s billion dollar man.Fighting is big moneyMixed martial arts, spearheaded by the UFC, has become a force among combat and professional sports.Initially contrived as a competition to determine which style of martial Cheap ray ban sunglasses arts was most effective in a real fight, the sport has evolved into a hybrid combining striking and grappling.In 2015, the UFC earned in excess of US$600 million in revenue, setting a new high water mark for the company, while smashing qualitative and quantitative records around the world.”It’s a record number and a metric wholesale jerseys which shows our sport has never been stronger before,” explains Lorenzo Fertitta, chief executive and majority owner of the UFC.”When we look at the metrics, whether it be overall revenue, social media, television ratings across our global markets, we’re continuing to grow and get stronger.”Revenues have been growing rapidly for the UFC wholesale nfl jerseys over the past decade, improving from a reported US$250 million in 2008 to last year’s US$600 million.”It feels that with all of the momentum we have, the conversation and the popularity around the world, it feels like our revenue really hasn’t caught up to what our true potential really is,” Fertitta says.

78 thoughts on “Get VMware Disk Usage with Powershell”

  1. Hi Hugo,

    I got an error on this one, something to do with the “-f” any ideas?

    Error formatting a string: Input string was not in a correct format..
    At :line:46 char:70
    + Write-Progress “Gathering Information” (”Processing Datastore {0}” -f <<<< $Datastore.Name) -Id 0

    BTW
    Love the site and the scripts, excellent work:)
    JoeL

  2. Dear Hugo!

    Very nice script! I have the following problem:
    I would like to have a script which sents my an alarm by email if a LUN has for example only 15% of free space.

    Could you write anything like that?

    That would be very nice and I think a lot of VI3 admins need that.

    Greetings
    Simon

  3. @JoeL
    I think you might have a datastore with special characters in it. You can try to avoid the problem by using:
    $DatastoreName = $Datastore.Name
    Write-Progress “Gathering Info” “Processing $DatastoreName” -Id 0
    Clear-Variable $DatastoreName -ErrorAction SilentlyContinue

    Let me know if that helps.
    Hugo

  4. @Simon
    Try this:
    $VCServerName = “MYVCSERVER”
    $Decimals = 0
    $Limit = 15
    $From = “no@spam.mow”
    $To = “SomeOne@Foo.com”
    $Title = “Datastore nearly full!”

    $VC = Connect-VIServer $VCServerName
    $Datastores = Get-Datastore
    ForEach ($Datastore in $Datastores)
    {
    $PercentFree = [math]::Round(((100*($Datastore.FreeSpaceMB / $Datastore.CapacityMB )),$Decimals)
    If ($PercentFree -lt $Limit)
    {
    $Body = “Datastore {0} has {1} percent free space.” -f $Datastore.Name, $PercentFree
    # Mail part copied from http://mow001.blogspot.com/2005/11/sending-mail-from-msh.html
    $SmtpServer = “smtp.Server.com”
    $SmtpClient = new-object system.net.mail.smtpClient
    $SmtpClient.host = $SmtpServer
    }
    }

  5. When I run this script, I got the following error, can you check that?

    VMDK AV_DEV.vmdk belongs to VM AV_DEV
    VM is powered on
    Get-WmiObject : RPC server is unavailable (Exception from HRESULT: 0x800706BA)
    At line:50 char:28
    + $Partitions = Get-WmiObject <<<< -Class Win32_DiskPartition -ComputerName $V
    MRef.HostName

  6. @Jack
    That’s a Windows / Networking issue. You cannot reach that server through RPC (Remote Procedure Call). Check network connectivity and possibly DCOM permissions. Lots of info on Google.
    Hope that helps you out.
    Hugo

  7. Nice script, and just a couple of comments.

    To get around the non-connectivity errors – this script could be modified to do this via sql, since VirtualCenter stores all the VM free/used/capacity, as well as Datastore free/used/capacity in a simple table structure for any client with VMtools installed.

    Alternatively, we could trim the ‘dns’ name off the VMname and do a lookup to determine credentials to connect to the remote machine with a default local account. I think I will probably head down this path myself 🙂

    Sometimes disks are on local VMFS volumes and you don’t want this as it will throw the stats out. It would nice to have an opt-out to exclude VMs with disks on ‘local’ storage. But this is pretty trivial.
    Cheers.

  8. error :

    Error formatting a string: Input string was not in a correct format..
    At :line:46 char:70
    + Write-Progress “Gathering Information” (”Processing Datastore {0}” -f <<<< $Datastore.Name) -Id 0

    the datastore name is quite long: “GL-dldn0534nsd-rg9-034-templates” will the script cater for that ?.

    Regards

  9. sorry – looks like i have same problem as Joel. Your extra code fixed that but now get :
    Error formatting a string: Input string was not in a correct format..
    At :line:65 char:65
    + Write-Progress “Gathering Information” (”Processing VMDK {0}” -f <<<< $vmdk.Path) -Id 1

    $vmdk.path has a couple of “-” in it, could this be the problem ?.

  10. @Ryan
    You could modify this part:
    # List Datastores (Datastore Name)
    Write-Progress “Gathering Information” “Listing Datastores” -Id 0
    $Datastores = Get-Datastore | Sort Name

    Into something like this:
    # List Datastores (Datastore Name)
    Write-Progress “Gathering Information” “Listing Datastores” -Id 0
    $exclusions = “Datastore1”, “Datastore2”
    $Datastores = Get-Datastore | Where {$exclusions -notcontains $_.Name} | Sort Name

  11. @Simon
    Here’s a script to do what you are looking for:

    New-PSDrive -Name PS -Root T:scriptingps -PSProvider filesystem
    Set-Location PS:
    Connect-VIServer -Server pni-dvsysmgt01.pni.com -User administrator
    $dir = “c:TEMP”
    $outfile = “c:tempsysadminreport.txt”
    $sysadmins = Import-Csv “t:ScriptingpsSysAdmin Email.txt” -ErrorAction stop

    if (Test-Path $dir)
    {}

    else
    {
    New-Item $dir -type directory
    }

    if (Test-Path $outfile)
    {
    Remove-Item $outfile -force
    }

    ####################################################################################
    # Get Systems Excel Spreadsheet for processing
    ####################################################################################
    $excelApp = new-object -comobject Excel.Application
    $excelApp.visible = $true
    $date = Get-Date –f yyyyMMdd
    $copy = “pni-pcfs01system$VMWare$date Powershell Datastore Report.xls”
    Copy-Item “pni-pcfs01system$VMWareVMWare LUN Configuration & Licensing.xls” $copy
    $file = (dir $copy).FullName
    $book = $excelApp.Workbooks.Open($file)

    ####################################################################################
    # Get Datastores and create size related variables
    ####################################################################################
    Get-Datastore|`
    %{$arrDATASTORE = $_;`
    $DS = $arrDATASTORE.Name;`
    [int]$FREESPACE = $arrDATASTORE.FreeSpaceMB;`
    [int]$CAPACITY = $arrDATASTORE.CapacityMB;`
    [decimal]$PERCENTFREE = $FREESPACE / $CAPACITY;`

    ####################################################################################
    # Update Systems Datastore Spreadsheet
    ####################################################################################
    # get sheet and update sheet name
    $sheet = $book.Worksheets.Item(1)
    #$s1.name = “Datastore Report for PNI”
    $row = 3
    while(“True”)
    {
    if ($DS -match “Dellpe”)
    {
    write-host “$DS is internal”
    break;
    }
    $datastore = $sheet.Cells.Item($row,1).Value2
    $description = $sheet.Cells.Item($row,2).Value2
    if (!$datastore)
    {
    write-host “$datastore does not match $DS”
    break;
    }
    if ($datastore -match “$DS”)
    {
    write-host “$datastore matched!”
    $sheet.Cells.Item($row,3).Value2 = [int][decimal]$CAPACITY / 1000
    $sheet.Cells.Item($row,5).Value2 = [int][decimal]$FREESPACE / 1000
    break;
    ;
    }
    $row++
    }

    # temporary break for excel testing:
    #}
    #break;

    ####################################################################################
    # Get Datastores with less than 10% available space and list hosted VMs.
    ####################################################################################
    If ( [decimal]$PERCENTFREE -lt .1) {
    Add-Content $outfile “`n####################################################################`r”
    Add-Content $outfile “$DS has less than 10% free space!`r”
    Add-Content $outfile “Capacity: $CAPACITY MB`r”
    Add-Content $outfile “Available: $FREESPACE MB`r”
    Add-Content $outfile “The following VM’s are on this Datastore:`r”
    Add-Content $outfile “####################################################################`r”
    Get-Datacenter| Get-VM |`
    %{$vm = $_;`
    Get-HardDisk -VM $vm |`
    %{$hd = $_;`
    [int]$hdcap = $hd.capacitykb/1000
    # Write-Host -Separator ” ” $vm.name $hd.filename “$hdcap MB”
    If ($hd.filename -match “[$DS]”) {
    [int]$hdcap = $hd.capacitykb/1000
    $name = $vm.Name
    $hdname = $hd.Filename
    $vmgroup = $vm.CustomFields.Item(“Group”)
    $vmadmin = $vm.CustomFields.Item(“System Administrator”)
    If ($name -match “replicat”) {
    $vmgroup = “VizionCore Replication”
    $vmadmin = “John Taber”
    }
    If ($vmgroup -match “$description”)
    {Add-Content $outfile “$name `t $hdname `t $hdcap MB `r”}
    Else {
    foreach($sysadmin in $sysadmins) {
    $adminfirstname = $sysadmin.First
    $adminlastname = $sysadmin.Last
    If ($vmadmin -match “$adminlastname”) {
    Add-Content $dir$adminlastname.txt “$name is located on the wrong Datastore. `r”
    Add-Content $dir$adminlastname.txt “The harddrive file $hdname is located on datastore $DS. `r”
    Add-Content $dir$adminlastname.txt “This datastore is reserved for $description usage. `r”
    Add-Content $dir$adminlastname.txt “$name is classified as $vmgroup and should be on a $vmgroup datastore. `r”
    Add-Content $dir$adminlastname.txt “Unfortunately, the $DS datastore has less than 10 percent free disk space. `r”
    Add-Content $dir$adminlastname.txt “Please relocate the $name VM as soon as possible. `r”
    Add-Content $dir$adminlastname.txt “`r”
    }
    }
    Add-Content $outfile “**** Wrong Group ***** Group is $vmgroup and should be $description `t $name `t $hdname `t $hdcap MB `r”
    }
    }
    }
    }
    }
    }

    Add-Content $outfile “`n`n`nEnd of Report.”

    ####################################################################################
    # Clean up Excel work.
    ####################################################################################
    $excelApp.Quit()
    $book = $null
    $sheet = $null
    $excelApp = $null
    [GC]::Collect()

    ####################################################################################
    # Send email to team with Datastore summary and recommendations
    ####################################################################################
    #$email = new-object -comobject “cdo.message”
    #$email.From = “pni-dvsysmgt01.pni.com”
    #$email.To = “phx.it.systems@pni.com”
    #$email.Subject = “Datastorage Space Managment.”
    #$email.TextBody = “Please examine the following output. This is important that we keep these datastores with 10 percent or more of freespace to give us room for replication, snapshots and emergency filesystem growth!`n`n”
    #
    #foreach ($f in get-content $outfile)
    # {
    # $email.TextBody += “$f `n”
    # }
    #
    #
    #$email.Configuration.Fields.Item(“http://schemas.microsoft.com/cdo/configuration/sendusing”) = 2
    #$email.Configuration.Fields.Item(“http://schemas.microsoft.com/cdo/configuration/smtpserver”) = “mail.pni.com”
    #$email.Configuration.Fields.Item(“http://schemas.microsoft.com/cdo/configuration/smtpserverport”) = 25
    #
    #$email.Configuration.Fields.Update()
    #$email.Send()

    ####################################################################################
    # Send email to Sysadmin with Datastore summary and recommendations
    ####################################################################################
    foreach($sysadmin in $sysadmins) {
    $adminfirstname = $sysadmin.First
    $adminlastname = $sysadmin.Last
    $adminemail = $sysadmin.Email
    $adminfile = “$dir$adminlastname.txt”
    $email = new-object -comobject “cdo.message”
    $email.From = “pni-dvsysmgt01.pni.com”
    $email.To = “$adminemail”
    $email.CC = “sgray@pni.com,john.taber@pni.com”
    $email.Subject = “Datastorage Space Managment.”
    $email.TextBody = “Please examine the following output. This is important that we keep these datastores with 10 percent or more of freespace to give us room for replication, snapshots and emergency filesystem growth!`n The latest information can be found in $copy `n`n”
    if (test-path $adminfile) {
    foreach ($f in get-content $adminfile)
    {
    $email.TextBody += “$f `n”
    }
    $email.Configuration.Fields.Item(“http://schemas.microsoft.com/cdo/configuration/sendusing”) = 2
    $email.Configuration.Fields.Item(“http://schemas.microsoft.com/cdo/configuration/smtpserver”) = “mail.pni.com”
    $email.Configuration.Fields.Item(“http://schemas.microsoft.com/cdo/configuration/smtpserverport”) = 25

    $email.Configuration.Fields.Update()
    $email.Send()
    del $adminfile
    }

    }

    »crosslinked«

  12. Pingback: Another way to gather VMware disk info with Powershell « H9Newser’s Blog
  13. Pingback: vuemuer.pmiservice.biz » Blog Archive » Analizzare l’uso dei dischi con powershell
  14. I stumbled across this website after a google search. I’m interested in running this script. What do I need to have installed for it to run? Can I just copy and paste into a file, what file extension does it need etc. to execute. Thanks!

  15. Hi Hugo

    Great Script

    Trying to understand though why some of my VM’s would show up as “NO MATCHES!” when doing the SCSI matching. Can you explain a little about this part of the script so I can work out where it’s going wrong. I’m wondering if there are problems with my VM’s

    Regards

    C Stewart

  16. Hi Hugo,

    I am getting the expected results for only a few VMs but most are getting this error messsage while running the script:

    VMDK UPLSVUXYZ.vmdk belongs to VM USPLSVUXYZ
    Get-WmiObject : Access is denied. (Exception from HRESULT: 0x80070005 (E_ACCESS DENIED)
    At C:\temp\VM-SAN-Script.ps1:72 char:28
    + $Partitions = Get-WmiObject <<<< – Class Win32_DiskPartition – ComputerName $VMRef.Hostname

    Regards

    Eric C

    1. Eric,
      The error indicates you have insufficient permissions to do a WMI query to the machines. Make sure the account running the script is local admin on all target vm’s.

  17. I am looking to use PowerShell to run against my environment, asks me which cluster I want to investigate, and then enumerate each lun, the used space, total capacity, and free space, then dump that to a csv or xls file. Can you please advise?

    1. Do you mean LUNs or datastores? (Subtle difference)
      Datastores is easily done:
      # Variables
      $VIServer = “MyVCServer.domain.local”
      $ExportFile = ‘D:\scripts\datastores.csv’

      #Functions
      function Create-ListBox
      {
      param ([array]$Items,[string]$Title = “ListBox”,[string]$Text = “Please make your selection”)
      If ($Items -eq $null)
      {
      Write-Warning ‘Argument “Items” is mandatory.’;throw “Syntax error.”
      }

      [System.Reflection.Assembly]::LoadWithPartialName(“System.Windows.Forms”) | Out-Null
      [System.Reflection.Assembly]::LoadWithPartialName(“System.Drawing”) | Out-Null

      $objForm = New-Object System.Windows.Forms.Form
      $objForm.Text = $Title
      $objForm.Size = New-Object System.Drawing.Size(300,200)
      $objForm.StartPosition = “CenterScreen”

      $objForm.KeyPreview = $True
      $objForm.Add_KeyDown({if ($_.KeyCode -eq “Enter”){$x=$objListBox.SelectedItem;$objForm.Close()}})
      $objForm.Add_KeyDown({if ($_.KeyCode -eq “Escape”){$objForm.Close()}})

      $OKButton = New-Object System.Windows.Forms.Button
      $OKButton.Location = New-Object System.Drawing.Size(75,120)
      $OKButton.Size = New-Object System.Drawing.Size(75,23)
      $OKButton.Text = “OK”
      $OKButton.Add_Click({$x=$objListBox.SelectedItem;$objForm.Close()})
      $objForm.Controls.Add($OKButton)

      $CancelButton = New-Object System.Windows.Forms.Button
      $CancelButton.Location = New-Object System.Drawing.Size(150,120)
      $CancelButton.Size = New-Object System.Drawing.Size(75,23)
      $CancelButton.Text = “Cancel”
      $CancelButton.Add_Click({$objForm.Close()})
      $objForm.Controls.Add($CancelButton)

      $objLabel = New-Object System.Windows.Forms.Label
      $objLabel.Location = New-Object System.Drawing.Size(10,20)
      $objLabel.Size = New-Object System.Drawing.Size(280,20)
      $objLabel.Text = $Text
      $objForm.Controls.Add($objLabel)

      $objListBox = New-Object System.Windows.Forms.ListBox
      $objListBox.Location = New-Object System.Drawing.Size(10,40)
      $objListBox.Size = New-Object System.Drawing.Size(260,20)
      $objListBox.Height = 80

      ForEach ($item in $Items)
      {
      [void] $objListBox.Items.Add($item)
      }

      $objForm.Controls.Add($objListBox)

      $objForm.Topmost = $True

      $objForm.Add_Shown({$objForm.Activate()})
      [void] $objForm.ShowDialog()

      return $x
      }

      #Script
      $VC = Connect-VIServer $VIServer
      $Cluster = Create-ListBox -Items (Get-Cluster | Sort Name) -Title “Select Cluster” -Text “Please select a cluster”
      $Cluster | Get-VMHost | Get-Datastore | Sort Name | Select Name, CapacityMB, FreeSpaceMB -Unique | Export-Csv $OutputFile -NoTypeInformation
      Disconnect-VIServer -Confirm:$False

  18. I have blogged about several bits and pieces you could use. There’s a Create-Listbox function I wrote, which makes selecting the cluster really nifty. Enumerating LUNs should be a breeze with the VI Toolkit 1.5 Get-SCSILun cmdlet. Capacity and free space are properties of those luns, so easily extracted.
    I’ll write a script when I have some spare time. Check back soon.

  19. Cool Script.. How do I get the script to continue after failures because of “access denied” or “RPC errors”? and in report leave entries blank..

    denied@admin

  20. Hugo,

    I was able to get the script to continue after failures and pipe failed VMs into a error log..

    “trap {

    Write-Host “error connecting to $VMRef.HosteName” -Foregroundcolor Red
    “$VMRef.VM” | Out-File d:\Reports\errors.txt -append
    continue
    }”

    Thanks..

  21. Hi Hugo,
    i tryed to run your great script against our Virtual Center.
    Starting fine…. but when the script reaches a VM running Linux an exception occured and the script stopped. I know running WMI – Commands against a Linux Host doesnt work – but – i am an absulute Powershell Beginner and therefore i have no idea to “help” the script continue after the exception.
    Do you have a idea to solve this?

    Thanks in advance and excuse my horrible english,
    Frank

  22. Hi all,

    I’ve recently had to do some work on some disk space reporting which may be of use. In terms of excluding ‘local’ datastore, the datastore view (get-datastore | get-view) contains summary.MultipleHostAccess. You can use this field, to exclude datastores that are local by ‘assuming’ that any VMFS or NFS volume that has MultipleHostAccess true, will be shared storage, and anything set to false will be local.

    Working well, so far.

    SP

    @admin

  23. Hi All,

    I know it’s been a bit since the last post but I have a quick question. The above script works great in my environment – really gives great info in the CSV. Is it possible to capture in that CSV what VMDK’s that the script finds that are powered off? I am very new to PowerShell – I did see that the script does know here:
    {
    Write-Host “VM is powered off” -ForegroundColor “yellow”
    }
    That a VM is off and points to the VMDK althougth it doesn’t know who the owner of the VMDK is…can this data be stored and also added to the CSV? This is to flag to me so I know what the LUN and Datastore picture is with all VM’s on but to also know what VM’s are currently off to ensure there is enough space on the LUN/Datastore when it is turned back on…

    Thanks for the great script

    Kevin Nelson

  24. @Kevin
    Okay, no problem. I do my best to keep supporting all scripts. Also plder ones.
    Try replacing the Write-Host “VM powered off” bit with this:
    # Create Output Object
    $myObj = “” | Select Datastore, DSSizeGB, DSFreeGB, DSPercentFree, DiskFile, VM, HardDisk, DriveLetter, DiskSizeGB, DiskFreeGB, PercFree
    # List datastore name
    $myObj.Datastore = $Datastore.Name
    # Determine datastore size in GB
    $myObj.DSSizeGB = [Math]::Round(($Datastore.CapacityMB * 1MB / 1GB),$Decimals)
    $myObj.DSFreeGB = [Math]::Round(($Datastore.FreeSpaceMB * 1MB / 1GB),$Decimals)
    # Determine datastore free space (DS%Free)
    $myObj.DSPercentFree = [Math]::Round((100*($Datastore.FreeSpaceMB/$Datastore.CapacityMB)),$Decimals)
    # List disk file name
    $myObj.DiskFile = $vmdk.Path
    # List VM Name
    $myObj.VM = $VMRef.VM
    # Determine virtual hard disk / logical drive
    $myObj.HardDisk = $VMRef.DiskName
    # Report driveletter
    $myObj.DriveLetter = “UNKNOWN: VM OFF”
    # Report Size
    $myObj.DiskSizeGB = “UNKNOWN: VM OFF”
    # Report Free Space
    $myObj.DiskFreeGB = “UNKNOWN: VM OFF”
    # Calculate Percentage free space
    $myObj.PercFree = “UNKNOWN: VM OFF”
    Write-Host “RESULT:” -ForegroundColor “yellow”
    $myObj
    # Add output object to output collection
    $myCol += $myObj

    Hugo

  25. Thank you very much it seems to have worked as I expected. I did get a lot of errors though at the end of the script:(this is a sample there was over a page of them in the toolkit screen….)

    Measure-Object : Property “DiskFreeGB” is not numeric.
    At C:\VMScripts\GetDataStoreInfoWithPoweredOff.ps1:203 char:65
    + $AverageDiskFree = [Math]::Round(100 * (($myCol | Measure-Object <<<< DiskFr
    eeGB -Sum).Sum / ($myCol | Measure-Object DiskSizeGB -Sum).Sum),$Decimals)
    Measure-Object : Property "DiskFreeGB" is not numeric.
    At C:\VMScripts\GetDataStoreInfoWithPoweredOff.ps1:203 char:65
    + $AverageDiskFree = [Math]::Round(100 * (($myCol | Measure-Object <<<< DiskFr
    eeGB -Sum).Sum / ($myCol | Measure-Object DiskSizeGB -Sum).Sum),$Decimals)
    Measure-Object : Property "DiskFreeGB" is not numeric.
    At C:\VMScripts\GetDataStoreInfoWithPoweredOff.ps1:203 char:65

    The outputed CSV seems to have the data I was looking for but there were these errors….

    Kevin

  26. Hi Hugo,

    I’m trying to run this script in our vSphere 4 evironment but i’m getting the error:

    Exception calling “SearchDatastoreSubFolders” with “2” argument(s): “Not initialized: boolean fileOwner”

    There is 1 esx 3.5 host available, connected to this host the script will run better, also with the same error, the file is present after running the script but no data inside it..

    Do you have any suggestion??

    Fabian

    1. I am getting the following error when I ran the code above

      Exception calling “SearchDataStoreSubFolders” with 2 arguments : “Permission to perform this operation was denied”

  27. Hi,

    Can you tell me how can I find out the poweroff Vm and also when it is poweroff and by whom with powershell script.

    I know how to get the poweroff vm, but not able to get the other details.

    If possible can you put your comments on this.

    Regards
    Gurjit Dhillon

  28. Hi,

    Is it possible to get all or most of the details returned by Get-WMIObject by using Get-VMguest instead? I’m trying to figure out how I can get the logical disk information without network access to the VM’s, such as in a DMZ.

    Cheers

    1. Hi Stephen,
      I’m afraid that won’t work. The only disk-related information Get-VMGuest returns is a list of logical volumes and sizes. For this script, you need the relationship between the vDisks and the logical volumes.
      Hugo

  29. This script is excellent and works great for my windows VM. Do you have suggestions for doing something similar to gain visibility into the disk usage by my Linux VMs?They all use LVM to manage the disk space.

  30. I have one for you. Im looking for a script that will list all the guests and their storage. Something that would be useful to a planning group.

  31. I am getting an exception when running the script:
    Exception calling “SearchDatastoreSubFolders” with “2” argument(s): “Cannot contact the specified host (xxxxxxxxxxxxx). The host may not be available on the network, a network configuration problem may exist, or the management services on this host may not be responding.”

    I know why I am getting the exception: the host is in Standby mode. I have a few hosts like that, ready to kick in some extra capacity if needed during heavy delevelopment cycles. The question is: is there a way to bypass the hosts that are in Standby mode (or unavailable for any reason) so that the script continues? I already added the following line $ErrorActionPreference = “SilentlyContinue”, but that does not seem to help… Any idea?

  32. This algorithm works with vmx-04 but with the addition of the newer controllers in vmx-07 (LSI Logic SAS and Paravirtual) the offset to SCSIPort is no longer fixed at one, but can be anywhere from 0 to 3 from what I have seen. Has anyone encountered this, and if so, found a solution?

  33. I am seeing the following error when running the scrip
    above and I am not sure why. Can you help? Attempted to divide by
    zero. At line:1 char:57 + $AverageDSFree = [Math]::Round(100 *
    ($TotalDSFree / <<< $Averag eDiskFree = [Math]::Round(100 * (($myCol | Measure-Object DiskFreeGB -Sum).Sum / ($myCol | Measure-Object DiskSizeGB -Sum).Sum),$Decimals) Attempted to divide by zero. At line:1 char:92 + $AverageDiskFree = [Math]::Round(100 * (($myCol | Measure-Object DiskFree GB -Sum).Sum / <<<< ($myCol | Measure-Object DiskSizeGB -Sum).Sum),$Decimals) + CategoryInfo : NotSpecified: (:) [], RuntimeException + FullyQualifiedErrorId : RuntimeException

  34. Hi, I tgried your script but its not working with vCenter 4.1. I get Messages following message: “vm xyz is off”, but all VM guest are running.

  35. I get the following error message:

    Attempted to divide by zero.
    At E:\Scripts\VM-Disks4.ps1:175 char:92
    + $AverageDiskFree = [Math]::Round(100 * (($myCol | Measure-Object DiskFreeGB -Sum).Sum / <<<< ($myCol | Measure-Object
    DiskSizeGB -Sum).Sum),$Decimals)
    + CategoryInfo : NotSpecified: (:) [], RuntimeException
    + FullyQualifiedErrorId : RuntimeException

    Could you give me an explanation why I get this error message?

  36. @Admin

    I still get the same error. I have a small test cluster running one VM currently (I know it sound sick :-)). I have the rights to do get-wmiobject queries. I don’t why it is saying attempted to divide by zero. That doesn’t make any sense to me.
    Do you have any other ideas?

    Complete powershell output:

    ====================================================
    VMDK VM01.vmdk belongs to VM VM01
    VM is powered on
    Read partition and disk information
    WARNING: NO MATCHES!
    ====================================================
    VMDK VM01_1.vmdk belongs to VM VM01
    VM is powered on
    Read partition and disk information
    WARNING: NO MATCHES!
    ====================================================
    VMDK VM01_2.vmdk belongs to VM VM01
    VM is powered on
    Read partition and disk information
    WARNING: NO MATCHES!
    ===================================================
    ===================================================

    Attempted to divide by zero.
    At E:\Scripts\petersonline-vmware-disk-usage.ps1:171 char:54
    + $AverageDSFree = [Math]::Round(100 * ($TotalDSFree / <<<< $TotalDSSize),$Decimals)
    + CategoryInfo : NotSpecified: (:) [], RuntimeException
    + FullyQualifiedErrorId : RuntimeException

    Attempted to divide by zero.
    At E:\Scripts\peetersonline-vmware-disk-usage.ps1:172 char:89
    + $AverageDiskFree = [Math]::Round(100 * (($myCol | Measure-Object DiskFreeGB -Sum).Sum / <<<< ($myCol | Measure-Object Di
    skSizeGB -Sum).Sum),$Decimals)
    + CategoryInfo : NotSpecified: (:) [], RuntimeException
    + FullyQualifiedErrorId : RuntimeException

    Total DS Free:
    Total DS Size:
    Average DS Free Percentage:
    Average Disk Free Percentage:

  37. Morpheus,
    Can you paste the output of the following commands?

    $vmView = Get-VM VM01 | Get-View
    $vmView.Config.Hardware.Device | Where {$_.DeviceInfo.Label -match "SCSI Controller"}
    Get-WmiObject -Class Win32_DiskDrive -ComputerName $vmView.Guest.HostName

    Hugo

  38. Thanks for your quick reply! Here is the output:

    HotAddRemove : True
    SharedBus : noSharing
    ScsiCtlrUnitNumber : 7
    BusNumber : 0
    Device : {2000, 2001, 2002}
    Key : 1000
    DeviceInfo : VMware.Vim.Description
    Backing :
    Connectable :
    ControllerKey : 100
    UnitNumber : 3
    DynamicType :
    DynamicProperty :

    Partitions : 1
    DeviceID : \\.\PHYSICALDRIVE0
    Model : VMware Virtual disk SCSI Disk Device
    Size : 48315294720
    Caption : VMware Virtual disk SCSI Disk Device

    Partitions : 3
    DeviceID : \\.\PHYSICALDRIVE1
    Model : VMware Virtual disk SCSI Disk Device
    Size : 48315294720
    Caption : VMware Virtual disk SCSI Disk Device

    Partitions : 1
    DeviceID : \\.\PHYSICALDRIVE2
    Model : VMware Virtual disk SCSI Disk Device
    Size : 21467980800
    Caption : VMware Virtual disk SCSI Disk Device

    1. Hmmm, not all properties are showing. My bad. Try this:

      $vmView = Get-VM VM01 | Get-View
      $vmView.Config.Hardware.Device | Where {$_.DeviceInfo.Label -match "SCSI Controller"} | fl *
      Get-WmiObject -Class Win32_DiskDrive -ComputerName $vmView.Guest.HostName | fl *
  39. No problem. Btw. the VM’s name is 912vmt01. New output:

    HotAddRemove : True
    SharedBus : noSharing
    ScsiCtlrUnitNumber : 7
    BusNumber : 0
    Device : {2000, 2001, 2002}
    Key : 1000
    DeviceInfo : VMware.Vim.Description
    Backing :
    Connectable :
    ControllerKey : 100
    UnitNumber : 3
    DynamicType :
    DynamicProperty :

    ConfigManagerErrorCode : 0
    LastErrorCode :
    NeedsCleaning :
    Status : OK
    DeviceID : \\.\PHYSICALDRIVE0
    StatusInfo :
    Partitions : 1
    BytesPerSector : 512
    ConfigManagerUserConfig : False
    DefaultBlockSize :
    Index : 0
    InstallDate :
    InterfaceType : SCSI
    MaxBlockSize :
    MaxMediaSize :
    MinBlockSize :
    NumberOfMediaSupported :
    SectorsPerTrack : 63
    Size : 48315294720
    TotalCylinders : 5874
    TotalHeads : 255
    TotalSectors : 94365810
    TotalTracks : 1497870
    TracksPerCylinder : 255
    __GENUS : 2
    __CLASS : Win32_DiskDrive
    __SUPERCLASS : CIM_DiskDrive
    __DYNASTY : CIM_ManagedSystemElement
    __RELPATH : Win32_DiskDrive.DeviceID=”\\\\.\\PHYSICALDRIVE0″
    __PROPERTY_COUNT : 51
    __DERIVATION : {CIM_DiskDrive, CIM_MediaAccessDevice, CIM_LogicalDevice, CIM_LogicalElement…}
    __SERVER : 912VMT01
    __NAMESPACE : root\cimv2
    __PATH : \\912VMT01\root\cimv2:Win32_DiskDrive.DeviceID=”\\\\.\\PHYSICALDRIVE0″
    Availability :
    Capabilities : {3, 4}
    CapabilityDescriptions : {Random Access, Supports Writing}
    Caption : VMware Virtual disk SCSI Disk Device
    CompressionMethod :
    CreationClassName : Win32_DiskDrive
    Description : Disk drive
    ErrorCleared :
    ErrorDescription :
    ErrorMethodology :
    FirmwareRevision : 1.0
    Manufacturer : (Standard disk drives)
    MediaLoaded : True
    MediaType : Fixed hard disk media
    Model : VMware Virtual disk SCSI Disk Device
    Name : \\.\PHYSICALDRIVE0
    PNPDeviceID : SCSI\DISK&VEN_VMWARE&PROD_VIRTUAL_DISK\5&22BE343F&0&000000
    PowerManagementCapabilities :
    PowerManagementSupported :
    SCSIBus : 0
    SCSILogicalUnit : 0
    SCSIPort : 2
    SCSITargetId : 0
    SerialNumber : 6000c295fce1c72fdac7991d60556608
    Signature : 4084640933
    SystemCreationClassName : Win32_ComputerSystem
    SystemName : 912VMT01
    Scope : System.Management.ManagementScope
    Path : \\912VMT01\root\cimv2:Win32_DiskDrive.DeviceID=”\\\\.\\PHYSICALDRIVE0″
    Options : System.Management.ObjectGetOptions
    ClassPath : \\912VMT01\root\cimv2:Win32_DiskDrive
    Properties : {Availability, BytesPerSector, Capabilities, CapabilityDescriptions…}
    SystemProperties : {__GENUS, __CLASS, __SUPERCLASS, __DYNASTY…}
    Qualifiers : {dynamic, Locale, provider, UUID}
    Site :
    Container :

    ConfigManagerErrorCode : 0
    LastErrorCode :
    NeedsCleaning :
    Status : OK
    DeviceID : \\.\PHYSICALDRIVE1
    StatusInfo :
    Partitions : 3
    BytesPerSector : 512
    ConfigManagerUserConfig : False
    DefaultBlockSize :
    Index : 1
    InstallDate :
    InterfaceType : SCSI
    MaxBlockSize :
    MaxMediaSize :
    MinBlockSize :
    NumberOfMediaSupported :
    SectorsPerTrack : 63
    Size : 48315294720
    TotalCylinders : 5874
    TotalHeads : 255
    TotalSectors : 94365810
    TotalTracks : 1497870
    TracksPerCylinder : 255
    __GENUS : 2
    __CLASS : Win32_DiskDrive
    __SUPERCLASS : CIM_DiskDrive
    __DYNASTY : CIM_ManagedSystemElement
    __RELPATH : Win32_DiskDrive.DeviceID=”\\\\.\\PHYSICALDRIVE1″
    __PROPERTY_COUNT : 51
    __DERIVATION : {CIM_DiskDrive, CIM_MediaAccessDevice, CIM_LogicalDevice, CIM_LogicalElement…}
    __SERVER : 912VMT01
    __NAMESPACE : root\cimv2
    __PATH : \\912VMT01\root\cimv2:Win32_DiskDrive.DeviceID=”\\\\.\\PHYSICALDRIVE1″
    Availability :
    Capabilities : {3, 4}
    CapabilityDescriptions : {Random Access, Supports Writing}
    Caption : VMware Virtual disk SCSI Disk Device
    CompressionMethod :
    CreationClassName : Win32_DiskDrive
    Description : Disk drive
    ErrorCleared :
    ErrorDescription :
    ErrorMethodology :
    FirmwareRevision : 1.0
    Manufacturer : (Standard disk drives)
    MediaLoaded : True
    MediaType : Fixed hard disk media
    Model : VMware Virtual disk SCSI Disk Device
    Name : \\.\PHYSICALDRIVE1
    PNPDeviceID : SCSI\DISK&VEN_VMWARE&PROD_VIRTUAL_DISK\5&22BE343F&0&000100
    PowerManagementCapabilities :
    PowerManagementSupported :
    SCSIBus : 0
    SCSILogicalUnit : 0
    SCSIPort : 2
    SCSITargetId : 1
    SerialNumber : 6000c2951c44d797d0bbffa986904b63
    Signature : 4084640957
    SystemCreationClassName : Win32_ComputerSystem
    SystemName : 912VMT01
    Scope : System.Management.ManagementScope
    Path : \\912VMT01\root\cimv2:Win32_DiskDrive.DeviceID=”\\\\.\\PHYSICALDRIVE1″
    Options : System.Management.ObjectGetOptions
    ClassPath : \\912VMT01\root\cimv2:Win32_DiskDrive
    Properties : {Availability, BytesPerSector, Capabilities, CapabilityDescriptions…}
    SystemProperties : {__GENUS, __CLASS, __SUPERCLASS, __DYNASTY…}
    Qualifiers : {dynamic, Locale, provider, UUID}
    Site :
    Container :

    ConfigManagerErrorCode : 0
    LastErrorCode :
    NeedsCleaning :
    Status : OK
    DeviceID : \\.\PHYSICALDRIVE2
    StatusInfo :
    Partitions : 1
    BytesPerSector : 512
    ConfigManagerUserConfig : False
    DefaultBlockSize :
    Index : 2
    InstallDate :
    InterfaceType : SCSI
    MaxBlockSize :
    MaxMediaSize :
    MinBlockSize :
    NumberOfMediaSupported :
    SectorsPerTrack : 63
    Size : 21467980800
    TotalCylinders : 2610
    TotalHeads : 255
    TotalSectors : 41929650
    TotalTracks : 665550
    TracksPerCylinder : 255
    __GENUS : 2
    __CLASS : Win32_DiskDrive
    __SUPERCLASS : CIM_DiskDrive
    __DYNASTY : CIM_ManagedSystemElement
    __RELPATH : Win32_DiskDrive.DeviceID=”\\\\.\\PHYSICALDRIVE2″
    __PROPERTY_COUNT : 51
    __DERIVATION : {CIM_DiskDrive, CIM_MediaAccessDevice, CIM_LogicalDevice, CIM_LogicalElement…}
    __SERVER : 912VMT01
    __NAMESPACE : root\cimv2
    __PATH : \\912VMT01\root\cimv2:Win32_DiskDrive.DeviceID=”\\\\.\\PHYSICALDRIVE2″
    Availability :
    Capabilities : {3, 4}
    CapabilityDescriptions : {Random Access, Supports Writing}
    Caption : VMware Virtual disk SCSI Disk Device
    CompressionMethod :
    CreationClassName : Win32_DiskDrive
    Description : Disk drive
    ErrorCleared :
    ErrorDescription :
    ErrorMethodology :
    FirmwareRevision : 1.0
    Manufacturer : (Standard disk drives)
    MediaLoaded : True
    MediaType : Fixed hard disk media
    Model : VMware Virtual disk SCSI Disk Device
    Name : \\.\PHYSICALDRIVE2
    PNPDeviceID : SCSI\DISK&VEN_VMWARE&PROD_VIRTUAL_DISK\5&22BE343F&0&000200
    PowerManagementCapabilities :
    PowerManagementSupported :
    SCSIBus : 0
    SCSILogicalUnit : 0
    SCSIPort : 2
    SCSITargetId : 2
    SerialNumber : 6000c296c6c454bb5777618a3576bdcb
    Signature : 4084640899
    SystemCreationClassName : Win32_ComputerSystem
    SystemName : 912VMT01
    Scope : System.Management.ManagementScope
    Path : \\912VMT01\root\cimv2:Win32_DiskDrive.DeviceID=”\\\\.\\PHYSICALDRIVE2″
    Options : System.Management.ObjectGetOptions
    ClassPath : \\912VMT01\root\cimv2:Win32_DiskDrive
    Properties : {Availability, BytesPerSector, Capabilities, CapabilityDescriptions…}
    SystemProperties : {__GENUS, __CLASS, __SUPERCLASS, __DYNASTY…}
    Qualifiers : {dynamic, Locale, provider, UUID}
    Site :
    Container :

  40. Odd. You’re SCSI bus:target numbers appear to be off. Try replacing this line of code in the script and see whether you get a match:

    #REPLACE
    $DiskMatch = $Disks | ?{($_.SCSIPort - 1) -eq $VMRef.SCSIController -and $_.SCSITargetID -eq $VMRef.SCSITarget}
    #WITH
    $DiskMatch = $Disks | ?{($_.SCSIPort - 2) -eq $VMRef.SCSIController -and ($_.SCSITargetID + 1) -eq $VMRef.SCSITarget}

    Hugo

  41. Wait, my bad (again). Show me the output of the following commands:

    $vmView = Get-VM VM01 | Get-View
    ForEach ($VirtualSCSIController in ($VMView.Config.Hardware.Device | Where {$_.DeviceInfo.Label -match "SCSI Controller"}))
    {
    	Write-Host $VirtualSCSIController.BusNumber
    	$VMView.Config.Hardware.Device | Where {$_.ControllerKey -eq $VirtualSCSIController.Key} | Select UnitNumber
    }

    Hugo

  42. Aha! It is only the SCSI bus ID that is off. Make this adjustment to the original script and you should get results:

    #REPLACE
    $DiskMatch = $Disks | ?{($_.SCSIPort - 1) -eq $VMRef.SCSIController -and $_.SCSITargetID -eq $VMRef.SCSITarget}
    #WITH
    $DiskMatch = $Disks | ?{($_.SCSIPort - 2) -eq $VMRef.SCSIController -and $_.SCSITargetID -eq $VMRef.SCSITarget}

    Hugo

  43. Cool it works! Thank you very much! Could you give me a short explanation what’s the difference between $_.SCSIPort – 1 and $_.SCSIPort – 2?

    1. A disk in Windows (and probably in Linux) gets a SCSI ID in the form of x:y, where x is a number indicating the SCSI Bus i.e. controller and y is the port i.e. disk. Take a look at Edit Settings for your VM and find each disk’s SCSI ID. In your case 0:0, 0:1 and 0:2.
      The script uses this ID to match the disks of your vm’s to the disk info found via WMI.
      In your case, WMI lists the IDs as 2:0, 2:1 and 2:2. In my testlab it reports 1:0,1:1 and 1:2 for the same vm disks. So instead of subtracting 1 from the SCSI Bus ID in my case, you need to subtract two.
      Hugo

  44. Dear Hugo,

    I did a test on our big cluster now. I see for some VMs WMI lists the IDs as 2:0, 2:1 and 2:2 but for others it lists the IDs as 1:0, 1:1 and 1:2. The strange thing is these VMs (w2k8R2) were installed with the same image. What could I do to get results from all VMs no matter if their IDs are 1 or 2? Thanks a lot for your help!

  45. One possible in one scenario: if you are certain you never use more than one SCSI Controller in a vm. Then you can remove the checking of the SCSI Bus ID:

    #REPLACE
    $DiskMatch = $Disks | ?{($_.SCSIPort - 1) -eq $VMRef.SCSIController -and $_.SCSITargetID -eq $VMRef.SCSITarget}
    #WITH
    $DiskMatch = $Disks | ?{$_.SCSITargetID -eq $VMRef.SCSITarget}

    Hugo

  46. I do not get results.

    this is the only output i receive.

    =============================
    =============================
    Total DS Free:
    Total DS Size:
    Average DS Free Percentage:
    Average Disk Free Percentage:

    Please help.

  47. I’m getting errors like:
    The term ‘Connect-VIServer’ is not recognized as the name of a cmdlet, function
    , script file, or operable program. Check the spelling of the name, or if a pat
    h was included, verify that the path is correct and try again.
    At C:\getdiskspace.ps1:10 char:23
    + $VC = Connect-VIServer <<<< $VCServer + CategoryInfo : ObjectNotFound: (Connect-VIServer:String) [], Co mmandNotFoundException + FullyQualifiedErrorId : CommandNotFoundException

  48. I get the same thing as Molotsi:

    =============================
    =============================
    Total DS Free:
    Total DS Size:
    Average DS Free Percentage:
    Average Disk Free Percentage:

    Is this because I tried to add the DiskFileSizeGB object you mentioned in the comments in the Script Repository post? Your script is what I’m looking for, however, without the DiskFileSizeGB object, it doesn’t give what I need.. Thanks in advance!

  49. Hi,

    Looks like win32_diskdrive’s scsiport -1 or scsiport- 2 doesnt always work for all environments.

    For example in my environment for scsi controllers 0, 1, 2, 3 bus numbers are 0, 1, 2, 3 respectively.

    I have attached vmdks to these sci controllers but the windows assigned random port numbers.

    it assigned 2, 5, 4, 3 for the disks that are attached 0, 1, 2, 3 scsi controllers.

    So am i missing something? is there any other way to map a vmdk to a windows physical disk.

    Regards,

    Dreamer

  50. this sript is excactly that what i need.

    but when i tried it, i just get a “VM is powered off” but im sure our filesevers are powered on…

    how comes that?

Leave a Reply