Saving & Restoring IP Configuration

We are getting ready to convert our ESXi cluster to AHV. During the process each VM will be shutdown briefly and Windows VM’s in particular will likely lose their VMware NIC and gain a AHV related NIC.

We are expecting this because that is what happened on our first ESXi to AHV conversion. That was only 25 VM’s so it wasn’t a big deal. Our big cluster will have over 200 Windows VM’s, so I’ve been writing and testing a script to save the IP configuration for restoring after the VM is converted.

The script is correctly saving all of the IP addresses the server has assigned to it if the configuration file is missing. However, when I delete the NIC and add a new one (or restore it to DHCP settings) only 1 IP address is restored, not all of the addresses found in the configuration file.

For testing, I cloned a VM with multiple IP addresses configured and deleted the NIC. Then I added a new NIC and put it on an isolated network switch (so no communications on the network). After logging into the cloned machine and running the script, only 1 IP address is restored.

Using a break point I stepped through the code that is supposed to restore each address. The variable that holds the ip info changes with each iteration, but when it’s done only a single IP is configured. Here’s the script:

In general terms the script should

  1. Check if the config file exists
  2. Check if the NIC is static or DHCP
  3. If static but no config file exists, create it
  4. If DHCP and no config file then exit (we don’t need to do anything)
  5. If DHCP and config file exist then update the NIC to be the same as the config file has
# Define the path to the configuration file
$configFilePath = "C:\temp\NetAdapterConfig.json"

# Get the active network adapter
$adapter = Get-NetAdapter | Where-Object { $_.Status -eq "Up" }

if (-not $adapter) {
    Write-Error "No active network adapter found."
    return
}

# Get the IPv4 configuration of the adapter
$ipv4Config = Get-NetIPAddress -InterfaceAlias $adapter.Name -AddressFamily IPv4
$ipv4DefaultGateway = Get-NetIPConfiguration -InterfaceAlias $adapter.Name
$dnsConfig = Get-DnsClientServerAddress -InterfaceAlias $adapter.Name -AddressFamily IPv4

# Check if the configuration file exists
if (Test-Path $configFilePath) {
    # Load the configuration file
    $config = Get-Content $configFilePath | ConvertFrom-Json

    # Check if the adapter is dynamic
    if ($ipv4Config.PrefixOrigin -contains "Dhcp") {
        # Update the network interface to match the configuration file
        foreach ($entry in $config.IPv4Addresses) {
            New-NetIPAddress -InterfaceAlias $adapter.Name -IPAddress $entry.IPAddress -PrefixLength $entry.PrefixLength -DefaultGateway $entry.DefaultGateway -ErrorAction SilentlyContinue
        }
        Set-DnsClientServerAddress -InterfaceAlias $adapter.Name -ServerAddresses $config.DnsServers
        Write-Output "Network interface updated to match the configuration file."
    }
} else {
    # If the adapter is static, create the configuration file
    if ($ipv4Config.PrefixOrigin -contains "Manual") {
        $config = @{
            IPv4Addresses = @(
                $ipv4Config | ForEach-Object {
                    @{
                        IPAddress      = $_.IPAddress
                        PrefixLength   = $_.PrefixLength
                        DefaultGateway = $ipv4DefaultGateway.IPv4DefaultGateway.NextHop
                    }
                }
            )
            DnsServers = $dnsConfig.ServerAddresses
        }

        # Save the configuration to the file
        $config | ConvertTo-Json -Depth 10 | Set-Content $configFilePath
        Write-Output "Configuration file created with the current static network settings."
    } else {
        Write-Output "No action needed. The network interface is dynamic, and no configuration file exists."
    }
}

Any ideas why it’s only restoring a single IP?

I think you need to use Set-NetIPAddress and specify an array of addresses to set, rather than New-NetIPAddress but I can’t test.

I’ll give that a spin. Thanks.

Set-NetIPAddress didn’t work either. I did finally figure out the solution.

The problem is this section of code

The New-NetIPAddress command wipes out the default gateway in this kind of loop. I solved that by changing that section to this.

$i = 0
        foreach ($entry in $config.IPv4Addresses) {
            if ($i -eq 0) {
                New-NetIPAddress -InterfaceAlias $adapter.Name -IPAddress $entry.IPAddress -PrefixLength $entry.PrefixLength -DefaultGateway $entry.DefaultGateway -ErrorAction SilentlyContinue
                $i++
            }
            else{
                New-NetIPAddress -InterfaceAlias $adapter.Name -IPAddress $entry.IPAddress -PrefixLength $entry.PrefixLength -ErrorAction SilentlyContinue
                $i++
            }
        }
The adapter settings are now the same when the adapter is removed and a new one is added.
2 Likes