Changing VM and NLB IPs after SRM Failover with Powershell
Here it is, my little project I have been working on for the last few weeks. Yes, I know, a few weeks is quite a long time for a script. This however is my first time writing a powershell script, so there have a been a few road bumps and blocks a long the way.
My goal for the script is such being able to re-ip a VM and an NLB cluster. I also wanted to do this to a VM that doesn’t have a current network connection. The thought being that after an srm failover the VM would not have a network connection since it would be on a different subnet and all that goodness.
My thoughts were to pull the info I wanted from a nice and simple excel spreadsheet that I would keep up to date, being that the IPs wouldn’t change that often I figured that wouldn’t be that hard. My spreadsheet looks like this.
[table "1" not found /]I think the titles there are pretty descriptive as to contents of the cells and columns.
There were also a few things I wanted to stay away from
- netsh- I didn’t want to have to script or plan for the the interface name, also I wasn’t sure how well netsh would handle re-ip with multiple IPs to a single interface
- Set-VMGuestNetworkInterface–The guests would primarily be Server 2008, which means this cmdlet just doesn’t work
That leaves me with pretty much this line
(Get-WMIObject Win32_NetworkAdapterConfiguration | where {$_.ipenabled -eq $true}).EnableStatic($ip,$mask)
Which is great but how do I use it with a VM that currently doesn’t have network access. The answer is the Invoke-VMScript cmdlet. This answer is both great and awful.
I could not and have not been able to get my re-ip line to work inside of the Invoke-VMScript cmdlet, no matter how I tried to feed to the Invoke-VMScript, it wouldn’t work. I could get it to return the interface by leaving off the .EnableStatic($ip,$mask), however once I put the EnableStatic on there it continuously had problems.
Taking it from there I decided to put the script and spreadsheet local on the target computer and run it using the Invoke-VMScript. This obviously isn’t the most ideal solution, but it’s what I got! I wrote a quick script to copy my ip script and the to those target computers.
$data=import-csv book1.csv
Foreach ($line in $data){
$match = $line.guestname
$match
IF(
(test-path \$matchc$power -pathtype container) -ne $true){
new-item \$matchc$power -type directory}
copy ./works2.ps1 \$matchc$power -confirm
copy ./book1.csv \$matchc$power -confirm
}
As you can see it just simply copies those to files to each of the guests named in the spreadsheet. This allows me to keep a central or master copy of both the script and the spreadsheet and send them out whenever there are updates.
Now my for invoke-vmscript. This one tests the guest names listed in the spreadsheet for VMs listed in a folder, if there is a match then it will run the ip changing script(works2.ps1 in my case) on the target machine. Oh, and I also threw in a ton of comments in case they are helpful….
# The $test variable can be pretty much whatever you want it to be, or with a little adjustment it isn't even necessary.
# I just wanted to set it up like this for the $match variable later on
$test=(get-folder testing|get-vm)
#$data and the csv is where all the information lies that this script/s pulls
$data=import-csv book1.csv
$hostcredential=Get-Credential "Host Credentials"
$guestcredential=Get-Credential "Guest Credentials"
#Line row, row line, same thing in a spreadsheet. I just wish I knew more of those basic understood variables such as $line.
# If anyone knows a good listing please let me know
foreach ($line in $data)
{
#For each of the VMs in $test it checks to see if there is a listing for that vm name in the excel spreadsheet.
$match=$test|?{$line.guestname -eq $_.name}
IF($match)
{
#Oh invoke-vmscript how I both love and hate you. This calls for the execution of the script works2.ps1 script locally on the target computer
invoke-vmscript -vm $match.name -scripttext '&"C:WindowsSystem32WindowsPowerShellv1.0powershell.exe" "C:Powerworks2.ps1"' -scripttype "powershell" -hostcredential $hostcredential -guestcredential $guestcredential -confirm
}
}
And last but certainly not least, my script to re-ip a VM. Not going to lie, being my first real script I am pretty proud of it.
#Different than my script to run Invoke-Vmscript, here $test is the hostname of the vm, because I am only going to be running this script against the computer it resides
$test=hostname
$data=import-csv "c:powerbook1.csv"
foreach ($line in $data){
$match=$test|?{$line.guestname -eq $_}
IF($match)
{
#Pulling the information for the vm. Basically as long
#as the naming convention I set is correct in the spreadsheet
#and the cell isn't blank, it will pull all the info it needs
$ips=1..50|%{IF ($line."ip$_" -gt ""){$line."ip$_"}}
$masks=1..50|%{IF ($line."mask$_" -gt ""){$line."mask$_"} }
$gateway=1..50|%{IF ($line."gateway$_" -gt ""){$line."gateway$_"} }
$dns=1..50|%{IF ($line."dns$_" -gt ""){$line."dns$_"} }
#I only want the network interface that is enabled. If you have more than one interface, you will need to make adjustments
$NICs =Get-WMIObject Win32_NetworkAdapterConfiguration | where {$_.ipenabled -eq $true}
#I like this nice group variable because it allows me to see what is being put into the actionable commands
#It makes it easier to troubleshoot if there are problems.
$ips
$masks
$nice
$gateway
$nics
#Setting the static IPs, Gateways, and DNS entries on the VM
$nics.EnableStatic($ips,$masks)
$nics.setgateways($gateway)
$nics.SetDNSServerSearchOrder($dns)
#This last part I threw in to change the NLB virtual IP for an NLB cluster
IF ($line.nlb -gt "")
{
#In this instance the full path of the module isn't necessary
import-module "C:WindowsSystem32WindowsPowerShellv1.0ModulesNetworkLoadBalancingClusters"
#I did a sleep to have the script pause after changing the IPs of the nics.
#I don't believe it is necessary, but changing the nlb virtual IP has been very finicky for me personally and this seems to work for me
start-sleep -s 15
#The IP of the NLB Cluster
$nlbip=$line.nlb
#I should note sometimes this does give an error about the cmdlet when in fact it does succeed in the change
#Just FYI
get-nlbclustervip -hostname $test | set-nlbclustervip -newip $nlbip
}
}
}
There are some things this script specifically was not designed to do
- Change IP on multiple interfaces for a single VM, although a few changes and it would be able to do it.
- Copy the script and excel spreadsheets out to the target VMs After a failover has occurred. A network connection is needed for that so make sure you have everything up to date.
I understand as a whole this is all kind of messy and not as clean as most people would want it. If anyone has any suggestions on how I could clean it up let me know. Please please Let me know!!
One more thing, I just recently learned powershell, and I am definitely still learning. I just wanted to say though that Hal’s Book has been immensely helpful in both teaching me powershell/powercli and as an all-around great reference guide