Server Core: Change NIC binding order with nvspbind

My router VM in my home lab is a Server 2012 R2 set up running RRAS, but with the GUI features removed to save resources on the host.

It has two NICs – one “External”, facing my home router, and the “Internal”, facing the lab VMs. The external NIC just gets a DHCP address, and along with that, my ISP’s DNS server. I’d also set the DNS server on the Internal NIC, but it wasn’t taking precedence due to the binding order of the NICs. I needed to have the router VM query the lab DNS server so that it could join the domain.

Normally, in Server with a GUI, it would be easy to change the NIC binding order. Out of the box without the GUI, not so much. There’s a 3rd-party utility called nvspbind that can be used to make the change.

If you had a NIC named “Internal” that you wanted to bump up the order, and you already had nvspbind somewhere, you could just run the following:

C:\temp\nvspbind\nvspbind.exe /++ Internal ms_tcpip

Here’s my script that I can run on future lab machines to download nvspbind and configure the correct NIC binding order, assuming that there are NICs named “Internal” and “External”:

$nicName = 'Internal'
$downloadUri = ''

New-Item -ItemType Directory -Path 'c:\temp' -Force
Invoke-WebRequest -Uri $downloadUri -OutFile 'c:\temp\Microsoft_Nvspbind_package.EXE'
& 'C:\temp\Microsoft_Nvspbind_package.EXE' /T:c:\temp\nvspbind /C /Q
& 'C:\temp\nvspbind\nvspbind.exe' /++ 'Internal' ms_tcpip

Reading the Windows DHCP Server logs with PowerShell

I’ve been doing a bit of work with DHCP over the last week or so – specifically with troubleshooting IP assignment from various VLANs. I threw together a quick function to read the last (x) lines out of the current day’s DHCP server log. For now, there’s no support for reading the logs remotely. This needs to be run on the server itself.

Once you’ve dot sourced the script, just call the function. By default, it will grab the last 20 lines out of the current day’s log file.


You can specify a day, and/or the number of lines to grab from the end of the log file:

Get-DHCPServerLog -Lines 5 -Day mon

You can also pipe it to Select-Object:

Get-DHCPServerLog | Select-Object Date,Time,Description,MAC*,IP* | Format-Table -AutoSize

Here’s the source:

#requires -version 3
Get-DhcpServerLog – Reads the Windows DHCP server logs
The Windows DHCP server logs are stored in CSV format in C:\Windows\System32\dhcp
It's difficult to read these logs in Notepad due to them being in CSV format.
By default, this script reads the last 20 lines of the current day's log, and
converts each line into a PSObject.
Additionally, the PSObject will also contain descriptive versions of the ID and QResult fields
A PSObject, output from ConvertFrom-CSV
Get-DhcpServerLog | Select-Object Date,Time,Description,MAC* | Format-Table -AutoSize
Date Time Description MAC Address
—- —- ———– ———–
08/14/15 10:23:46 Renew 68F7286B71AA
08/14/15 10:25:38 Database Cleanup Begin
08/14/15 10:25:38 Expired
08/14/15 10:25:38 0 leases expired and 0 leases deleted
08/14/15 10:25:38 0 leases expired and 0 leases deleted
08/14/15 11:37:52 Renew AC162BF8249C
Written By: Daniel Streefkerk
Todo: Nothing at the moment
Change Log
v1.0, 14/08/2015 – Initial version
function Get-DhcpServerLog {
[int]$Lines = 20,
[ValidateSet("mon","tue", "wed", "thu", "fri", IgnoreCase=$true)]
[string]$Day= (get-date).DayOfWeek.ToString().Substring(0,3)
Write-Verbose "Get-DHCPServerLog called with parameters – Lines:$Lines, Day:$Day"
# CSV header fields, to be used later when converting each line of the tailed log from CSV
$headerFields = @("ID","Date","Time","Description","IP Address","Host Name","MAC Address","User Name","TransactionID","QResult","Probationtime","CorrelationID","Dhcid","VendorClass(Hex)","VendorClass(ASCII)","UserClass(Hex)","UserClass(ASCII)","RelayAgentInformation","DnsRegError")
# Translations of the ID field, as per the description inside the log file itself
$idMeanings = @{
00 = "The log was started.";
01 = "The log was stopped.";
02 = "The log was temporarily paused due to low disk space.";
10 = "A new IP address was leased to a client.";
11 = "A lease was renewed by a client.";
12 = "A lease was released by a client.";
13 = "An IP address was found to be in use on the network.";
14 = "A lease request could not be satisfied because the scope's address pool was exhausted.";
15 = "A lease was denied.";
16 = "A lease was deleted.";
17 = "A lease was expired and DNS records for an expired leases have not been deleted.";
18 = "A lease was expired and DNS records were deleted.";
20 = "A BOOTP address was leased to a client.";
21 = "A dynamic BOOTP address was leased to a client.";
22 = "A BOOTP request could not be satisfied because the scope's address pool for BOOTP was exhausted.";
23 = "A BOOTP IP address was deleted after checking to see it was not in use.";
24 = "IP address cleanup operation has begun.";
25 = "IP address cleanup statistics.";
30 = "DNS update request to the named DNS server.";
31 = "DNS update failed.";
32 = "DNS update successful.";
33 = "Packet dropped due to NAP policy.";
34 = "DNS update request failed as the DNS update request queue limit exceeded.";
35 = "DNS update request failed.";
36 = "Packet dropped because the server is in failover standby role or the hash of the client ID does not match.";
# Event descriptions for 50-64 sourced from
50 = "The DHCP server could not locate the applicable domain for its configured Active Directory installation.";
51 = "The DHCP server was authorized to start on the network.";
52 = "The DHCP server was recently upgraded to a Windows Server 2003 operating system, and, therefore, the unauthorized DHCP server detection feature (used to determine whether the server has been authorized in Active Directory) was disabled."
53 = "The DHCP server was authorized to start using previously cached information. Active Directory was not currently visible at the time the server was started on the network.";
54 = "The DHCP server was not authorized to start on the network. When this event occurs, it is likely followed by the server being stopped.";
55 = "The DHCP server was successfully authorized to start on the network.";
56 = "The DHCP server was not authorized to start on the network and was shut down by the operating system. You must first authorize the server in the directory before starting it again.";
57 = "Another DHCP server exists and is authorized for service in the same domain.";
58 = "The DHCP server could not locate the specified domain.";
59 = "A network-related failure prevented the server from determining if it is authorized.";
60 = "No Windows Server 2003 domain controller (DC) was located. For detecting whether the server is authorized, a DC that is enabled for Active Directory is needed.";
61 = "Another DHCP server was found on the network that belongs to the Active Directory domain.";
62 = "Another DHCP server was found on the network.";
63 = "The DHCP server is trying once more to determine whether it is authorized to start and provide service on the network.";
64 = "The DHCP server has its service bindings or network connections configured so that it is not enabled to provide service."
$qResultMeanings = @{0 = "No Quarantine"; 1 = "Quarantine"; 2 = "Drop Packet"; 3 = "Probation"; 6 = "No Quarantine Information"}
$filePath = "$env:SystemRoot\System32\dhcp\DhcpSrvLog-$Day.log"
Write-Verbose "Attempting to search for DHCP log at location: $filePath"
if ((Test-Path $filePath) -eq $false) { throw "Couldn't locate DHCP log at $filePath" }
Write-Verbose "Reading last $Lines lines from DHCP log at location: $filePath"
Get-Content $filePath tail $Lines | ConvertFrom-Csv Header $headerFields | Select-Object *,@{n="ID Description";e={$idMeanings[[int]::parse($_.ID)]}},@{n="QResult Description";e={$qResultMeanings[[int]::parse($_.QResult)]}}

Braindump: Moving clustered VMs from one Hyper-V cluster to another

This applies to Server 2012 and newer, but these directions are from when I moved VMs from a 2012 cluster to a 2012 R2 cluster.

  1. On the new cluster, right-click on the cluster and choose More Actions -> Copy Cluster Roles
  2. Choose the roles to copy, and then complete the wizard. This will set up the roles and their dependencies on the destination cluster.
  3. Shut down the VMs on the source cluster
  4. Take the relevant storage offline in Failover Cluster Manager (FCM)
  5. Disconnect the iSCSI volumes on all source cluster nodes
  6. Re-assign the LUNs to the new cluster nodes in your SAN of choice’s management console
  7. Connect the LUNs on the destination cluster nodes, but leave the disks offline in disk management
  8. In FCM, go to storage and bring the copied disks online. You should see the volume details reflected in the bottom details pane if all is successful.
  9. Start the VMs