Monday, July 30, 2012

Server 2012 Windows Network Virtualization part 6 Lookup Routes

I am finally at the last part that makes this all work.

If you have defined everything so far you have VM traffic routing between VMs on the same Virtual Switch (and it is isolated like a tiny VLAN) but nothing more.  No traffic will travel from VM to VM across hosts until we define the Lookup Route that tells that packet where to go.

here is the command in a nutshell:

New-NetVirtualizationLookupRecord -VirtualSubnetID 5001 -CustomerAddress -MACAddress 00155D002001 -ProviderAddress -Rule TranslationMethodNat -CustomerID "{2ad17590-33b5-45fc-ad3a-90e5ff9b017f}" -VMName VMPXE

The VirtualSubnetID, the CA (the IP of the VM), the MAC of the VM, the PA that the CA is associated with, the type of network virtualization to use, the Routing Domain (Customer ID) and the name of the VM (really for management benefits – it does not have to match anything).

The –Rules are TranslationMethodNat (for IP Rewrite) or TranslationMethodEncap for (NVGRE encapsulation).  This is that decision I mentioned before.

If your traffic is all IP based and can handle segmentation then by all means use encapsulation (also, your physical devises must support it, most do, but as long as they don’t somehow do something with the virtual subnet ID you should be good).

Otherwise fall back to Nat (IP Rewrite).  But, remember that if you use this you need one PA for each CA, so you need to add PA addresses each time you add a VM.  And don’t worry, you can define multiples on the physical NIC of the virtual switch.

Here I have a script to set up encapsulation on a static network (where I don’t have to worry about VM change).

Here are my assumptions:

  1. The PA is defined and I am using one for all VMs
  2. The VMs are running and reporting an IP address to Hyper-V
  3. I write an output file to run on the ‘other’ Hyper-V Servers to propagate the Lookup Routes.
  4. If the IP is I ignore it.

There is a lot going on here and the screen does not format it well, be warned.

$paAddress = Get-NetVirtualizationProviderAddress

$otherHostsFile = $env:Public + "\Documents\" + "RunOnHostsOtherThan_" + $env:COMPUTERNAME + ".ps1"
Out-File -Force $otherHostsFile  # this is the propagation file

$vms = Get-VM -Name *

foreach ($i in $vms) {

    if ($i.NetworkAdapters.IPAddresses -ne $null) {
        $vmIpv4 = $i.NetworkAdapters.IPAddresses | where { $_.contains(".") }
        $vmIpv6 = $i.NetworkAdapters.IPAddresses | where { $_.contains(":") }
    $vmNic = Get-VMNetworkAdapter -VM $i

    "    " + $vmNic.Name + " -> " + $vmNic.SwitchName

    if ($vmIpv4 -ne $NULL) {
        New-NetVirtualizationLookupRecord -VirtualSubnetID $vSubnetId -CustomerAddress $vmIpv4 -MACAddress $vmNic.MACAddress -ProviderAddress $paAddress.ProviderAddress -Rule TranslationMethodEncap -CustomerID $routingDomainId -VMName $vmNic.VMName
        Set-VMNetworkAdapter -VirtualSubnetId $vSubnetId -VMNetworkAdapter $vmNic
        ("New-NetVirtualizationLookupRecord -VirtualSubnetID " + $vSubnetId + " -CustomerAddress " + $vmIpv4 + " -MACAddress " + $vmNic.MACAddress + " -ProviderAddress " + $paAddress.ProviderAddress+ " -Rule TranslationMethodEncap -CustomerID `"" + $routingDomainId + "`" -VMName " + $vmNic.VMName) | Out-File -NoClobber -Append -FilePath $otherHostsFile

    <#    If ($vmIpv6 -ne $NULL) {
        New-NetVirtualizationLookupRecord -VirtualSubnetID $vSubnetId -CustomerAddress $vmIpv6 -MACAddress $vmNic.MACAddress -ProviderAddress $paAddress.ProviderAddress -Rule TranslationMethodEncap -CustomerID $routingDomainId -VMName $vmNic.VMName
        Set-VMNetworkAdapter -VirtualSubnetId $vSubnetId -VMNetworkAdapter $vmNic
        ("New-NetVirtualizationLookupRecord -VirtualSubnetID " + $vSubnetId + " -CustomerAddress " + $vmIpv6+ " -MACAddress " + $vmNic.MACAddress + " -ProviderAddress " + $paAddress.ProviderAddress+ " -Rule TranslationMethodEncap -CustomerID `"" + $routingDomainId + "`" -VMName " + $vmNic.VMName) | Out-File -NoClobber -Append -FilePath $otherHostsFile

    Clear-Variable -name vmIpv4 -ErrorAction SilentlyContinue
    Clear-Variable -Name vmIpv6 -ErrorAction SilentlyContinue


I have another script to set up NAT and that takes a bit more due to the PA management.  A post of its own.

Tuesday, July 24, 2012

Server 2012 Windows Network Virtualization part 5 the Customer Address

I am not going to spend much if any time on this.

Do you recall this graphic:



All that you need to know is that the Customer Address must be a known thing.  You need to know the IP address of your VM, the MAC or your VM, and how you are going to forward your VM traffic (encapsulation or IP Rewrite) prior to the next step.

Remember, if you use IP Rewrite – each CA needs a unique PA.  If you use encapsulation you can have one PA support multiple CAs.

IP Rewrite gives high compatibility but is more to manage, Encapsulation is easier to manage but might not work in all cases (actually, I know cases where it fails).

The CA is the IP of the VM.  There can only be one LookupRoute defined per CA + VirtualSubnetID.  Remember, VirtualSubnetID is your isolation boundary, within the CustomerRoute, but cannot be used more than once within a datacenter.

This can also be thought of as the IP that defines the target route – as a remote CA is actually the target of any packet.

And, most important – in the WNV model, this is the IP that the customer brings with them.  There can be duplicates, but not for a single customer – as that would duplicate too many settings and create conflicting routing rules.

Friday, July 20, 2012

Server 2012 Windows Network Virtualization part 4 the PA address

In the previous post I set the basics.  I enabled WNV and left you hanging.

Lets begin with getting the concepts straight about the PA (ProviderAddress) and the CA (CustomerAddress).  If you think about the paradigm, these names reflect the owner of the respective subnet / address space.

The PA is an address that is owned by the Provider.  Also referred to as the Hoster or the Enterprise.  These addresses allow packets to be routed between Hyper-V Virtual Switches.

The CA is an address that is brought by the Customer.  Also referred to as a Tenant, or a cloud user.  These addresses are the addresses that the VMs have.  And need to be known when establishing the routing rules.

Lets just focus on the PA for the remainder of this post.

An important thing to understand (that I really did not get at first) is that the ProviderAddress (the PA) is unique and different from the Management IP of the Hyper-V Server.

I draw it this way:


Also, the ProviderAddress just needs to be routable to any other hosts where VMs reside that participate in a particular virtual network.

For example:

Your management subnet might be 10.10.3.x.  If you don’t need any more than 254 PA addresses then you can use 192.168.3.x (for example).

In this model 192.168 is not routable, so all the Hyper-V Extensible Switches need to be local to each other. 

I am going to talk Switches here, since that is what this is all about, not the Hyper-V Server – that is a different IP and different issue.

ProviderAddresses are all about switch to switch communication using a routable IP address.  So all the networking or routing rules that you already know apply.  Your choice of PA addresses combined with routing rules can restrict your virtual network to a datacenter, or allow it to span datacenters, or even to remote services.  It is all in how you define and build it.

Lets add that you can define multiple PAs.  And the PAs can be private, public, different subnets, etc.  The IP of the PA simply interacts with the routing rules at the physical / fabric layer of your network.

Now, lets mention the two primary types of virtual networks.  MSFT has used the terms NVGRE (or Encapsulated) and IPRewrite (or NAT) in various places.  The reason that I mention this is that it affects your PA options.

IPRewrite sets up a NAT rule.  This requires one PA per CA.  So, each VM has an IP address (the CA) and a corresponding PA.  The rules for IPRewrite is essentially a one to one NAT (no port redirection here like in a router this is IP translation).

NVGRE uses encapsulation.  This is the most flexible in how you define it.  As you can use one PA for multiple CAs.  And again, you can have multiple PAs.  Here are some possibilities.

The simplest model of one PA per virtual switch:


This is compatible with:  NVRGE (all virtual networks using NVGRE)


Another possibility is one PA per virtual network.  This would give a bit more flexibility in managing different tenants sharing Hyper-V Servers. Again, this would only support using NVGRE (encapsulation).



If you want to use IPRewrite you need one PA for each VM.


After all this, you want to define a ProviderAddress?

It is really simple.  In this example I am assuming one thing, you have only one External Virtual Switch.

$wnvIf = Get-NetAdapterBinding -ComponentID "ms_netwnv" | Where-Object { $_.Enabled -eq $true } | Get-netadapter

New-NetVirtualizationProviderAddress -InterfaceIndex $wnvIf.InterfaceIndex -ProviderAddress -PrefixLength 24

Next, we will tackle the CA space.

Wednesday, July 18, 2012

Server 2012 Windows Network Virtualization part 3 the Virtual Subnet Id

First of all, I want to say that I am only describing these concepts in a way that I think I can build from one concept to the next.

The order that you define these various things in does not matter.  However, the data does not flow until it is all in place.

In an attempt to better relate the concept of where these various settings reside I have drawn the following diagram:



In this article lets talk about the Virtual Subnet Id in a bit of detail. This is a relatively simple setting.

This is a setting of the port of the Virtual Switch.  However, it is presented to you as a property of the Virtual Network Interface of a VM. 

It is defined in this way as it makes sense to want these settings to remain with the VM, not the virtual switch port.  So it just helps the brain to keep things straight when the UI calls this a vNIC or virtual NIC.

Now, down to business.

If you list the properties of a VM NetworkAdapter you will see the VirtualSubnetId. 

PS C:\Users\administrator.BRIANEH> Get-VMNetworkAdapter -VMName VM2 | fl

Name                     : VM2
Id                       : Microsoft:D9B02F4B-47B1-4A88-A20B-E763CC97209A\71803
IsLegacy                 : True
IsManagementOs           : False
ComputerName             : BJELKS5
VMName                   : VM2
VMId                     : d9b02f4b-47b1-4a88-a20b-e763cc97209a
SwitchName               : Virtual Network0
SwitchId                 : a6891eb9-bb01-45e5-bf20-e8a450fb0135
Connected                : True
PoolName                 :
MacAddress               : 001DD8B71C01
DynamicMacAddressEnabled : False
MacAddressSpoofing       : Off
AllowTeaming             : Off
RouterGuard              : Off
DhcpGuard                : Off
PortMirroringMode        : None
IeeePriorityTag          : Off
VirtualSubnetId          : 11657562
VMQWeight                : 0
VMQUsage                 : 0
IOVWeight                : 0
IOVUsage                 : 0
IovQueuePairsRequested   : 1
IovQueuePairsAssigned    : 0
IOVInterruptModeration   : Default
IPsecOffloadMaxSA        : 0
IPsecOffloadSAUsage      : 0
VFDataPathActive         : False
MaximumBandwidth         :
MinimumBandwidthAbsolute :
MinimumBandwidthWeight   :
BandwidthPercentage      : 0%
MandatoryFeatureId       : {}
MandatoryFeatureName     : {}
Status                   : {Ok}
IPAddresses              : {, fe80::78aa:947f:8718:d231}

However, if you look in the Hyper-V Manager GUI you will never see this property.  This is only available only through PowerShell or WMI as it is considered a far advanced setting.

If you did no more than set the VirtualSubnetId of of a bunch of VMs to the same VirtualSubnetId you would have the equivalent of a VLAN tag that is local to the Virtual Switch.  The virtual switch would route the VirtualSubnetIds internally and sort them out, very much like a VLAN tag.

This concept alone can be handy.

But, for the traffic to leave the local virtual switch you need the other settings in place and defined for the Network Virtualization module.

So, how do you set this?  Well, the Set-VMNetworkAdapter cmdlet supports multiple options.

If you have the VMNetworkAdapter object you can do this: 

Set-VMNetworkAdapter -VirtualSubnetId $vSubnetId -VMNetworkAdapter $vmNic

If you want to set all the VMNetworkAdapters on your Hyper-V Server to the same VirtualSubnetId you can do this: 

Get-VMNetworkAdapter * | Set-VMNetworkAdapter –VirtualSubnetId $vSubnetId

The Key is that the VirtualSubnetId is higher than the VLAN tag top limit of 4095, it goes from 4096 to 16,777,215. A VMNetworkAdapter can only have one VirtualSubnetId at any time.  Setting this to 0 is the same as not having it set (just like VLAN tags).

One more thing is that the VirtualSubnetID must only be used once in the datacenter.  In other words Customer A and B in the Big Hosted Datacenter could not both use the VirtualSubnetID of 5001 even though they have unique Routing Domains.

The very last item to know about the VirtualSubnetID is that in the NVGRE internet draft it is mentioned that this can be utilized by the physical switching devices to more efficiently route traffic.  This opens a huge potential.  And if the fabric can self learn routes (the fabric does the forwarding, not the virtual switch), maybe some of the upcoming details to maintain routes could be avoided.  Huge potential.

Friday, July 13, 2012

Server 2012 Windows Network Virtualization part 2 the Customer Route

So, at this point Network Virtualization is turned on.  Yea!  Now we can use it.  But we have to define and know a few things.

One thing we need is a Customer Route also referred to as a Routing Domain (an easier term to use I think, but I will stay consistent with the API terms).

A Customer Route can be described in a couple different ways.  And how I describe this affects how I describe other features later on.  But the easiest way to describe a Routing Domain / Customer Route is that it is a single Virtual Network.

A Customer Route is a routing container, or a routing domain.  It can contain multiple virtual subnets.  In the Windows Network Virtualization implementation a Customer Route should represent a single Customer or Tenant.  And this customer can then define multiple VLANs within this route.

For example:

Say that you want to translate your current network into a Virtual Network.  You have a flat topology using various subnets divided by VLANs.

IP addresses with no VLAN tags are client desktops and services they consume.  VLAN 10 is Server management interfaces.  VLAN 20 is application server to database server traffic.  And so on.

If I was a Hosting provider using Server 2012.  I would create one CustomerRoute for you.  Within this Route I would establish at least two virtual subnets.  One for application server to database traffic, one to isolate the management interfaces.  Here is the hard part, how to handle the client to application server traffic.  If the application server is exposed on a public IP then I wouldn’t add a virtual subnet.  If the application servers are in your datacenter and I am hosting the database servers then I establish Network Virtualization rules so that your ProviderAddress(es) can reach mine (more on this later).

I could go on an on and as I move through the articles I hope the picture of possibilities and dependencies becomes clear.

Regardless what I do within a CustomerRoute, it is yours.  It is a single routing container that is isolated from all others.  Within this there needs to be at least one VirtualSubnetId and there can be many (more on that next).

Lets define one.

The Customer Route is defined using a GUID.  This GUID is referred to as the RoutingDomainId.  You have to derive one.  Oh, you also need to know what the CA addresses of the VMs will be (the IP subnet that will be used within a particular virtual subnet).

So, lets establish our constants:

$customerName = "Atomic Widgets"
$routingDomainId = "{2ad17590-33b5-45fc-ad3a-90e5ff9b017f}" #Note the brackets in the string, that is important.
$vSubnetId = "5001"
$caDestinationPrefix = "”

$caNexthopGw = ""

What I have done here is that I state that VirtualSubnetId 5001 contains VMs with IP addresses within the 192.168.104.x class C subnet.

I then need to define this CustomerRoute on each Hyper-V Server where there will be VMs participating in this CustomerRoute / Virtual Network.

New-NetVirtualizationCustomerRoute -RoutingDomainID $routingDomainId -VirtualSubnetID $vSubnetId -DestinationPrefix $caDestinationPrefix -NextHop $caNexthopGw -Metric 255

If I did no more than add this Customer Route, and then created VMs on this Hyper-V Server with the VirtualSubnetId of 5001 I will have the equivalent of my own (local) isolated VLAN.  The traffic is 100% local to my Hyper-V Server even though this is an External Virtual Switch.  It takes the establishment of some additional settings and routing rules for the VM traffic to exit the virtual switch and know where to go.

Actually, I don’t even need to set the Customer Route to have my own private VLAN 5001 within one Virtual Switch.  I really only need to set the virtual subnet id on the virtual NIC of the VMs.

Okay, enough of that, lets go back to my Virtual Network that is my CustomerRoute / RoutingDomain…

What if my Virtual Network has multiple VirtualSubnetIds (multiple little internal VLANs)?

Well, you simply add additional CustomerRoute definitions.  One for each virtual subnet id.

What does this look like if there are multiple virtual subnets?

PS C:\Users\administrator.BRIANEH> Get-NetVirtualizationCustomerRoute

RoutingDomainID   : {99B3D49E-9281-4C8E-81A0-8DC2257FB7EE}
VirtualSubnetID   : 7636197
DestinationPrefix :
NextHop           :
Metric            : 9

RoutingDomainID   : {99B3D49E-9281-4C8E-81A0-8DC2257FB7EE}
VirtualSubnetID   : 9889980
DestinationPrefix :
NextHop           :
Metric            : 9

RoutingDomainID   : {99B3D49E-9281-4C8E-81A0-8DC2257FB7EE}
VirtualSubnetID   : 4139103
DestinationPrefix :
NextHop           :
Metric            : 9

RoutingDomainID   : {99B3D49E-9281-4C8E-81A0-8DC2257FB7EE}
VirtualSubnetID   : 11657562
DestinationPrefix :
NextHop           :
Metric            : 9

The same RoutingDomainID is used, but each subnet is defined with its destination prefix(s).  There will be more on that later.

*Just a note, I am working on a good graphical way to describe this all.

Wednesday, July 11, 2012

Server 2012 Windows Network Virtualization part 1 of many

I have spent quite an extensive amount of time working with the Network Virtualization that is in Server 2012.
Most folks that are interested in this have caught the article on Jeff Snover's blog. And have possibly seen a few TechEd presentations that keep working the same graphics.  And, if you explore a bit you can find some interesting articles from folks in the networking community like over at about how NVGRE is a ‘right thing’.  And a primer on NVGRE over at
Oh, and lets not forget the Network Virtualization Survival Guide by the MSFT folks.
That all sets the basis for the technology.  Now the interesting bits.  The implementation.
First of all, lets get a big question out of the way:  Is SCVMM required to manage Windows Network Virtualization?  No, it isn’t.  However, you want some management layer to manage the complexities of keeping all of the routes and what not up to date.   If you look at Jeff Snover’s graphics, there is this whole set of PA and CA addresses that need to be kept straight.  And then there is the LookupRecords.
Really, this is not too bad in a static environment.  If the VMS never move or change, you set all these rules once and never touch them again.  However, if you move a VM (and Server 2012 makes that super easy) then you need to update the proper records or that VM is off the network.  SCVMM 2012 has a similar challenge of keeping LookupRecords and PAs updated if a VM is moved by Failover Clustering due to an HA event that it did not do.
In other words, this is not for the faint of heart.  There is actually a lot to this.  If you move beyond an environment where your VMs are static then you need to maintain these rules.  This is what management layers (like SCVMM, CloudStack) do for you, manage the complex stuff.
Okay, thanks for the warning, now what?
Step one:
Enable Windows Network Virtualization (WNV).  This is a binding that is applied to the NIC that you External Virtual Switch is bound to.  This can be a physical NIC, it can be an LBFO NIC team.  Either way, it is the network adapter that your External Virtual Switch uses to exit the server.
This also means that if you have multiple virtual networks or multiple interfaces that you can pick and choose and it is not some global setting.
If you have one External Virtual Switch this is fairly easy:
$vSwitch = Get-VMSwitch -SwitchType External
# Check if Network Virtualization is bound
# This could be done by checking for the binding and seeing if it is enabled
ForEach-Object -InputObject $vSwitch {
if ((Get-NetAdapterBinding -ComponentID "ms_netwnv" -InterfaceDescription $_.NetAdapterInterfaceDescription).Enabled -eq $false){
  # Lets enable it
  Enable-NetAdapterBinding -InterfaceDescription $_.NetAdapterInterfaceDescription -ComponentID "ms_netwnv"
I have a ForEach in the example above.  In case $vSwitch is an array, I assume I want to enable it on all virtual switches.  We will deal with the other details later.
Before me move on, I need to know some constants.  Such as my Tenant (Customer).  And some topology.  We will get there as we work through defining everything.
More to come.  Lots to learn about PA, CA, lookup routes, virtual subnet ids, and customer routes.  Lots of concepts, options, and rules to keep straight.

Monday, July 9, 2012

Enabling PING echo in Server 2012 with PowerShell

Once again, lets use the new PowerShell cmdlets that ship in the box with Server 2012.

The Server 2008 way of enabling PING to echo involved netsh.

netsh advfirewall firewall add rule name=”Allow Ping” protocol=icmpv4 dir=in action=allow 

Mind you, netsh is still in Server 2012 and this command works, but it is the old way of doing things, lets look forward.

Actually, lets run that netsh command on Server 2012 and see what we get – explore the assumptions of this netsh command.

Get-NetFirewallRule –Name “Allow Ping”


Hmm.  No Firewall rules found that match.  But in my netsh command I set name=”Allow Ping”, what gives?

Well, if you list all the rules out, you discover that netsh sets the DisplayName property, not the name property of the rule.  It creates a random GUID for the Name.  And, if you try New-NetFirewallRule you discover that –DisplayName is required but –Name is not.  (the things you learn).


Okay, enough discovery.

Let’s create the same rule using PowerShell in Server 2012

New-NetFirewallRule –DisplayName “Allow Ping” –Direction Inbound –Action Allow –Protocol icmpv4 –Enabled True

Now, the really nifty thing is that I can really quickly disable the same rule and turn PING echoes back off.

Set-NetFirewallRule –DisplayName “Allow Ping” –Enabled False

The rule remains, but it is simply disabled so I don’t need to create it again.  And I can turn it back on when I need.

And, to remove the rule entirely:

Remove-NetFirewallRule –DisplayName “Allow Ping”

Thursday, July 5, 2012

Hyper-V Extensible Switch unified tracing

I have been spending some quality time with the Hyper-V Networking features and I ran into a bit of a problem that I needed to unwind.

I was using the new Network Virtualization feature and I was encapsulating the traffic. 

This is where one host gets the packet from a VM, wraps it in an envelope, sends it to the host where the target VM is, unwraps its, and sends it to the receiving VM.

They also support IP Rewrite, which can be through of as NAT’ing.

I was having a problem where I needed to determine if things were working properly.  I had no way to tell without some type of tracing.

This is where Unified Tracing comes in.  You enable it on the Hyper-V Server and tell it which module and you get this highly detailed ETL format back out (use the latest Network Monitor to view).  I can see the traffic leave the VM, then hit the Network Virtualization module, then leave the switch and so on. 

I can capture the Windows Network Virtualization events by executing the following:

Netsh trace start provider=Microsoft-windows-wnv level=5

I can capture switch events and packets by executing the following:

Netsh trace start provider=Microsoft-Windows-Hyper-V-VmSwitch capture=yes capturetype=vmswitch

I capture both together (as you can only have one trace active at a time) with the following:

Netsh trace start provider=Microsoft-windows-wnv level=5 provider=Microsoft-Windows-Hyper-V-VmSwitch capture=yes capturetype=vmswitch

Now, what I did was I took my synchronization script and I combined that with this tracing into the following coordinating trace capture script:

# Coordinated Network tracing of Windows Network Virtualization
# Run this on both hosts.
# this will run for 3 minutes and then stop.  This should be enough time to do your test.  Change as you need.

# Only one trace can be executing at a time, you must choose one.
$selection = Read-Host -Prompt "Enter the trace number `
1 - WNV Events`
2 - VM packets and switch events`
3 - Both 1 and 2`

# wait until the next 5 minute even increment
Do {
    # square up near the whole minute mark to "synchronize watches"
    Start-Sleep ( 60 - (Get-Date -Format ss) )
    [string]$nowMinute = Get-Date -Format mm
} until ( $nowMinute -match ".[0,5]" )


"Begin Repro"

switch ( $selection ) {
    1 {
        # capture WNV events
        $trace = Netsh trace start provider=Microsoft-windows-wnv level=5
    2 {
        # capture switch events and packets
        $trace = Netsh trace start provider=Microsoft-Windows-Hyper-V-VmSwitch capture=yes capturetype=vmswitch
    3 {
        # capture both providers together
        $trace = Netsh trace start provider=Microsoft-windows-wnv level=5 provider=Microsoft-Windows-Hyper-V-VmSwitch capture=yes capturetype=vmswitch

Start-sleep -Seconds 120  #Two minutes of this is plenty of noise to pick through.

"Stopping Trace"

# Stop the trace
Netsh trace stop

foreach ( $i in $trace ) {
    if ( $i.Contains("Trace File") ) {
        $tracePath = $i.Split(" ")
        $file = $tracepath[($tracepath.Length - 1)]
# Convert the ETL to TXT
Netsh trace convert $file

# The ETL can be viewed using Netmon 3.4 or newer.