Storage Script Extracts and Examples
VM's with Datastores List
List of Virtual Machines, and their datastores (with usage)
$datastoreExp = @{N="Datastore"; E={ ($_ | get-datastore | select-object -first 1).Name }}
$diskSizeExp = @{N="Total Disk"; E={ ($_ | get-harddisk | measure-object -property CapacityKB -sum).Sum }}
get-vm | select Name, $datastoreExp, $diskSizeExp | sort -property Datastore,"Total Disk"
VM Storage Usage
Total storage usage (including any snapshots, logs, etc, etc), not just the VMDK files. Adapted from post by Arnim van Lieshout http://www.van-lieshout.com/2009/07/how-big-is-my-vm/
function Get-VMDiskUsage($vm2do)
{
#Initialize variables
$VMDirs =@()
$VMSize = 0
$searchSpec = New-Object VMware.Vim.HostDatastoreBrowserSearchSpec
$searchSpec.details = New-Object VMware.Vim.FileQueryFlags
$searchSpec.details.fileSize = $TRUE
Get-View -VIObject $vm2do | % {
#Create an array with the vm's directories
$VMDirs += $_.Config.Files.VmPathName.split("/")[0]
$VMDirs += $_.Config.Files.SnapshotDirectory.split("/")[0]
$VMDirs += $_.Config.Files.SuspendDirectory.split("/")[0]
$VMDirs += $_.Config.Files.LogDirectory.split("/")[0]
#Add directories of the vm's virtual disk files
foreach ($disk in $_.Layout.Disk) {
foreach ($diskfile in $disk.diskfile){
$VMDirs += $diskfile.split("/")[0]
}
}
#Only take unique array items
$VMDirs = $VMDirs | Sort | Get-Unique
foreach ($dir in $VMDirs){
$ds = Get-Datastore ($dir.split("[")[1]).split("]")[0]
$dsb = Get-View (($ds | get-view).Browser)
$taskMoRef = $dsb.SearchDatastoreSubFolders_Task($dir,$searchSpec)
$task = Get-View $taskMoRef
while($task.Info.State -eq "running" -or $task.Info.State -eq "queued"){$task = Get-View $taskMoRef }
foreach ($result in $task.Info.Result){
foreach ($file in $result.File){
$VMSize += $file.FileSize
}
}
}
}
# VM disk usage in GB
$VMSize/1048576000
}
Get-VMDiskUsage (Get-VM "MyVM")
ESX Storage Events
Creates a CSV of storage events (eg path up/downs). Useful in order to be analyse storage events, for example if you need to tally up to SAN logs etc. Note the get-VIEvent
is limited to 1000 results, which will typically get 1 - 2 days worth depending on your infrastructure. To get a longer history would require multiple calls to get-VIEvent
using the -Start
and -Finish
parameters
$OutputFile = "ESX-EventsStorage.csv"
$Results = @()
$events = Get-VIEvent -MaxSamples 1000 | Where {$_.EventTypeID -like "esx.*.storage.*"}
foreach ($event in $events) {
$row = "" | Select Date, Host, EventID, Device, Datastore, Path
$row.Date = $event.CreatedTime
$row.Host = $event.Host.Name.Split(".")[0]
$row.EventID = $event.EventTypeID
# Allow for Argument Keys being mixed up between "problem" aka fault start and "clear" aka fault end events
$row.Device = $event.Arguments[0].Value
if ($row.EventID -like "esx.problem.*") {
$row.Datastore = $event.Arguments[2].Value
$row.Path = $event.Arguments[1].Value
} elseif ($row.EventID -like "esx.clear.*") {
$row.Datastore = $event.Arguments[1].Value
$row.Path = $event.Arguments[2].Value
} else {
Write-Host "ERROR: Unexpected EventTypeID - " $row.EventID
}
$Results = $Results + $row
}
$Results | Format-Table *
$Results | Export-Csv -path $OutputFile -NoTypeInformation
ESX Datastore to LUN Mapping (ESX3)
Its bizarrely difficult to be able to map VMware presented datastore names to the underlying LUN's, despite the fact that its readily available via the VI Client. The following was adapted from the work of Catman found in this forum thread - http://communities.vmware.com/thread/240466#240466. As I expect to maybe want some of the other fields available during the working my notes from working through this are to be found here
# Thieved and adapted from the good work by catman...
# http://communities.vmware.com/thread/240466#240466
$objESX = Get-VMHost "My_ESX*"
# Get .NET views for host and storage system
$objViewESX = Get-View -id $objESX.id
$objViewESXstorageSys = Get-View -id $objViewESX.ConfigManager.StorageSystem
# Get FC HBAs
$HBAs = $objViewESXstorageSys.StorageDeviceInfo.HostBusAdapter | Where-Object {$_.Key -like "*FibreChannelHba*"}
foreach ($hba in $HBAs) {
# Enumerate LUNs
$LUNcount = $objViewESXstorageSys.StorageDeviceInfo.MultiPathInfo.Lun.Length
for ($LUNidx = 0; $LUNidx -lt $LUNcount; $LUNidx++ ) {
$objScsiLUN = $objViewESXstorageSys.StorageDeviceInfo.MultiPathInfo.Lun[$LUNidx]
# Enumerate paths on LUN
$PathCount = $objScsiLUN.Path.Length
for ($PathIdx = 0; $PathIdx -lt $PathCount; $PathIdx++) {
$objSCSIpath = $objViewESXstorageSys.StorageDeviceInfo.MultiPathInfo.Lun[$LUNidx].Path[$PathIdx]
# Only care about one path, active on current HBA
if (($objSCSIpath.PathState -eq "active") -and ($objSCSIpath.Adapter -eq $hba.Key)) {
# Now get the disk that we want
$objSCSIdisk = $objViewESXstorageSys.StorageDeviceInfo.ScsiLun | Where-Object{ ($_.CanonicalName -eq $objScsiLUN.Id) -and ($_.DeviceType -eq "disk") }
# Now get the datastore info for disk
$MountCount = $objViewESXstorageSys.FileSystemVolumeInfo.MountInfo.Length
for ($MountIdx = 0; $MountIdx -lt $MountCount; $MountIdx++ ) {
if ($objViewESXstorageSys.FileSystemVolumeInfo.MountInfo[$MountIdx].Volume.Type -eq "VMFS" ) {
$objVolume = $objViewESXstorageSys.FileSystemVolumeInfo.MountInfo[$MountIdx].Volume
$ExtentCount = $objVolume.Extent.Length
for ($ExtentIdx = 0; $ExtentIdx -lt $ExtentCount; $ExtentIdx++ ) {
$objExtent = $objVolume.Extent[$ExtentIdx]
# Match extent name to disk name
if ($objExtent.DiskName -eq $objSCSIdisk.CanonicalName) {
Write-Host($objSCSIdisk.Vendor + " " + $objSCSIdisk.Model + " " + $objSCSIdisk.CanonicalName + "`t" + $objVolume.Name)
}
}
}
}
}
}
}
}
Gives an output a bit like this...
HP HSV200 vmhba1:0:20 VMFS-DS-08 HP HSV200 vmhba1:0:7 VMFS-DS-01 HP HSV200 vmhba1:0:22 VMFS-DS-10 HP HSV200 vmhba1:0:8 VMFS-DS-02 HP HSV200 vmhba1:0:10 VMFS-DS-03 HP HSV200 vmhba1:0:18 VMFS-DS-07 HP HSV200 vmhba1:0:21 VMFS-DS-09 HP HSV200 vmhba1:0:12 VMFS-DS-05 HP HSV200 vmhba1:0:11 VMFS-DS-04 HP HSV200 vmhba1:0:3 VMFS-DS-Templates HP HSV200 vmhba1:0:2 VMFS-DS-ISOs HP HSV200 vmhba1:0:30 VMFS-DS-SCRATCH HP HSV200 vmhba1:0:13 VMFS-DS-06
ESX Datastore to LUN Mapping (ESX4)
Produces a similar output to the above, but works for ESX4 servers.
function Get-DS-LUNs-v4 ($objESXs) {
foreach ($cluster in (Get-View -ViewType "ClusterComputeResource")) {
$vmhostsview = $cluster.host | % { Get-View $_ }
$vmhostview = $vmhostsview | Select -first 1
$ScsiLuns = $vmhostsview | % { $_.Config.StorageDevice.ScsiLun } | Select -unique *
$UUIDs = $ScsiLuns | Select -unique UUID
$Datastores = $vmhostsview | % { $_.Config.FileSystemVolume.MountInfo } | % { $_.Volume } | Select -Unique *
$HostLUN = $vmhostsview | % { $_.Config.StorageDevice.ScsiTopology.Adapter } | % { $_.Target | % { $_.LUN } } | Select -unique *
foreach ($UUID in $UUIDs) {
$Lun = $ScsiLuns | ? { $_.UUID -eq $UUID.UUID } | Select -first 1
$objVolume = "" | Select Datastore, Make, Model, LUN
$objVolume.LUN = ($HostLUN | ? { $_.ScsiLun -eq $Lun.Key } | select -unique LUN).LUN
$objVolume.Make = $Lun.Vendor
$objVolume.Model = $Lun.Model
foreach ($vol in $Datastores) {
if ($vol.extent | % { $_.diskname -eq $Lun.CanonicalName}) {
$objVolume.Datastore = $vol.Name
}
}
$objVolume
}
}
}