Variations on a port

I got an interesting question from one of my co-authors of the PowerCLI Reference book. He was looking for a method to find the port used by a VM when connected to a portgroup on a dvSwitch.

Finding the answer to that question is not too difficult, once you know which property holds the value. But while writing and testing the script, I thought that this question would be a good opportunity to show several ways and methods that you have at your disposal in PowerCLI and PowerShell, to come to a solution.

Here it goes.

The basic solution

With a bit of (logical) thinking and the help of the Get-Member cmdlet, it didn’t take long to discover where the dvSwitch port information is hiding.

As a matter of fact the port information is kept with the VirtualMachine itself, under the virtual devices, in the NIC backing object, which is called VirtualEthernetCardDistributedVirtualPortBackingInfo.

A quick-and-dirty script to get the ports could look like this.

Annotations

Line 2: The script loops through all NIC that are defined on a VM

The result will appear on screen and will look something like this.

Notice that for NICs that are connected to standard portgroups, the Port property is left empty.

To get the results into a CSV file, you will have to store the results temporarily in a variable, and then, after the ForEach loop, you can pipe this variable to the Export-Csv cmdlet.

A faster solution

When you visited the PowerCLI Community recently, you might have noticed that there is a poll going on about ‘regular’ and ‘fast’ solutions. A ‘regular’ solution would be one that uses the PowerCLI cmdlets to retrieve PowerCLI objects and a ‘fast’ solution is one that uses the Get-View cmdlet to retrieve (read-only copies of) vSphere objects.

In bigger environments the difference in execution time between regular and fast solutions might be substantial.

So how would we tackle the problem at hand with a ‘fast’ solution ?

Annotations

Line 1: To select the NIC devices, out of all other devices connected to the VM, the script will check if the Type of the Device is present in this array. This array contains the typenames of all possible NIC types.

Line 3: The script retrieves all the VMs. In the Property parameter the script tells the engine to only fetch those specific properties. This will cause a time saving in the execution time.

Line 4-8: The NIC device object does not have a property with the actual name of the portgroup to which it is connected. There is a property that has a ‘key’ for the portgroups. To avoid having to scan the connected portgroups each time to find the name, the script sets up a hash table.

Line 10: This line will loop through all devices connected to the VM and will only pass the NIC devices to the Select-Object in the following line.

Line 14: The key that points to the portgroup (see above) is stored in a different property, depending if the portgroup is a regular or a distributed portgroup.

Line 15: The portgroupname is retrieved from the hash table.

This ‘fast’ version of the script looks, and is, more complex than the basic function we showed before. The reason for that is that the script will have to do everything, like finding the portgroupname, by itself. In the basic function, which uses PowerCLI objects, a lot of that work is done by the logic behind the PowerCLI cmdlet.

It makes you appreciate the work the PowerCLI Dev Team put in the development of the PowerCLI cmdlets, even more.

The output of this script looks of course exactly the same (besides the order in which the VM object are returned).

A function

If we want to report on these port numbers regularly, it is better to write a function around the logic we have from the scripts above. A function will allow us to call the functionality, just like we would call any other cmdlet.

Let’s create the function in such a way that we can retrieve the port information in 2 ways.

  • Retrieve the port information for one or more VMs (similar to the functions above)
  • Retrieve the port information for all VMs connected to specific Portgroups

By using parameter sets it is quite easy to package both methods in 1 function. Something like this

Annotations

Line 27-30: The function uses 2 parametersets, one to pass VMs and one to pass Portgroups. The default is VMs.

Line 29: Note that the script doesn’t accept Portgroups from the pipeline. Implementing such a feature is possible, but would require testing the type of the parameter value. I used the ‘keep it simple’ rule 😉

Line 34-35: The script needs to test if the device is a NIC. This array should contain all the possible NIC types a VM can have.

Line 36,59,86: For the PortGroup parameter the script needs to test if the VM under investigation is connected to the requested portgroup. By default we take all the portgroups. If the PortGroup parameter is used, the script will only report on NICs connected to that portgroup.

Line 40-62: The Switch statement which handles the 2 parametersets.

Line 43-50: For the VM parameter the script can handle 1 or more VM names, or 1 or more VirtualMachineImpl objects.

Line 49: When no value is passed with the VM parameter, the script will take all VMs known in the connected vCenter. Since the script uses the Get-View cmdlet with the Filter parameter, the regular expression ‘.+’ is used to find all VMs.

Line 51,60: For both parametersets, the script passes a variable $VMs to the code after the Switch statement. The $VMs variable is populated with the VMs for which the portgroup port needs to be reported upon.

Line 57: The mask for the Get-View Filter parameter is generated. It’s of the form “vm1|vm2|vm3”

Line 65-69: The script uses a hash table to allow the portgroup name to be retrieved  with the portgroup key.

Line 71-86: For each NIC an object holding the information is generated.

Line 78,81: Note that the portgroup key is located in different properties, depending if the portgroup is on a regular vSwitch or a distributed vSwitch.

There are several ways you can call the function. Some examples

No parameter is passed, so the VM parameterset will be chosen. The function will report on all the available VMs. This will produce the following output.

Note that we had to use a Select-Object cmdlet to define the order of the displayed properties. In PowerShell v2 one doesn’t have any way to specify the order of the properties defined ona New-Object cmdlet. In PowerShell v3 this will change !

Another example, with a selected set of VM that are passed through the pipeline.

This will give

And finally an example with the PortGroup parameterset.

This call will produce a report on all the VMs that have a NIC connected to any of the distributed portgroups.

A new property

If we want to display this port information with each NIC connected to a VM, when we do a Get-NetworkAdapter, we can wrap the above logic in a New-VIProperty.

The New-VIProperty cmdlet allows us to extend the default set of properties that come with a PowerCLI object.

In this case the code is quite simple

When we do

We will get the following.

I hope this showed a bit the numerous possibilities you have with PowerCLI and PowerShell to tackle your vSphere administrative tasks.

Enjoy !

5 Comments

    Miguel

    Hello
    This script is fantastic for our large vmware view environment, however,
    when using vCenter linked mode configuration on the environment, the script breaks in at least two places:
    Index operation failed; the array index evaluated to null.
    At C:\PowerShellScripts\5-02\get-dvvmport.ps1:83 char:20
    + $pgs[ <<<< $key]
    + CategoryInfo : InvalidOperation: (:) [], RuntimeException
    + FullyQualifiedErrorId : NullArrayIndex

    Exception calling "Add" with "2" argument(s): "Item has already been added. Key
    in dictionary: 'dvportgroup-85' Key being added: 'dvportgroup-85'"
    At C:\PowerShellScripts\5-02\get-dvvmport.ps1:68 char:19
    + $pgs.Add <<<< ($key,$_.Name)
    + CategoryInfo : NotSpecified: (:) [], MethodInvocationException
    + FullyQualifiedErrorId : DotNetMethodException

      LucD

      Thanks Miguel.
      I have to admit the script doesn’t consider linked vCenters.
      The script will need to be updated for that.

      How do expect the function to behave with linked vCenters ?
      Report on the VMs over all the linked vCenters ?

        Miguel

        Hello
        yes, exactly, all the vms in all the linked vCenters would be a good behaviour.
        It would similar to the behaviour of get-vm, for example.

    Conrad

    Impressive as always. Although I am disappointed you are missing a half beat in the final measure of the tune in the key of G 🙂

    As a side note, I am impressed with your ability to get anything done with the amount you are on the Powercli forums. Stop being so productive you make the rest of us look bad 🙂

      LucD

      @Conrad, thanks.
      Sorry to have disappointed you with the sheet music screenshot.
      To make up for that, the complete variations 😉

Leave a Reply

Your email address will not be published. Required fields are marked *

*
*

This site uses Akismet to reduce spam. Learn how your comment data is processed.