Hyper-V and PowerShell: Get Hyper-V VM MAC Address

While not common, there are times when you might need to know the MAC address for a virtual machine. This is a quick script to help you quickly retrieve that information.

This article is part of the “Hyper-V and PowerShell” series.

This script is meant to be as much a matter of teaching as functionality, and may be even more useful in that regard. I literally took the script from the earlier Get-VMIPAddresses script and made the necessary changes to produce this script. That’s a common way to get a head start on making tools that you need when none already exist: start from one that’s close to what you want.

Parameters

Name: The name of the virtual machine whose MAC address you wish to retrieve. Cannot be used with VM.

ComputerName: The name of the host that contains the virtual machine whose MAC address you wish to receive. Cannot be used with VM.

VM: The VM object whose MAC address you wish to receive. Cannot be used with Name or ComputerName.

Separator: “None”, “Colon”, “Hyphen”, or “Custom”. The first three use that item to separate the elements of the MAC address. With “Custom”, you also use the “CustomSeparator” parameter to specify the character that you want to use as a separator.

CustomSeparator: You use this parameter to specify the character that you want to use the MAC address elements with.

Separator Modification

The default separator type is “None”. Change line 74 to “Colon” or “Hyphen” if you’d rather have either of those. Of course, you could further modify the script to use anything you want.

The Script

Copy the contents of the following script block into a text editor and save it as a .PS1 file. It’s written to expect Get-VMMACAddress.ps1 as the name, but you can use anything you like:

<#
.SYNOPSIS
	Lists the MAC address for a virtual machine's network adapter(s).
.DESCRIPTION
	Lists the MAC address for a virtual machine's network adapter(s).
.PARAMETER Name
	The name of the virtual machine whose IP addresses you wish to retrieve. Cannot be used with VM.
.PARAMETER ComputerName
	The name of the host that contains the virtual machine whose MAC address you wish to receive. Cannot be used with VM.
.PARAMETER VM
	The VM object whose MAC address you wish to receive. Cannot be used with Name or ComputerName.
.PARAMETER Separator
	"None" retrieves the MAC address without any separator characters.
	"Colon" retrieves the MAC address with colon separators.
	"Hyphen" retrieves the MAC address with hyphen separators.
	"Custom" allows you to use the -CustomSeparator field to designate your own separator character.
.PARAMETER CustomSeparator
	Any character you wish to use as a separator for MAC address elements.
.OUTPUTS
	A string containing the MAC address.
.NOTES
	Author: Eric Siron
	Copyright: (C) 2014 Altaro Software
	Version 1.0
	Authored Date: November 23, 2014
.LINK
	
Hyper-V and PowerShell: Get Hyper-V VM MAC Address
.EXAMPLE C:PS> .Get-VMMACAddress -Name svtest Description ----------- Retrieves the MAC address for the VM named svtest. .EXAMPLE C:PS> .Get-VMMACAddress -Name svtest -ComputerName svhv2 Description ----------- Retrieves the MAC address for the VM named svtest on host svhv2. .EXAMPLE C:PS> .Get-VMMACAddress -Name svtest -Separator Colon Description ----------- Retrieves svtest's MAC address with colon separators. .EXAMPLE C:PS> .Get-VMMACAddress -Name svtest -Separator Custom -CustomSeparator * Description ----------- Retrieves svtest's MAC address with asterisks as separators. .EXAMPLE C:PS> Get-VM | .Get-VMMACAddress Description ----------- Retrieves the MAC addresses of all virtual machines on the local system. #> #requires -Version 3 #requires -Modules Hyper-V [CmdletBinding()] param ( [Alias("VMName")] [Parameter(ValueFromPipeline=$true, ValueFromPipelineByPropertyName=$true, ParameterSetName='ByName', Mandatory=$true, Position=1)] [String]$Name, [Alias("VMHost")] [Parameter(ValueFromPipelineByPropertyName=$true, Position=2, ParameterSetName='ByName')] [String]$ComputerName = $env:COMPUTERNAME, [Parameter(ValueFromPipeline=$true, ValueFromPipelineByPropertyName=$true, ParameterSetName='ByVM')] [Microsoft.HyperV.PowerShell.VirtualMachine]$VM, [Parameter(ValueFromPipelineByPropertyName=$true)] [ValidateSet("None", "Colon", "Hyphen", "Custom")] [String]$Separator, [Parameter(ValueFromPipelineByPropertyName=$true)] [Char]$CustomSeparator ) BEGIN { New-Variable -Name DefaultSeparator -Value "None" -Option Constant # Change to Colon or Hyphen if desired } PROCESS { if($VM) { $ParameterSet = @{ 'VM'=$VM } } else { $ParameterSet = @{ 'VMName'="$Name"; 'ComputerName'="$ComputerName" } } $MACAddress = (Get-VMNetworkAdapter @ParameterSet).MacAddress if($Separator -ne "None") { $MACAddress = $MACAddress -replace "(w{2})(w{2})(w{2})(w{2})(w{2})(w{2})", '$1(SEP)$2(SEP)$3(SEP)$4(SEP)$5(SEP)$6' if($CustomSeparator) { $SeparatorChar = $CustomSeparator } else { switch($Separator) { "Colon" { $SeparatorChar = ":" } "Hyphen" { $SeparatorChar = "-" } } } $MACAddress = $MACAddress -replace "(SEP)", $SeparatorChar } $MacAddress } END {}

New Tricks in this Script

The changes in this script are fairly minor. There is only one type of MAC address, so the references to “Type” are gone. However, the default formatting of running all the characters of the MAC address together may not be desirable. Getting a MAC address isn’t overly difficult, but having a script during the formatting is definitely convenient. There are a lot of really complicated ways to format strings, but I’m not much for complicated. So, I chose to use a couple of regular expressions.

If you’ve never heard of regular expressions, it’s a technology used to perform complex operations on strings. They can be extremely powerful, and, unfortunately, can be very intimidating. However, without regular expressions, the actions taken by a couple of lines in this script would require a great mass of shifting characters around. Let’s look at the first one:

$MACAddress = $MACAddress -replace "(w{2})(w{2})(w{2})(w{2})(w{2})(w{2})", '$1(SEP)$2(SEP)$3(SEP)$4(SEP)$5(SEP)$6'

PowerShell’s -replace operator calls one of its regular expression functions. It looks in the item to its left, in this case the $MACAddress variable, for a match in the first object to its right, in this case the repeating (w{2}) items. It then replaces those matches in the first item ($MACAddress) with those in the third.

In this case, we know that we’re going to get a 12-character long string. What we want to do is break it apart into 6 groups of two characters and insert our own characters inbetween. So, in the match string, we use six groups of parenthesis. These establish groups. The groups are delineated as 2 non-whitespace characters (the w is “non-whitespace” and {2} means “two of the previous item”). The second part is where we start our replacement character insert. This is ordinarily a simple process, but we have more than one possibility for separators, which makes it complicated.

The purpose of using groups in the match string is because we need to recall those items for the replacement string. Those groups can be recalled in the replacement by using $0, $1, $2, etc $0 represents the entire match, which in this case would be the original $MACAddress variable as presented. $1 represents the first group, $2 is the second, etc. The issue here is that these are for the regular expression engine, not the PowerShell engine. So, if you use something like “$1”, PowerShell is going to look in its variable list for $1, and when it doesn’t find anything, it will just “replace” with an empty string. So, we have to use the single-quote character around the replacement string so that PowerShell doesn’t use its own variable substitution and instead leaves the $1 and all the others for the regular expression engine. While that will allow the replacement to work, it will also prevent us from using our $SeparatorCharacter variable.

To solve that problem, I inserted a character string of (SEP). This doesn’t have any particular significance, but it’s not something that would be found in a proper MAC address and is too complex to conflict with anything submitted in the -CustomSeparator parameter. At this point, a sample MAC address would look like this: “00(SEP)15(SEP)5D(SEP)19(SEP)0A(SEP)00”. Now we have something we can perform a very simple replacement on:

$MACAddress = $MACAddress -replace "(SEP)", $SeparatorChar

Of course, this isn’t the only way to do this, even with regular expressions. You could pre-create the replacement string before performing any regular expression, and then you’d need only one.

Regular expressions are an extremely powerful tool that are worth the time to at least learn the basics of. I’m OK with regular expressions, but my first inclination is always to perform an Internet search to see if anyone has already designed an expression to solve the problem I’m facing. If you want to learn more, a great reference is www.regular-expressions.info. If you prefer a print reference, Jeffrey Friedl’s “Mastering Regular Expressions” is still the best work on the subject.

 

Threat Monitor
Share this post

Not a DOJO Member yet?

Join thousands of other IT pros and receive a weekly roundup email with the latest content & updates!

Leave a comment or ask a question

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

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

Notify me of follow-up replies via email

Yes, I would like to receive new blog posts by email

What is the color of grass?

Please note: If you’re not already a member on the Dojo Forums you will create a new account and receive an activation email.

Banner ad for eBook Azure IaaS Second Edition