25 July 2011

Setting MAC Address for VM NICs using PowerShell

A bit ago, there were some questions in the VMware VMTN community forums about setting explicit MAC addresses for VMs' NICs.

While this can be done via PowerCLI using the Set-NetworkAdapter cmdlet, the MAC address range is restricted to 00:50:56:00:00:00 - 00:50:56:3F:FF:FF when using the cmdlet, which is only a subset of the range that VMware uses.

An example came up where one might need to set the MAC address to something in a valid VMware range (with VMware OUIs like "00:50:56" or "00:0C:29") outside of the subset above. This can be done using the Web Services API, as it does not have the same range limitation as the cmdlet. The well-commented code below shows how to do so using the API:

## script function:  set the MAC address of a VM's NIC
## Author: vNugglets.com

## the name of the VM whose NIC's MAC address to change
$strTargetVMName = "myVM01"
## the MAC address to use
$strNewMACAddr = "00:50:56:90:00:01"

## get the .NET view object of the VM
$viewTargetVM = Get-View -ViewType VirtualMachine -Property Name,Config.Hardware.Device -Filter @{"Name" = "^${strTargetVMName}$"}
## get the NIC device (further operations assume that this VM has only one NIC)
$deviceNIC = $viewTargetVM.Config.Hardware.Device | Where-Object {$_ -is [VMware.Vim.VirtualEthernetCard]}
## set the MAC address to the specified value
$deviceNIC.MacAddress = $strNewMACAddr
## set the MAC address type to manual
$deviceNIC.addressType = "Manual"

## create the new VMConfigSpec
$specNewVMConfig = New-Object VMware.Vim.VirtualMachineConfigSpec -Property @{
   ## setup the deviceChange object
   deviceChange = New-Object VMware.Vim.VirtualDeviceConfigSpec -Property @{
       ## the kind of operation, from the given enumeration
       operation = "edit"
       ## the device to change, with the desired settings
       device = $deviceNIC
   } ## end New-Object
} ## end New-Object

## reconfigure the "clone" VM
$viewTargetVM.ReconfigVM($specNewVMConfig)


The ReconfigVM() method does not care if the new MAC address is a valid VMware MAC address. It does not even seem to care if the new MAC address string is a valid hex MAC address. So, use with care -- one would not want to break networking on their precious VM by setting its NIC to have an invalid MAC address, or a duplicate, etc.

Other info: the valid VMware OUIs can be found many places, like at the IEEE.org Public Listing search site.


Update 25 Nov 2011:
Do note that changing the MAC address of a VM NIC to something outside of the "accepted" range will cause other PowerCLI cmdlets and the vSphere client to report that the NIC's MAC is "not in the valid range", and may prevent further operations on that VM's NIC with those tools.  Thank-you to the anonymous commenter here and to LucD (in the VMware Communities thread at http://communities.vmware.com/message/1869800#1869800) for highlighting this point.


Update 31 Dec 2011:
The -Filter parameter for the Get-View call on line 10 was using a regular expression that had the possibility of returning more than one VM View object.  I have updated the regular expression to only match VMs of exactly the given name.  Thanks go to Joep Piscaer for pointing out the issue.  The code in this post has been updated.

12 comments:

  1. Thanks for the script. I've got the following message when i look in the NIC properties of the VM after i changed the MAC address:
    The MAC address entered is not in the valid range.....

    ReplyDelete
  2. Thanks for bringing that up, "Anonymous". I have updated the post with a note about this point.

    ReplyDelete
  3. ## get the .NET view object of the VM
    10
    $viewTargetVM = Get-View -ViewType VirtualMachine -Property Name,Config.Hardware.Device -Filter @{"Name" = $strTargetVMName}

    This line returns multiple objects of the VMName occurs more than once, i.e. if you have two VM's containing the name 'database'...

    ReplyDelete
  4. Thanks, Joep Piscaer (virtuallifestyle.nl), for pointing out the problem of multiple View objects being returned. I have now updated the code to use a regular expression for the -Filter such that it will match on the entire string only (by using the "^" and "$" anchor characters). Enjoy!

    ReplyDelete
  5. Adding " | ? {$_.MacAddress -eq "$strNewMACAddr"}" to line 12 will make the scripts compatible with VMs with multiple NICs.

    ReplyDelete
  6. Thanks, again, Joep Piscaer (virtuallifestyle.nl), for that suggestion. While the exact Where-Object clause that you suggested will not solve the "VM with multiple NICs" situation (since it will return zero NICs, since none of the VM's NICs should have the _new_ MAC address already), the general idea of adding a Where filter would definitely be a way to go.

    Example: use a Where-Object filter that matches on the VirtualNetworkCard device's display name or _current_ MAC address.

    Thanks for the tip for everyone.

    ReplyDelete
  7. Never used this trick to change MAC Address but it sounds very interesting.Would like to use it for sure.

    Thanks
    Silvester Norman

    Changing MAC Address

    ReplyDelete
  8. What is needed to be changed/added in order to use this script to change the MAC address for the "Network Adapter 1" on a VM which has more then one NIC?

    Thanks

    ReplyDelete
    Replies
    1. Ignore my question, I didn't spot that is has already been mentioned above - Adding " | ? {$_.MacAddress -eq "$strNewMACAddr"}" to line 12 will make the scripts compatible with VMs with multiple NICs.

      Delete
    2. Being new to Powershell I got confused as to how to modify this script in order to use it on multiple NICs. Any chance of showing how this script can be modified to enable this?

      Thanks

      Delete
  9. Just used this for a CentOS migration where mass guest access wasn't viable and the interface configs were tied to the MAC. Much appreciated.

    ReplyDelete
  10. I found the solution in order to use it on multiple NICs.

    Here is the modification of the script :

    $fromVMname is the VM that I just have cloned
    $newVMname is the cloned VM

    $NewMACAddr = Get-NetworkAdapter $fromVMname
    # get the .NET view object of the VM
    $viewTargetVM =
    Get-View -ViewType VirtualMachine -Property Name,Config.Hardware.Device -Filter @{"Name" = "^${newVMname}$"}
    $deviceNIC = $viewTargetVM.Config.Hardware.Device | Where-Object {$_ -is [VMware.Vim.VirtualEthernetCard]}
    $cardnumber = $NewMACAddr.MacAddress.Count
    for ($i=1; $i -le $cardnumber; $i++) {
    $j=$i-1
    # get the NIC device (further operations assume that this VM has only one NIC)
    $deviceNIC[$j].MacAddress = $NewMACAddr[$j].MacAddress
    #set the MAC address type to manual
    $deviceNIC[$j].addressType = "Manual"
    # create the new VMConfigSpec
    $specNewVMConfig = New-Object VMware.Vim.VirtualMachineConfigSpec -Property @{
    # setup the deviceChange object
    deviceChange = New-Object VMware.Vim.VirtualDeviceConfigSpec -Property @{
    # the kind of operation, from the given enumeration
    operation = "edit"
    # the device to change, with the desired settings
    device = $deviceNIC[$j]
    } # end New-Object
    } # end New-Object
    # Reconfiguration de la VM clone pour prendre en compte les nouveaux param├Ętres
    $viewTargetVM.ReconfigVM($specNewVMConfig)
    }

    I try it successfuly on a VM which have 1 NIC, 2 NICs and 3 NICs.

    ReplyDelete