Home > dvSwitch, PowerCLI, PowerShell, vSphere > dvSwitch scripting – Part 8 – Get and Set network adapters

dvSwitch scripting – Part 8 – Get and Set network adapters

One of the feature requests that came up in several emails I received for my dvSwitch series, was how to get and set the network adapters of virtual guests. In the current PowerCLI version the Get-NetworkAdapter and Set-NetworkAdapter cmdlets can not handle portgroups on dvSwitches.

That is why I created the following two functions, called Get-dvSwNetworkAdapter and Set-dvSwNetworkAdapter.

The script

In the functions I tried to emulate the existing Get-NetworkAdapter and Set-NetworkAdapter cmdlets.

Update March 21st 2010

Mike Laverick reported some problems with the original functions when an array of objects was passed as an argument. I have rewritten both functions to handle parameter arrays correctly.

Update June 3rd 2010

Glenn Sizemore, winner of the 2010 Scripting Games, reworked the functions so that they now work with a standard vSwitch and a dvSwitch! See dvSwitchNetworkAdapter for Glenn’s code.


function Get-dvSwNetworkAdapter{
	param([parameter(Mandatory = $true, ValueFromPipeline = $true)][VMware.VimAutomation.Client20.VirtualMachineImpl[]]$VM
	)

	process{
		$VM | Get-View | %{
			$vmObj = $_
			$vmObj.Config.Hardware.Device | where {"VirtualEthernetCard","VirtualVmxnet" -contains $_.GetType().BaseType.Name} | %{
				$net = $_
				New-Object PSObject -Property @{
					MacAddress = $net.MacAddress
					WakeOnLanEnabled = $net.WakeOnLanEnabled
					NetworkName = &{
						if($net.Backing.GetType().Name -eq "VirtualEthernetCardNetworkBackingInfo"){
							(Get-View $_.Backing.network).Name
						}
						else{
							($vmObj.Network | %{Get-View $_} | where{$_.Key -eq $net.Backing.Port.PortgroupKey}).Name
						}
					}
					Type = $net.GetType().Name
					ParentId = $vmObj.MoRef.Type + "-" + $vmObj.MoRef.Value
					ConnectionState = New-Object PSObject -Property @{
						Connected = $net.Connectable.Connected
						StartConnected = $net.Connectable.StartConnected
					}
					Id = $vmObj.MoRef.Type + "-" + $vmObj.MoRef.Value + "/" + $net.Key
					Name = $net.DeviceInfo.Label
				}
			}
		}
	}
}

function Set-dvSwNetworkAdapter{
	param([parameter(Mandatory = $true, ValueFromPipeline = $true)][PSCustomObject[]]$NetworkAdapter,
	[parameter(Mandatory = $true)][string]$NetworkName,
	[switch]$StartConnected,
	[switch]$Connected
	)

	process{
		$NetworkAdapter | %{
			$netAdapter = $_
			$vm = Get-View $netAdapter.ParentId
			$esx = Get-View $vm.Runtime.Host
			$newNet = $esx.Network | %{Get-View $_} | where {$_.Name -eq $NetworkName}
			$spec = New-Object VMware.Vim.VirtualMachineConfigSpec

			$dev = New-Object VMware.Vim.VirtualDeviceConfigSpec
			$dev.operation = "edit"
			$dev.device = $vm.Config.Hardware.Device | where {$_.GetType().Name -eq $netAdapter.Type -and $_.MacAddress -eq $netAdapter.MacAddress}

			# Determine backing type
			switch($newNet.GetType().Name){
				"Network" {
					$dev.device.backing = New-Object VMware.Vim.VirtualEthernetCardNetworkBackingInfo
					$dev.device.backing.deviceName = $NetworkName
				}
				"DistributedVirtualPortgroup" {
					$dev.device.Backing = New-Object VMware.Vim.VirtualEthernetCardDistributedVirtualPortBackingInfo
					$dev.device.backing.port = New-Object VMware.Vim.DistributedVirtualSwitchPortConnection

					$dev.device.backing.port.switchUuid = (Get-View $newNet.Config.DistributedVirtualSwitch).Uuid
					$dev.device.backing.port.portgroupKey = $newNet.Config.Key
				}
			}
			if($Connected -ne $null){
				$dev.Device.Connectable.Connected = $Connected
			}
			if($StartConnected -ne $null){
				$dev.Device.Connectable.StartConnected = $StartConnected
			}
			$spec.deviceChange += $dev
			$taskMoRef = $vm.ReconfigVM_Task($spec)

			$task = Get-View $taskMoRef
			while("running","queued" -contains $task.Info.State){
				$task.UpdateViewData("Info")
			}
			$returnNetworkAdapter = $netAdapter
			$returnNetworkAdapter.NetworkName = $NetworkName
			$returnNetworkAdapter.ConnectionState.StartConnected = $dev.Device.Connectable.StartConnected
			$returnNetworkAdapter.ConnectionState.Connected = $dev.Device.Connectable.Connected
			$returnNetworkAdapter
		}
	}
}

Annotations

Line 2: The Get-dvSwNetworkAdapter function requires a single parameter, the virtual machine for which you want to get the network adapter information.

Line 5: With the Process block the function can act as a filter. In other words, the function can be used in a pipeline construct.

Line 6: This loop takes care if the VM parameter is an array.

Line 8: The Where-Object filter only allows virtual devices that have the basetype VirtualEthernetCard or VirtualVmxnet to enter the script block that follows. By using the basetype the script doesn’t have to test all the derived objects.

Line 10: The returned information will be in a PSObject. The PSObject has the same properties that are present in the NetworkAdapterImpl that is returned by the Get-NetworkAdapter cmdlet.

Line 13-19: The network name has to be retrieved from different properties depending on the fact if the card is connected to vSwitch portgroup or to a dvSwitch portgroup.

Line 23-26: The ConnectionState property, which is a ConnectInfo object with the Get-NetworkAdapter cmdlet, contains a PSObject. But the property names and the values are the same.

Line 27: The Id property is constructed from the Id of the virtual machine and the device key of the network card. This is the same as what the Get-NetworkAdapter cmdlet returns.

Line 36-37: The Set-dvSwNetworkAdapter function has two required parameters. A network adapter object, as is returned by the Get-dvSwNetworkAdapter cmdlet, and the name of the portgroup to which the adapter shall be connected. Notice that the NetworkAdapter parameter can be passed via the pipeline.

Line 38-39: The function has two optional switch parameters, StartConnected and Connected.

Line 41: With the Process block the function can act as a filter. In other words, the function can be used in a pipeline construct.

Line 43: This loop takes care if the NetworkAdapter parameter is an array.

Line 47: This construct looks up the new portgroup to which the network adapter will be connected.

Line 48-67: These lines prepare the parameters for the ReconfigVM_Task method that is used to change the portgroup to which the network card is connected.

Line 52: The script copies the VirtualDevice object into the VirtualMachineConfigSpec object. This action minimises the data that will have to be entered into the properties. On March 26th 2010 I have added the condition that the MAC address should correspond as well. Otherwise there could eventually be multiple NICs that fit the condition. Rich, thanks for the discovery and the correction.

Line 55: Depending if the new portgroup is on a vSwitch or on a dvSwitch, the Backing property of the VirtualDevice is of a different type.

Line 68-73: These lines take care of the StartConnected and Connected switches.

Line 78-80: This is the “standard” loop to wait for the completion of a Task method.

Line 85: The function returns the new network adapter information through a PSObject. Similar to what the Get-dvSwNetworkAdapter function does.

Usage

Some sample use cases of the two functions.

Getting adapter information

Similar to the Get-NetworkAdapter cmdlet you can retrieve information from the network adapter(s).

$vmName = "MyGuest"

Get-dvSwNetworkAdapter -VM (Get-VM $vmName)

Returns something like this

Changing the adapters

To change the portgroup of a network adapter you can use something like this

$vmName = "MyGuest"

Get-dvSwNetworkAdapter -VM (Get-VM $vmName) | where {$_.NetworkName -eq "Net2"} | Set-dvSwNetworkAdapter -NetworkName "dvPgNet2"

And the changed network adapter will be returned.

The functions can handle calls of the following formats

Get-VM -Name "MyVm1" | get-dvSwNetworkAdapter | Set-dvSwNetworkAdapter -NetworkName "dvPgNet2"
Get-VM -Name "MyVm*" | get-dvSwNetworkAdapter | Set-dvSwNetworkAdapter -NetworkName "dvPgNet2"
Get-dvSwNetworkAdapter -VM (Get-VM MyVm1) | Set-dvSwNetworkAdapter -NetworkName "dvPgNet2"
Get-dvSwNetworkAdapter -VM (Get-VM MyVm*) | Set-dvSwNetworkAdapter -NetworkName "dvPgNet2"
Get-dvSwNetworkAdapter (Get-VM MyVm) | Set-dvSwNetworkAdapter -NetworkName "dvPgNet2"
Get-dvSwNetworkAdapter (Get-VM MyVm*) | Set-dvSwNetworkAdapter -NetworkName "dvPgNet2"
Get-dvSwNetworkAdapter (Get-VM MyVm*) | Set-dvSwNetworkAdapter -NetworkName "dvPgNet2" -StartConnected:$true
Get-dvSwNetworkAdapter -VM (Get-VM MyVm1) | Set-dvSwNetworkAdapter -NetworkName "dvPgNet2" -Connected:$true -StartConnected:$true

Conclusion

I hope these two functions come in handy in your work with dvSwitches.

And a word of warning, the two functions don’t perform any error checking whatsoever. If you pass no network adapter object to the Set-dvSwNetworkAdapter function, it will fail ! Same if you pass the name of a non-existing portgroup name.

  1. Batuhan
    November 22nd, 2012 at 08:26 | #1

    Hi, I know this is an old thread but this script has been great use to me. It works great, assigns the dvSwitch to the VM fine, but the script enters an infinite loop of errors after the configuration is done. The VM works fine, the network adapter is changed fine. The error is:

    Exception calling “UpdateViewData” with “1″ argument(s): “”
    At line:83 char:25
    + $task.UpdateViewData <<<< ("Info")
    + CategoryInfo : NotSpecified: (:) [], MethodInvocationException
    + FullyQualifiedErrorId : DotNetMethodException

    I am using this with PowerCLI 5 latest release. Maybe something deprecated as this is an old script. I tried to use the "Set-NetworkAdapter" command but it does not work with dvSwitch networks. Any help appreciated, thanks.

  2. March 9th, 2011 at 13:02 | #2

    Hi,

    Did anything change with the introduction of powercli 4.1.1? do we still need these functions to get/set network information?
    we have not upgraded to 4.1.1 yet so I was wondering about that.

    Thanks
    Ionut

    • March 9th, 2011 at 13:38 | #3

      @Ionut, no not really, in PowerCLI 4.1 and 4.1.1 some existing cmdlets were extended with dvSwitch functionality. See the PowerCLI changelog. and search for ‘distributed’.

  3. Drunky
    February 24th, 2011 at 13:46 | #4

    @LucD
    Great :)

    at now i have to pars each vmx file of every vm (with help of awk/sed/grep ) on esx side, removing such lines as

    ethernet0.dvs.switchId = “1d a1 2c 50 6d 7a ea 59-d0 cd b9 8a d2 a3 2d 37″
    ethernet0.dvs.portId = “133″
    ethernet0.dvs.portgroupId = “dvportgroup-367″
    ethernet0.dvs.connectionId = “1842595141″

    adding one line

    ethernet0.networkName = “temp”

    register those vm’s with your function “register-vm” and only after that changing portgroup from “temp” to what i need “dvportgroup”

    and all of it is a part of “SRM on scripts” ^_^

  4. Drunky
    February 24th, 2011 at 11:55 | #5

    @Drunky
    Never mind, i found the problem
    Unfortunately if you removing VM from inventory and than add it back (no matter form GUI or by your great function register-vm), it (VM) comes back with no (blank) portgroup, when using distributed switch

    • February 24th, 2011 at 12:47 | #6

      @Drunky, thanks for the feedback.
      I’ll check if I can do something with the Register-VMX function for this.

  5. Drunky
    February 24th, 2011 at 11:04 | #7

    Hi Luc. Trying to use your function, but getting strange error

    Get-VMHost | Get-Datastore -name “CX3_virtual_lab_lun2″ | get-vm | Get-dvSwNetworkAdapter

    Get-View : Не удается проверить аргумент для параметра “VIObject”. Аргумент пустой или име
    ет значение NULL. Укажите не пустой аргумент, не имеющий значение NULL, после чего повтори
    те выполнение команды.
    C:\Scirpts5.ps1:158 знак:17
    + $VM | Get-View <<<< | %{
    + CategoryInfo : InvalidData: (:) [Get-View], ParameterBindingValidationExce
    ption
    + FullyQualifiedErrorId : ParameterArgumentValidationError,VMware.VimAutomation.ViCor
    e.Cmdlets.Commands.DotNetInterop.GetVIView

  6. Jorgen
    September 22nd, 2010 at 02:05 | #8

    Luc, look at this site http://blogs.vmware.com/vipowershell/2010/07/output-type-changes-in-powercli-41.html

    >> In PowerCLI 4.1 we changed the namespaces in which output types live. This was done to improve the internal structure and enable other VMware teams to write cmdlets for the products they develop.

    This explains the error Alex had.

    • September 22nd, 2010 at 08:09 | #9

      @Jorgen, that is correct and that is what I said in my previous reply.
      The problem is that there is no method that I know to have it both ways.
      The script is for PowerCLI 4.1 or for PowerCLU 4.0u1 and earlier.
      In the long run I suspect I will have to update all the scripts for PowerCLI 4.1.

  7. August 15th, 2010 at 16:50 | #10

    @LuCD, thanks so much for all your scripts…amazingly helpful for quite a while now!

    Started receiving an error with get-dvsnetworkadapter to the likes of:

    Unable to find type [VMware.VimAutomation.Client20.VirtualMachineImpl[]]: make sure that the assembly containing this type is loaded.
    At :line:2 char:116
    + param([parameter(Mandatory = $true, ValueFromPipeline = $true)][VMware.VimAutomation.Client20.VirtualMachineImpl[]] <<< VMware.VimAutomation.ViCore.Impl.V1.VirtualDevice.VirtualDeviceImpl

    on the following page:
    http://blogs.vmware.com/files/typemapping—powercli-4.0.1-to-4.1-1.txt

    After making that change the script works again. Appears VMware updated some object typing in 4.1.

    Thanks and good scripting!

    • August 15th, 2010 at 19:07 | #11

      @VM-PRO, glad you like the script.
      You are correct. The types have changed in PowerCLI 4.1.
      For now, I was planning to leave the scripts in the PowerCLI 4.0.1 format.
      I was hoping VMW would come with a more global solution then just a translation table.

  8. Roey Azroel
    July 24th, 2010 at 19:09 | #12

    Hi LucD!

    There is a way to import/export DVS configuration? (Include the PortGroup names, configuration and the UUID of the DVS)

    Thanks!

    • July 25th, 2010 at 21:41 | #13

      Hi Roey, as a matter of fact I’m looking into such functionality.
      But I couldn’t find a simple way of doing that (yet).

  9. Z
    June 9th, 2010 at 18:47 | #14

    I keep getting this error when running the script:

    Get-Process : Cannot evaluate parameter ‘Name’ because its argument is specified as a script block and there is no input. A script block cannot be evaluated without input.

    I’m calling the function with your supplied example:
    $vmName = “TestSrv”
    Get-dvSwNetworkAdapter -VM (Get-VM $vmName)

    Any idea why I’m getting this?
    Thanks!

    • June 9th, 2010 at 23:38 | #15

      Hi Z, I tried several variations in several environments but I couldn’t reproduce the problem.
      Could you perhaps tell me how you run the script ? From the PowerCLI prompt, PowerShell Plus, PowerShell v2 ISE, EcoShell, PowerGUI… ?
      And which PowerShell and PowerCLI version you are using ?

  10. Rich
    March 26th, 2010 at 19:46 | #16

    Hi – Your scripts have always been a serious help. With the Set-dvSwNetworkAdapter script and a VM with multiple NICs I was getting this error on line 52:

    Exception setting “Device”: “Cannot convert the “System.Object[]” value of type “System.Object[]” to type “VM
    ware.Vim.VirtualDevice”.”

    because both NICs were getting returned.

    I fixed it by modifying the line to:
    $dev.device = $vm.Config.Hardware.Device | where {$_.GetType().Name -eq $netAdapter.Type -and $_.MacAddress -eq $netAdapter.MacAddress}

    Just wanted to let you know/see if there was something I was doing wrong.

    Thanks

    • March 26th, 2010 at 20:03 | #17

      Rich, thanks for finding this bug and providing a correction.
      The post has been updated.

  11. Alex
    March 24th, 2010 at 00:02 | #18

    @LucD
    Luc – That was it. Works great now. Thank you.

  12. Alex
    March 23rd, 2010 at 20:01 | #19

    Hi – Thanks for providing this script. I’m getting the following error when I attempt to load the above functions. I also tried to include these functions in my $profile, but still get the same error. I’m able to run other powercli cmdlets successfully. Any suggestions?

    Thanks.

    [vSphere PowerCLI] C:\Powershell scripts> & ‘C:\Powershell scripts\dvSw.ps1′
    Unable to find type [parameter(Mandatory = $true, ValueFromPipeline = $true)]:
    make sure that the assembly containing this type is loaded.
    At C:\Powershell scripts\dvSw.ps1:2 char:65
    + param([parameter(Mandatory = $true, ValueFromPipeline = $true)][ <<<< VMw
    are.VimAutomation.Client20.VirtualMachineImpl[]]$VM

  1. No trackbacks yet.