List NFS Datastore Usage

Some time ago someone we agreed on putting a minimum of 15 Virtual Machines on each NFS-volume on our NetApp storage. Now, almost a year later we have about 14 NFS volumes and the spreading of the VM’s on the Volumes have become a bit out of the ordinary. Mostly because we didn’t have an easy overview of how many VM’s there are present on each volume or because VM’s needed to be created on a short notice.

Since I’ve been busy with PowerShell I decided to create a nice script/utility to create this overview and to increase our insight in our NFS volumes. At first I made a console script, but soon -while I was discovering the posibilities of PowerShell- I created a GUI for it using PrimalForms.

List NFS Store Usage - Example Output

List NFS Store Usage - Example Output

The source is no rocket science, but I just found the utility very handy/helpful to monitor our storage environment for VMware. If you intend to use this sourcecode, don’t forget to adjust the VirtualCenter hostname and access credentials. Also, the names of our DataStores are all start with “VMWare_NFSxx” and I have a condition running to check if the DataStore name starts with that. You might want to adjust that to your datastore name convention.

#Generated Form Function
function GenerateForm {

#region Import the Assemblies
[reflection.assembly]::loadwithpartialname("System.Windows.Forms") | Out-Null
[reflection.assembly]::loadwithpartialname("System.Drawing") | Out-Null
#endregion

#region Generated Form Objects
$form1 = New-Object System.Windows.Forms.Form
$button1 = New-Object System.Windows.Forms.Button
$progressBar1 = New-Object System.Windows.Forms.ProgressBar
$treeView1 = New-Object System.Windows.Forms.TreeView
$label1 = New-Object System.Windows.Forms.Label
$InitialFormWindowState = New-Object System.Windows.Forms.FormWindowState
#endregion Generated Form Objects

#----------------------------------------------
#Generated Event Script Blocks
#----------------------------------------------
#Provide Custom Code for events specified in PrimalForms.
$handler_treeView1_AfterSelect=
{
#TODO: Place custom script here

}

$handler_button1_Click=
{
    $button1.Enabled = $False
    $vcHost = "your.vc.server"
    $vcClusterName = "Cluster KA"
    $vcUser = "username-to-connect-to-vc"
    $vcPass = "password-to-connect-to-vc"

    $label1.Text = "Connecting to $vcHost"
    [Windows.Forms.Application]::DoEvents()
    $vcServer = Connect-VIServer -Server:$vcHost -User:$vcUser -Password:$vcPass -WarningAction:SilentlyContinue

    $TVroot = New-Object System.Windows.Forms.TreeNode
    $TVroot.Text = $vcHost
    $TVroot.Name = $vcHost

    $treeView1.Nodes.Add($TVroot)|Out-Null

    If ($vcServer) {
        $label1.Text = "Connected to $vcHost"
        $progressBar1.Value = 10
        [Windows.Forms.Application]::DoEvents()

        $label1.Text = "Retreiving Cluster Data of '$vcClusterName'"
        $vcCluster = Get-Cluster -Server:$vcServer -Name:$vcClusterName
        $progressBar1.Value = 25
        [Windows.Forms.Application]::DoEvents()

        $label1.Text = "Retreiving Datacenters"
        $vcDataCenter = Get-Datacenter -Cluster:$vcCluster
        $progressBar1.Value = 30
        [Windows.Forms.Application]::DoEvents()

        $label1.Text = "Retreiving Datastores of",$vcDataCenter.Name
        $vcDataStores = Get-Datastore -Datacenter:$vcDataCenter | Sort
        $progressBar1.Value = 35
        [Windows.Forms.Application]::DoEvents()
    }

    $label1.Text = "Retreiving VM diagnostics on '$vcCluster'"
    $vcVirtualMachines = Get-VM -Location:$vcCluster | Sort
    $progressBar1.Value = 40
    [Windows.Forms.Application]::DoEvents()

    $progressStep = ($progressBar1.Maximum - $progressBar1.Value) / $vcVirtualMachines.Length

    ForEach ($DataStore in $vcDataStores) {
        If ($DataStore.Name -like "VMWare_NFS*") {
            $DSName = $DataStore.Name

            $DSSize = [System.Math]::Round($DataStore.CapacityMB / 1024,1)
            $DSFree = [System.Math]::Round($DataStore.FreeSpaceMB / 1024,1)

            $TVnode = New-Object System.Windows.Forms.TreeNode
            $TVnode.Name = $DSName
            $TVnode.Text = $DSName, "Capacity: ",$DSSize," GB / Free: ",$DSFree," GB"

            $TVroot.Nodes.Add($TVnode)

            $vmCount = 0

            ForEach ($vcVM in $vcVirtualMachines) {
                If ($vcVM.HardDisks[0].Filename -like "*$DSName*") {
                    $progressBar1.Value += $progressStep

                    $TVsub = New-Object System.Windows.Forms.TreeNode
                    $TVsub.Name = $vcVM.Name
                    $TVsub.Text = $vcVM.Name

                    ForEach ($vmHardDisk in $vcVM.HardDisks) {
                        $vmCapacity = [System.Math]::Round(($vmHardDisk.CapacityKB / 1024) / 1024,1)
                        $TVchild = New-Object System.Windows.Forms.TreeNode

                        $TVchild.Name = $vmHardDisk.Name
                        $TVchild.Text = $vmHardDisk.Name, " (Capacity: ",$vmCapacity,"GB)"

                        $TVsub.Nodes.Add($TVchild)
                        [Windows.Forms.Application]::DoEvents()
                    }

                    $TVnode.Nodes.Add($TVsub)
                    $vmCount = $vmCount + 1

                    [Windows.Forms.Application]::DoEvents()
                }
                $TVnode.Text = $DSName, "Capacity: ",$DSSize," GB / Free: ",$DSFree," GB ($vmCount)"
            }
        }
    }

    $progressBar1.Value = 100
    $label1.Text = "Done"

    Disconnect-VIServer -Server:$vcServer -Confirm:$false

    $button1.Enabled = $True
    $label1.Text = "Idle"
}

$OnLoadForm_StateCorrection=
{#Correct the initial state of the form to prevent the .Net maximized form issue
    $form1.WindowState = $InitialFormWindowState
}

#----------------------------------------------
#region Generated Form Code
$form1.Text = 'VMware Volume Statistics by Laurens de Koning'
$form1.Name = 'form1'
$form1.DataBindings.DefaultDataSourceUpdateMode = 0
$form1.MaximizeBox = $false
$System_Drawing_Size = New-Object System.Drawing.Size
$System_Drawing_Size.Width = 394
$System_Drawing_Size.Height = 572
$form1.ClientSize = $System_Drawing_Size

$button1.TabIndex = 1
$button1.Name = 'button1'
$System_Drawing_Size = New-Object System.Drawing.Size
$System_Drawing_Size.Width = 129
$System_Drawing_Size.Height = 23
$button1.Size = $System_Drawing_Size
$button1.UseVisualStyleBackColor = $True

$button1.Text = 'Generate Statistics'

$System_Drawing_Point = New-Object System.Drawing.Point
$System_Drawing_Point.X = 12
$System_Drawing_Point.Y = 9
$button1.Location = $System_Drawing_Point
$button1.DataBindings.DefaultDataSourceUpdateMode = 0
$button1.add_Click($handler_button1_Click)

$form1.Controls.Add($button1)

$label1.TabIndex = 4
$label1.TextAlign = 4
$System_Drawing_Size = New-Object System.Drawing.Size
$System_Drawing_Size.Width = 353
$System_Drawing_Size.Height = 20
$label1.Size = $System_Drawing_Size
$label1.Text = 'Idle'

$System_Drawing_Point = New-Object System.Drawing.Point
$System_Drawing_Point.X = 13
$System_Drawing_Point.Y = 38
$label1.Location = $System_Drawing_Point
$label1.DataBindings.DefaultDataSourceUpdateMode = 0
$label1.Name = 'label1'

$form1.Controls.Add($label1)

$progressBar1.DataBindings.DefaultDataSourceUpdateMode = 0
$System_Drawing_Size = New-Object System.Drawing.Size
$System_Drawing_Size.Width = 353
$System_Drawing_Size.Height = 28
$progressBar1.Size = $System_Drawing_Size
$progressBar1.TabIndex = 3
$System_Drawing_Point = New-Object System.Drawing.Point
$System_Drawing_Point.X = 12
$System_Drawing_Point.Y = 64
$progressBar1.Location = $System_Drawing_Point
$progressBar1.Name = 'progressBar1'

$form1.Controls.Add($progressBar1)

$System_Drawing_Size = New-Object System.Drawing.Size
$System_Drawing_Size.Width = 353
$System_Drawing_Size.Height = 421
$treeView1.Size = $System_Drawing_Size
$treeView1.Name = 'treeView1'

$System_Drawing_Point = New-Object System.Drawing.Point
$System_Drawing_Point.X = 12
$System_Drawing_Point.Y = 103
$treeView1.Location = $System_Drawing_Point
$treeView1.DataBindings.DefaultDataSourceUpdateMode = 0
$treeView1.TabIndex = 0
$treeView1.add_AfterSelect($handler_treeView1_AfterSelect)

$form1.Controls.Add($treeView1)

#endregion Generated Form Code

#Save the initial state of the form
$InitialFormWindowState = $form1.WindowState
#Init the OnLoad event to correct the initial state of the form
$form1.add_Load($OnLoadForm_StateCorrection)
#Show the Form
$form1.ShowDialog()| Out-Null

} #End Function

#Call the Function
GenerateForm
  1. Thanks for posting the code for your utility. It helps having a VMware related example in figuring out how powershell code fits into the PrimalForms GUI generated templates.

  1. No trackbacks yet.