Storage Script Extracts and Examples

From vWiki
Jump to: navigation, search

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
      }
    }
}