30 October 2014

XtremIO PowerShell Module Updated -- v0.6.0 available!

XtremIO + PowerShell!Oh, boy -- more updates!  I committed the module at version 0.6.0 on 24 Sep 2014, and am just now making the time to post about it.  Plenty of good stuff in this release, with some preparation for changes to come. The release notes and change log are in the repo, of course, at https://github.com/mtboren/XtremIO.Utils, but some of the highlights:
  • added explicit Get-XIO* cmdlets for object types, in place of using -ItemType on the Get-XIOItemInfo cmdlet, so as to make things more PowerShell-y
  • more properties available, including loads of performance-related items in a new PerformanceInfo property for many objects
  • added support for new things available in the XIOS v3.0 release (properties, object types)
And, I recently added XtremIO.Utils as a module available via PsGet, so installing/updating the module becomes a snap for PsGet module users.  The quick how-to on using PsGet to install the XtremIO.Utils module:
PS vN:\> Install-Module -Verbose -Module XtremIO.Utils

Or, to update the existing version you may already have:
PS vN:\> Update-Module -Verbose -Module XtremIO.Utils

Or, if you like the "old fashioned" module management route (of manually handling the module grab), you can always follow the steps outlined in our previous XtremIO post here.

And, a couple of futures, in development for the next version of this module:
  • Connect-XIOServer / Disconnect-XIOServer, so as to handle credentials at a connection level instead of a per-call for every cmdlet
  • more New-XIO* cmdlets
In the meantime, enjoy!

30 July 2014

XtremIO PowerShell Module Updated -- Now with New-XIO* Functions!

XtremIO + PowerShell!Since releasing the XtremIO PowerShell module that had "Get" capabilities (about which you can read in our previous XtremIO + PowerShell post, if you missed it), we've been working to improve the module!  Some such improvements:
  • added functions to cover New-XIO* activities, for things like volumes and initiator groups (yes, with -WhatIf)
  • added credential storing, so that you need not specify credentials for every call
  • expanded Get-XIOItemInfo to support more object types (as the API has expanded), like volume folders, initiator group folders, target groups, and bricks
  • updated numeric properties on return objects to actually be numeric (were returned as strings, previously)
  • added function to open the Java GUI (most of the time, "yuck", but, sometimes useful)
  • changed the module name to XtremIO.Utils, as it now does more than reporting information
In the works:  making module available via PsGet, so that it is that much easier to get.  I shall update this post once this is done.

* Update 28 Oct 2014:
Made the time to make this module available via the extra-cool PsGet.  In order to install the XtremIO.Utils module via PsGet's Install-Module:
PS vN:\> Install-Module -Verbose -Module XtremIO.Utils

That's it -- no muss, no fuss!  And, have a look at the PsGet page to see the easy, one-line install of the PsGet module itself if you do not already use it.
End of update - 28 Oct 2014

Now, how about some examples?  Sure!

Create an encrypted, stored credential, that the functions in this module will use by default (so you need not specify credentials for every command):
PS vN:\> New-XIOStoredCred
Windows PowerShell credential request.
Enter credentials to use for XtremIO access
User: mattXio
Password for user mattXio: *********************

VERBOSE: Credentials encrypted (via Windows Data Protection API) and saved to:
'C:\Users\Matt\AppData\Local\Temp\xioCred_by_Matt_on_VM-MattDesktop-002.enc.xml'

Create a new volume:
PS vN:\> New-XIOVolume -ComputerName myxms0.dom.com -Name testvol3 -SizeGB 5120 -ParentFolder "/testVols"

Name        NaaName   VolSizeTB   IOPS
----        -------   ---------   ----
testvol3              5.00        0

Note: there is no NaaName value at this piont, as the NaaName property does not get populated in the volume object until the volume has been mapped to an initiator group for the first time

Create a new initiator group:
PS vN:\> New-XIOInitiatorGroup -ComputerName myxms0.dom.com -Name testIG0 -ParentFolder "/testIGs" -InitiatorList @{"myserver-hba2" = "10:00:00:00:00:00:00:F4"; "myserver-hba3" = "10:00:00:00:00:00:00:F5"}

Name     Index   NumInitiator   NumVol   IOPS
----     -----   ------------   ------   ----
testIG0  21      2              0        0

Create a new initiator group for each host in a cluster:
PS vN:\> ## general params to use for each New-XIOInitiatorGroup call
PS vN:\> $hshGeneralParamsForNewXioIG = @{
    Computer = "myxms0.dom.com"
    TrustAllCert = $true
    Port = 443
    WhatIf = $true
} ## end hashtable

PS vN:\> ## get the HBA WWNs for the VMHosts in the given cluster, and for each VMHost, create a new XtremIO initiator group with initiators for each HBA
PS vN:\> Get-Cluster -Name myCluster0 -PipelineVariable cluThisOne | Get-VMHostHBAWWN | Group-Object -Property @{e={$_.VMHostName.Split(".")[0]}} | Foreach-Object{
    $strVMHostShortname = $_.Name
    ## make a hashtable of key/value pairs that are initiator-name => HBA WWN; initiator names will be like "myhost0-hba2"
    $_.Group | Foreach-Object -begin {$hshInitList = @{}} {$hshInitList["${strVMHostShortname}-$($_.DeviceName.Replace("vmhba","hba"))"] = $_.HBAPortWWN}
    ## make a hashtable of parameters specific to this new initiator group to make
    $hshParamForNewXioIG = @{
        Name = $strVMHostShortname
        InitiatorList = $hshInitList
        ParentFolder = "/$($cluThisOne.Name)"
    } ## end hashtable
    ## create the new initiator group via the given params
    New-XIOInitiatorGroup @hshGeneralParamsForNewXioIG @hshParamForNewXioIG
} ## end foreach-object

Name      Index   NumInitiator   NumVol   IOPS
----      -----   ------------   ------   ----
myhost0   21      2              0        0
myhost1   22      2              0        0
...

This creates an initiator group for each VMHost in the given cluster, each group with an initiator for each of the VMHost's HBAs.  Utilizes the vNugglets function Get-VMHostHBAWWN that we posted in Get VMHost FC HBA WWN Info Most Quickly.  These initiator groups are created in the existing initiator-group folder that is defined for this cluster (of the same name as the cluster).

Open the management console (Java GUI):
PS vN:\> Open-XIOMgmtConsole myxms0.dom.com


Credentials discussion:
Stored credentials are encrypted using the Windows Data Protection API, via a derivative of HalR9000's Export-PSCredential.  If the encrypted credential file is found at runtime of any of the module's functions that require credentials, the credentials will be imported from said file transparently.

Decryption of the encrypted credentials can only be performed by the user account that performed the encryption, and on the same computer on which the encryption was performed.  This module stores the credential file in the ${env:temp} directory by default, and this location is configurable as desired.

If no credentials are specified to the functions of this module, the given function will look for the credential file in the configured location.  If none exists, the functions behave as before:  they will prompt for credentials as necessary.  And, you can get the stored credential with Get-XIOStoredCred, and remove it from disk, if you would like, with Remove-XIOStoredCred.

To use the module, just:  (also, updated above:  install this module via PsGet. See update at top of post)
  1. download from latest and greatest! https://github.com/mtboren/XtremIO.Utils/releases/download/Latest/XtremIO.Utils.zip
  2. unzip somewhere you like (like, say, in Join-Path ${env:\userprofile} "Documents\WindowsPowerShell\Modules")
  3. you should now have a folder named <pathToModules>\XtremIO.Utils, in which the PowerShell files reside (see note in previous XtremIO + PowerShell post about using Unblock-File, since this module is not yet Authenticode signed)
  4. Import-Module <pathToModules>\XtremIO.Utils

Other upcoming changes:
  • add the other New-XIO* functions for things like folders, single initiators, lun-maps, more
  • expand Get-XIOItemInfo to support even more object types (as the API continues to expand), like volume snapshots, events, dataprotection-groups
  • actually get the project on GitHub
Enjoy, and let us know what features would be best to add the soonest!

* Update 06 Aug 2014:  included the MIT License file in the .zip file.

17 July 2014

Get VMHost FC HBA WWN Info Most Quickly with PowerCLI

VMHba WWN Info
People know about getting VMHost HBA info via PowerCLI -- there are plenty of posts about doing so, generally via Get-VMHostHba.  Since that works great, there is barely a reason to write something else to do the same thing, save one reason that is near and dear to our vNugglets hearts:  speed.  We made this a couple of years ago, have tweaked it a few times, and now it seems like time to post it (like, maybe it will be helpful in an upcoming post, or something?  So exciting).

This function uses everybody's favorite PowerCLI cmdlet Get-View.  The speed reward:  well worth it.  For example:
Technique
Time, 28 hosts
Time, 270 hosts
Get-VMHostHba
61.9s
720s
Get-VMHostHBAWWN
1.32s
14.1s
improvement:
46x
51x

More than 45 times faster?  I'm in.  Now for the function, complete with examples in comment-based help:  (double-click anywhere in the code to Select All)
function Get-VMHostHBAWWN {
<#    .Description
    Get the Port- and Node WWN(s) for HBA(s) in host(s). Feb 2012, vNugglets
    .Example
    Get-VMHostHBAWWN -VMHost myhost0.dom.com
    VMHostName       DeviceName  HBAPortWWN               HBANodeWWN               HBAStatus
    ----------       ----------  ----------               ----------               ---------
    myhost0.dom.com  vmhba1      10:00:00:00:00:00:00:ca  20:00:00:00:00:00:00:ca  online
    myhost0.dom.com  vmhba2      10:00:00:00:00:00:00:83  20:00:00:00:00:00:00:83  online
    Get the HBA WWNs for hosts whose name match the pattern myhost0.dom.com
    .Example
    Get-VMHostHBAWWN -VMHost ^my.+
    VMHostName       DeviceName  HBAPortWWN               HBANodeWWN               HBAStatus
    ----------       ----------  ----------               ----------               ---------
    myhost0.dom.com  vmhba1      10:00:00:00:00:00:00:ca  20:00:00:00:00:00:00:ca  online
    myhost0.dom.com  vmhba2      10:00:00:00:00:00:00:83  20:00:00:00:00:00:00:83  online
    mytest1.dom.com  vmhba1      10:00:00:00:00:00:00:da  20:00:00:00:00:00:00:da  online
    mytest0.dom.com  vmhba2      10:00:00:00:00:00:00:93  20:00:00:00:00:00:00:93  online
    Get the HBA WWNs for hosts whose name match the pattern ^my.+
    .Example
    Get-Cluster mycluster | Get-VMHostHBAWWN
    ...
    Get the HBA WWNs for hosts in the cluster "mycluster"
    .Outputs
    PSCustomObject
#>
[CmdletBinding()]param(
    ## Name pattern of the host for which to get HBA info (accepts regex patterns)
    [parameter(Mandatory=$true,ParameterSetName="SearchByHostName")][string]$VMHostName_str,
    ## Name pattern of the cluster for whose hosts to get HBA info (accepts regex patterns)
    [parameter(Mandatory=$true,ParameterSetName="SearchByCluster",ValueFromPipelineByPropertyName)][Alias("Name")][string]$ClusterName_str
) ## end param
Begin {
    ## helper function for formatting WWN as hex string with colon-separators
    function _Format-AsHexWWNString {
        param([parameter(Mandatory=$true)][long]$WWN_long)
        (("{0:x}" -f $WWN_long) -split "(\w{2})" | ?{$_ -ne ""}) -join ":"
    } ## end function
}

Process {
    ## params for the Get-View expression for getting the View objects
    $hshGetViewParams = @{
        ViewType = "HostSystem"
        Property = "Name", "Config.StorageDevice.HostBusAdapter"
    } ## end hashtable
    Switch ($PSCmdlet.ParameterSetName) {
        ## if host name pattern was provided, filter on it in the Get-View expression
        "SearchByHostName" {$hshGetViewParams["Filter"] = @{"Name" = $VMHostName_str}; break;} ## end case
        ## if cluster name pattern was provided, set it as the search root for the Get-View expression
        "SearchByCluster" {$hshGetViewParams["SearchRoot"] = (Get-Cluster $ClusterName_str).Id; break;}
    } ## end switch

    Get-View @hshGetViewParams | Foreach-Object {
        $viewHost = $_
        $viewHost.Config.StorageDevice.HostBusAdapter | Where-Object {$_ -is [VMware.Vim.HostFibreChannelHba]} | Foreach-Object {
            New-Object -TypeName PSObject -Property ([ordered]@{
                VMHostName = $viewHost.Name
                DeviceName = $_.Device
                HBAPortWWN = _Format-AsHexWWNString -WWN $_.PortWorldWideName
                HBANodeWWN = _Format-AsHexWWNString -WWN $_.NodeWorldWideName
                HBAStatus = $_.Status
            }) ## end new-object
        } ## end foreach-object
    } ## end foreach-object
} ## end process
} ## end function

Not terribly fancy, but something to get it done more quickly (FaF, in fact).  And, handy for other things down the road.  Like, oh, using the WWN info when creating some initiator groups on your XtremIO array?  What a good idea.

Oh, and if you have not yet seen/used parameter splatting, this provides a decent example of that, too -- the hashtable of parameters used on line 54.  Enjoy!

24 April 2014

XtremIO PowerShell module -- Report on your all-flash arrays!

XtremIO + PowerShell!
All-flash arrays -- if you do not have any, get some.  If you have XtremIO, you are likely ecstatic with the performance, ease of setup, low maintenance, etc.  You are potentially also fairly sad about the Java-based management GUI for when you want to report, especially when you want to report in bulk (say, across ten XtremIO arrays), as it is a separate interface to launch for each array.

How to turn that frown upside-down?  Hello, RESTful API!  After a bit of exploring the API, I have created a module for reading info from the XMS (XtremIO Management Server) appliances (the appliances that are used to manage the XtremIO arrays).  While the APIs provide support for nearly all management activities (create/delete/modify/read config), this module is starting out with just the configuration/stats-reading types of actions.

The XtremIO RESTful API provides item types upon which to report, like volumes, lun-maps, clusters, and initiators.  Newer releases of the XMS appliances add item types of bricks, snapshots, ssds, storage-controllers, and xenvs.  At the end of this post, after the examples, is more info on the differences between the appliance versions and how those difference affect the way one uses this module.

As for the module itself, it is linked below, it is still being improved upon, and the intentions are to [eventually]:
  1. house it on GitHub or the likes
  2. add the rest of the supported item types
  3. add functionality beyond read-only reporting (think config/manage)
  4. finish error handling for some scenarios (invalid item types for given API version, for example)
To use the module, just
  1. download from https://github.com/mtboren/XtremIO.Utils/releases/download/Latest/XtremIO.Utils.zip https://github.com/mtboren/XtremIO.Utils/releases/download/Latest/XtremIO.Utils.zip
  2. unzip somewhere you like (like, say, in Join-Path ${env:\userprofile} "Documents\WindowsPowerShell\Modules")
  3. you should now have a folder named <pathToModules>\XtremIOInfo, in which the PowerShell files reside (see note below about using Unblock-File, since this module is not yet Authenticode signed)
  4. Import-Module <pathToModules>\XtremIOInfo

You can use Get-Command -Module XtremIOInfo and Get-Help to find out all about the functionality provided by the module and its currently one (1) exported function, including examples.  You will also find the ItemType values currently supported by the module (more to come).

And, some quick examples to whet appetites:
PS vN:\> Get-XIOItemInfo -Computer somexms01.dom.com, somexms02.dom.com, somexms03.dom.com -Credential $credMyAcct -ItemType clusters

Name    TotSSDTB   UsedSSDTB   FreeSSDTB   UsedLogicalTB   TotProvTB   DedupeRatio   IOPS
----    --------   ---------   ---------   -------------   ---------   -----------   ----
xio01   7.47       4.03        3.44        12.17           50          3.0           7886
xio02   7.47       1.13        6.34        3.17            50          2.8           2821
xio03   7.47       5.23        2.24        17.79           50          3.4           28363


PS vN:\> Get-XIOItemInfo -Computer somexms04.dom.com -Credential $credMyAcct -TrustAllCert -Port 443 | Format-List

Name               : xio04
TotSSDTB           : 7.47
UsedSSDTB          : 2.43
FreeSSDTB          : 5.04
FreespaceLevel     : healthy
UsedLogicalTB      : 8.02
TotProvTB          : 50
OverallEfficiency  : 21:1
DedupeRatio        : 3.3
ThinProvSavingsPct : 76
IOPS               : 18160
SWVersion          : 2.2.3-25
SystemSN           : APM00000000004
ComputerName       : somexms04.dom.com

Various notes:
While the module has the ability to connect to different versions of the XMS appliances (v2.2.2 listens on a different port for API requests than does v2.2.3+), not all items are available on the older versions.  For example, one can retrieve info on the item type ssds only from from the newer version of the appliances.

When connecting to an appliance of the newer version, one might save a bit of time by specifying the port on which to communicate -- port 443.  The function tries the default port of the old appliances first (42503), and, if that port is not found to be responsive, tries the default port of the new appliances.  Also, if you did not put "legitimate" SSL certificate on the appliance (as opposed to the self-signed cert that is on it by default), _and_ you are sure that the address to which you are connecting in the appliance, you can use the -TrustAllCert switch parameter.  This is to allow the PowerShell session to establish the SSL connection by not stopping at a "self-signed cert found" error.

One of the other "features" of this module:  we have not yet set the authenticode  signature for it.  That is, it is unsigned.  We went back and forth on the solution:
  • buy a legit cert for code signing (best solution, but $$$)
  • sign it with a self-signed cert (which still leads to a prompt of 'Do you want to run software from this untrusted publisher?' when you try in import the module, since everyone is security-minded and has at least the RemoteSigned execution policy set on their machines)
  • ✔ do not add a signature, and make mention that you will need to Unblock-File the files in the module (after careful inspection of the files to make sure that there is nothing dangerous in there; but, we're talking about vNugglets, here -- you can trust us, right?!  a:  No.  Trust no one)
So, since we went with the last option there, below is the quick/easy way to unblock files.  But, again, this should only be done when you trust the code in the files that you are unblocking -- inspecting the files is for your own good.  Anyway, the unblock command:
Get-ChildItem <pathToModules>\XtremIOInfo | Unblock-File

Alright, enough with the notes, for now.  XtremIO storage arrays: awesome.  Now, the ability to start interacting with management appliances via PowerShell: excellanté!

29 December 2013

Get VM Disks and RDMs via PowerCLI

Need to get info about a VM's hard disks?  Like, "regular" virtual disks and RDMs, in a handy and fast manner?  We need to, occasionally, and so wrote a function to do so (a while ago -- just finally posting it).  It gets things like the hard disk name, the SCSI ID, the storage device display name, the disk size, the SCSI canonical name, and [optionally] the full datastore path for the disk files.  Here again, not the first bit of code around to retrieve such things, but a version that is written to do things most quickly.

The script:
<# .Description
    Function to get a VM's hard disk and RDM info
    Originally from Sep 2011, updated Dec 2013 -- vNugglets.com
    .Example
    Get-VMDiskAndRDM -vmName someVM -ShowVMDKDatastorePath | ft -a
    VMName HardDiskName ScsiId DeviceDisplayName SizeGB ScsiCanonicalName                    VMDKDStorePath
    ------ ------------ ------ ----------------- ------ -----------------                    --------------
    someVM Hard disk 1  0:0                          50                                      [dstore0] someVM/someVM.vmdk
    someVM Hard disk 2  1:0    someVM-/log_dir       20 naa.60000945618415615641111111111111 [dstore0] someVM/someVM_1.vmdk
    Get the disks (including RDMs) for "someVM", and include the datastore path for each VMDK
#>
function Get-VMDiskAndRDM {
    param(
        ## name pattern of the VM guest for which to get info
        [parameter(Mandatory=$true)][string]$vmName_str = "myVM",
        ## switch to specify that VMDK's datastore path should also be returned
        [switch]$ShowVMDKDatastorePath_sw
    )

    ## the cool, FaF way (using .NET View objects)
    ## get the VM object(s)
    $arrVMViewsForStorageInfo = Get-View -Viewtype VirtualMachine -Property Name, Config.Hardware.Device, Runtime.Host -Filter @{"Name" = "$vmName_str"}
    if (($arrVMViewsForStorageInfo | Measure-Object).Count -eq 0) {Write-Warning "No VirtualMachine objects found matching name pattern '$vmName_str'"; exit} ## end if

    $arrVMViewsForStorageInfo | %{
        $viewVMForStorageInfo = $_
        ## get the view of the host on which the VM currently resides
        $viewHostWithStorage = Get-View -Id $viewVMForStorageInfo.Runtime.Host -Property Config.StorageDevice.ScsiLun

        $viewVMForStorageInfo.Config.Hardware.Device | ?{$_ -is [VMware.Vim.VirtualDisk]} | %{
            $hdThisDisk = $_
            $oScsiLun = $viewHostWithStorage.Config.StorageDevice.ScsiLun | ?{$_.UUID -eq $hdThisDisk.Backing.LunUuid}
            ## the properties to return in new object
            $hshThisVMProperties = @{
                VMName = $viewVMForStorageInfo.Name
                ## the disk's "name", like "Hard disk 1"
                HardDiskName = $hdThisDisk.DeviceInfo.Label
                ## get device's SCSI controller and Unit numbers (1:0, 1:3, etc)
                ScsiId = &{$strControllerKey = $_.ControllerKey.ToString(); "{0}`:{1}" -f $strControllerKey[$strControllerKey.Length - 1], $_.Unitnumber}
                DeviceDisplayName = $oScsiLun.DisplayName
                SizeGB = [Math]::Round($_.CapacityInKB / 1MB, 0)
                ScsiCanonicalName = $oScsiLun.CanonicalName
            } ## end hsh
            ## the array of items to select for output
            $arrPropertiesToSelect = "VMName,HardDiskName,ScsiId,DeviceDisplayName,SizeGB,ScsiCanonicalName".Split(",")
            ## add property for VMDKDStorePath if desired
            if ($ShowVMDKDatastorePath_sw -eq $true) {$hshThisVMProperties["VMDKDStorePath"] = $hdThisDisk.Backing.Filename; $arrPropertiesToSelect += "VMDKDStorePath"}
            New-Object -Type PSObject -Property $hshThisVMProperties | Select $arrPropertiesToSelect
        } ## end foreach-object
    } ## end foreach-object
} ## end function

Some example usage:
PS vN:\> Get-VMDiskAndRDM -vmName myVM01 -ShowVMDKDatastorePath | ft -a

VMName HardDiskName ScsiId DeviceDisplayName SizeGB ScsiCanonicalName                    VMDKDStorePath
------ ------------ ------ ----------------- ------ -----------------                    --------------
myVM01 Hard disk 1  0:0                          50                                      [dstore0] myVM01/myVM01.vmdk
myVM01 Hard disk 2  1:0    myVM01-/data001      660 naa.60000946665554443331111111111111 [dstore0] myVM01/myVM01_1.vmdk


The disks with no values for the DeviceDisplayName or ScsiCanonicalName properties are the "regular" virtual disks, and the others are RDMs.  And, this VM has hard disks on two separate SCSI controllers.

Note:  the vmName parameter is used as a regular expression when getting the .NET View object of the given VM.  As such, one can use a pattern, and can get info on multiple VMs that share the same name pattern.

And, that is that:  some juicy disk/RDM info for VMs, and on the quick!  Thanks, Get-View, for keeping things FaF!  Enjoy

BTW:  related post, Get VM by RDM with PowerCLI:  how to get the VM that is using a particular SAN storage device as an RDM.

24 December 2013

Get VM By RDM with PowerCLI

Sometimes one needs to find a VM by RDM.  This is not a new thought, and there are plenty of spots on the internet that give ways to achieve this.  When this need arose for us a couple of years ago, we found no spot that gave a way to achieve this quickly.  So, with vNugglets' focus on speed, I put together a function to do just that:  quickly find the VM that is using a given SAN device as an RDM.

Then, just recently, a VMware Communities forum post made me realize that we had not yet shared this function with the world.  So, here we go:
<#    .Description
    Function to find what VM (if any) is using a LUN as an RDM, based on the LUN's SCSI canonical name. Assumes that the best practice of all hosts in a cluster seeing the same LUNs is followed.
    vNugglets, originally from Nov 2011
    .Example
    Get-VMWithGivenRDM -CanonicalName naa.60000970000192602222333031314444 -Cluster myCluster0 | ft -a
    Find a VM using the given LUN as an RDM, formatting output in auto-sized table.  Output would be something like:
    VMName            VMDiskName     DeviceDisplayName   CanonicalName
    ------            ----------     -----------------   -------------
    myvm033.dom.com   Hard disk 10   myvm033-data3FS     naa.60000970000192602222333031314444
    .Outputs
    Zero or more PSObjects with info about the VM and its RDM
#>
function Get-VMWithGivenRDM {
    param(
        ## Canonical name of the LUN in question
        [parameter(Mandatory=$true)][string[]]$CanonicalNameOfRDMToFind_arr,
        ## Cluster whose hosts see this LUN
        [parameter(Mandatory=$true)][string]$ClusterName_str
    ) ## end param

    ## get the View object of the cluster in question
    $viewCluster = Get-View -ViewType ClusterComputeResource -Property Name -Filter @{"Name" = "^$([RegEx]::escape($ClusterName_str))$"}
    ## get the View of a host in the given cluster (presumably all hosts in the cluster see the same storage)
    $viewHostInGivenCluster = Get-View -ViewType HostSystem -Property Name -SearchRoot $viewCluster.MoRef | Get-Random
    ## get the Config.StorageDevice.ScsiLun property of the host (retrieved _after_ getting the View object for speed, as this property is only retrieved for this object, not all hosts' View objects)
    $viewHostInGivenCluster.UpdateViewData("Config.StorageDevice.ScsiLun")

    ## if matching device(s) found, store some info for later use
    $arrMatchingDisk = &{
    ## get the View objects for all VMs in the given cluster
    Get-View -ViewType VirtualMachine -Property Name, Config.Hardware.Device -SearchRoot $viewCluster.MoRef | %{$viewThisVM = $_
        ## for all of the RDM devices on this VM, see if the canonical name matches the canonical name in question
        $viewThisVM.Config.Hardware.Device | ?{($_ -is [VMware.Vim.VirtualDisk]) -and ("physicalMode","virtualMode" -contains $_.Backing.CompatibilityMode)} | %{
            $hdThisDisk = $_
            $lunScsiLunOfThisDisk = $viewHostInGivenCluster.Config.StorageDevice.ScsiLun | ?{$_.UUID -eq $hdThisDisk.Backing.LunUuid}
            ## if the canonical names match, create a new PSObject with some info about the VirtualDisk and the VM using it
            if ($CanonicalNameOfRDMToFind_arr -contains $lunScsiLunOfThisDisk.CanonicalName) {
                New-Object -TypeName PSObject -Property @{
                    VMName = $viewThisVM.Name
                    VMDiskName = $hdThisDisk.DeviceInfo.Label
                    CanonicalName = $lunScsiLunOfThisDisk.CanonicalName
                    DeviceDisplayName = $lunScsiLunOfThisDisk.DisplayName
                } ## end new-object
            } ## end if
        } ## end foreach-object
    } ## end foreach-object
    } ## end scriptblock

    ## if a matching device was found, output its info
    if ($arrMatchingDisk) {$arrMatchingDisk | Select VMName, VMDiskName, DeviceDisplayName, CanonicalName}
    ## else, say so
    else {Write-Verbose -Verbose "Booo. No matching disk device with canonical name in '$CanonicalNameOfRDMToFind_arr' found attached to a VM as an RDM in cluster '$ClusterName_str'"}
} ## end fn
Some example usage:
PS vN:\> Get-VMWithGivenRDM -CanonicalName naa.60000123412342602222333031314444 -Cluster myMegaCluster

VMName            VMDiskName     DeviceDisplayName   CanonicalName
------            ----------     -----------------   -------------
myvm002.dom.com   Hard disk 13   myvm002-dataFS_7    naa.60000123412342602222333031314444
...

The point of having a Cluster param is to focus the scope of the search (one generally knows to what set of hosts a particular LUN has been presented).

And, some thoughts on how to make this function even better:
  • take cluster input from pipeline
  • add ability to check entire vCenter inventory, but keep things fast by first narrowing scope to only the VMHosts that see given device, then check those hosts' clusters for a VM with RDM using said device (removes need for "Cluster" param)
  • maybe:  add other info to output object, if there are other things that would be useful/valuable
So, how does this do -- FaF for you, too?  Yeah, just as we thought!

21 November 2013

Get VMs by Virtual Port Group with PowerCLI

How to find out what VMs use a particular virtual port group, and quickly?  Well, we have just the thing.  And, it also helps to illustrate the practical use of LinkedViews and the UpdateViewData() method of .NET View objects (about which we posted a while back in Even Faster PowerCLI Code with Get-View, UpdateViewData() and LinkedViews), along with the kind of speed increase that said method brings.

So, the function:
<#  .Description
    Function to get info about what VMs are on a virtual portgroup.  vNugglets, Oct 2013
    Highlights the use of the UpdateViewData() method of a .NET View object
    .Outputs
    PSObject
#>
function Get-VMOnNetworkPortGroup {
    param(
        ## name of network to get; regex pattern
        [parameter(Mandatory=$true)][string]$NetworkName_str
    ) ## end param

    ## get the .NET View objects for the network port groups whose label match the given name
    $arrNetworkViews = Get-View -ViewType Network -Property Name -Filter @{"Name" = $NetworkName_str}
    if (($arrNetworkViews | Measure-Object).Count -eq 0) {Write-Warning "No networks found matching name '$NetworkName_str'"; exit}

    ## get the networks' VMs' names, along with the name of the corresponding VMHost and cluster
    $arrNetworkViews | %{$_.UpdateViewData("Vm.Name","Vm.Runtime.Host.Name","Vm.Runtime.Host.Parent.Name")}
    ## create a new object for each VM on this network
    $arrNetworkViews | %{
        $viewNetwk = $_
        $viewNetwk.LinkedView.Vm | %{
            New-Object -TypeName PSObject -Property @{
                VMName = $_.Name
                NetworkName = $viewNetwk.Name
                VMHost = $_.Runtime.LinkedView.Host.Name
                Cluster = $_.Runtime.LinkedView.Host.LinkedView.Parent.Name
            } | Select-Object VMName,NetworkName,VMHost,Cluster
        } ## end foreach-object
    } ## end foreach-object
} ## end fn
And, some sample usage:
PS vN:\> Get-VMOnNetworkPortGroup -NetworkName "223|237"

VMName        NetworkName   VMHost           Cluster
------        -----------   ------           -------
dubuntu0      223.Prod      esxi01.dom.com   Cluster0
vma5          223.Prod      esxi02.dom.com   Cluster0
vcsa02        223.Prod      esxi02.dom.com   Cluster0
tmpl_test1    237.Dev       esxi12.dom.com   Cluster1
...
This illustrates the use of a regular expression pattern to match virtual networks whose names contain "223" or "237".

And, on the topic of speed increases:
## using standard cmdlets:
PS vN:\> Measure-Command {Get-VirtualPortGroup -Name SomeNetworkName | Get-VM | select name,@{n="VMHostName"; e={$_.VMHost.name}},@{n="ClusterName"; e={$_.VMHost.Parent.Name}}}
...
TotalSeconds      : 25.4870345


## using vNugglets function:
PS vN:\> Measure-Command {Get-VMOnNetworkPortGroup -NetworkName SomeNetworkName}
...
TotalSeconds      : 0.9676149      ## big winner!

So, while similar results can be had with native PowerCLI cmdlets, leveraging this function definitely comes in handy, especially when you are as impatient as we can be here at vNugglets.  Enjoy!