Archive

Posts Tagged ‘netsh’

PowerCLI cmdlets: Get/Set-VMGuestNetworkInterface

June 8th, 2010 Jase No comments

After my last post on Get/Set-OSCustomizationNicMapping, I started looking further at what options there were to configure network settings for guests that were “already” created.

It is one thing to be able to set the network adapter properties during the cloning process and something entirely different to do it after the fact.  Maybe a mistake was made during the cloning process.  More likely a network migration could be planned, and a completely different way of doing things would be needed.

Using Invoke-VMScript
In January, I wrote a post on how to Update VMware Windows Guest DNS and WINS through PowerCLI that uses the Invoke-VMScript cmdlet to run a batch file in Windows to set the DNS and WINS information.  For those versed with netsh, it is powerful, but there are requirements

One pretty big requirement is that the  name of the network adapter must be known.  On older VM’s, or possibly P2V’ed VM’s the network adapter name could be something like “Local Network Connection 2″, “Local Network Connection 3″, etc.  Using the above mentioned script is going to fail if the connection name is not known.  The only way around that, would be to put some logic in to determine the name to use when calling the script.  Additionally using netsh with DNS and WINS requires the addition of new values, and deletion of old values.

Another issue with the Invoke-VMScript method, is that it requires different scripts for Windows and Linux guests.

A Different Way
So I started to peruse the online docs for the current vSphere 4.0 Update 1 and found the Get/Set-VMGuestNetworkInterface cmdlets.  Just like my last post, I couldn’t really find any example scripts of anyone using it.

Here is the syntax for these cmdlets:

Get-VMGuestNetworkInterface
Syntax
Get-VMGuestNetworkInterface [[-VM] <VirtualMachine[]>] [-VMGuest <VMGuest[]>] [-Server <VIServer[]>] [-ToolsWaitSecs <Int32>] [-GuestPassword <SecureString>] [-GuestUser <String>] [-GuestCredential <PSCredential>] [-HostPassword <SecureString>] [-HostUser <String>] [-HostCredential <PSCredential>] [<CommonParameters>]

Set-VMGuestNetworkInterface
Syntax
Set-VMGuestNetworkInterface -VmGuestNetworkInterface <VMGuestNetworkInterface[]> [-WinsPolicy <DhcpPolicy>] [-Wins <String[]>] [-DnsPolicy <DhcpPolicy>] [-Dns <String[]>] [-IPPolicy <DhcpPolicy>] [[-Gateway] <Object>] [[-Netmask] <String>] [[-Ip] <IPAddress>] [-ToolsWaitSecs <Int32>] [-GuestPassword <SecureString>] [-GuestUser <String>] [-GuestCredential <PSCredential>] [-HostPassword <SecureString>] [-HostUser <String>] [-HostCredential <PSCredential>] [-WhatIf] [-Confirm] [<CommonParameters>]

One thing that struck me as odd, was that both of these commands have the following statements as part of their documentation:

… Consider that this functionality is experimental. …

and

Notes
Supported on ESX 3.5 and newer. …

So which is it? Maybe @cshanklin can address this at some point.

How Does It Really Work?
Are the Get/Set-VMGuestNetworkInterface cmdlets really that different from Invoke-VMScript? Not really, except for the fact that VMware has taken some of the guesswork out of the process.  These cmdlets actually call scripts in the Scripts folder located under the installation path of the vSphere PowerCLI.  There are separate scripts for Windows OSes and Linux OSes (currently only supported on RHEL 5).

The netsh scripting limitation I mentioned earlier (network connection name) is actually taken care of by these scripts.  Additionally these scripts can be modified/added to if desired.

There are a couple things to be aware of.

  • Set-VMGuestNetworkInterface does not work in my environment if the vNic is disconnected.
  • I could not use the vSphere PowerCLI in x64 mode to run the script.  The PowerCLI stated that I needed to use the 32bit PowerCLI instead.
  • WINS settings are not available in Linux guests.

How To Update
Now how do I go and update IP addresses on several machines (possibly those that I created in my last post)?

Here are the contents of my text file (C:\vms.csv) that contained my VM names and other settings.

basevm,datastore,vmhost,custspec,vmname,ipaddress,subnet,gateway,pdnswins,sdnswins,vlan
BASEVM,DS1,ESXi1,W2K3,VM01,192.168.0.80,255.255.255.0,192.168.0.1,192.168.0.199,192.168.0.198,Primary
BASEVM,DS1,ESXi1,W2K3,VM02,192.168.0.81,255.255.255.0,192.168.0.1,192.168.0.199,192.168.0.198,Primary
BASEVM,DS1,ESXi1,W2K3,VM03,192.168.0.82,255.255.255.0,192.168.0.1,192.168.0.199,192.168.0.198,Primary
BASEVM,DS1,ESXi1,W2K3,VM04,192.168.255.83,255.255.255.0,192.168.0.1,192.168.0.199,192.168.0.198,Secondary
BASEVM,DS1,ESXi1,W2K3,VM05,192.168.255.84,255.255.255.0,192.168.0.1,192.168.0.199,192.168.0.198,Secondary

So I’ll modify it because I didn’t mean to use 192.168.0.x, I meant to use 192.168.1.x. And I’ll pull out the things I don’t need, like basevm, datastore, vmhost, & custspec.

vmname,ipaddress,subnet,gateway,pdnswins,sdnswins,vlan
VM01,192.168.1.80,255.255.255.0,192.168.1.1,192.168.1.199,192.168.1.198,Primary
VM02,192.168.1.81,255.255.255.0,192.168.1.1,192.168.1.199,192.168.1.198,Primary
VM03,192.168.1.82,255.255.255.0,192.168.1.1,192.168.1.199,192.168.1.198,Primary
VM04,192.168.255.83,255.255.255.0,192.168.1.1,192.168.1.199,192.168.1.198,Secondary
VM05,192.168.255.84,255.255.255.0,192.168.1.1,192.168.1.199,192.168.1.198,Secondary

Now I’ll save it as C:\vms-newip.csv.

Also, unlike the Get/Set-OSCustomizationNicMapping cmdlet, I’ll have to connect specifically to the host and the guest with appropriate credentials.  I have to do this, because credentials are required in the guest to make the change.

The Script
I’ll use the following script to update the VM’s.

##########################################################
# updateip.ps1
# Jase McCarty 6/6/2010
# Posh Script to update IP
# addresses in Virtual Machines
##########################################################

Connect-VIServer vcenter.jasemccarty.com

$HostCred = $Host.UI.PromptForCredential("Please enter credentials", "Enter ESX host credentials", "", "")
$GuestCred = $Host.UI.PromptForCredential("Please enter credentials", "Enter Guest credentials", "", "")

$vmlist = Import-CSV C:\vms.csv

foreach ($item in $vmlist) {

  # I like to map out my variables
  $vmname = $item.vmname
  $ipaddr = $item.ipaddress
  $subnet = $item.subnet
  $gateway = $item.gateway
  $pdnswins = $item.pdnswins
  $sdnswins = $item.sdnswins

  #Get the current interface info
  $GuestInterface = Get-VMGuestNetworkInterface -VM $vmname -HostCredential $HostCred -GuestCredential $GuestCred

  #If the IP in the VM matches, then I don't need to update
  If ($ipaddr -ne $($GuestInterface.ip)) {
      Set-VMGuestNetworkInterface  -VMGuestNetworkInterface $GuestInterface -HostCredential $HostCred -GuestCredential $GuestCred -IP $ipaddr -Netmask $subnet -Gateway $gateway -DNS $pdnswins,$sdnswins -WINS $pdnswins,$sdnswins
  }
}

As can be seen, it doesn’t take a complex script to update IP information in guests.

Keep in mind that not all of the attributes that I chose to use are required.  If desired, only the IP, DNS, WINS, etc can be updated.  My script just happens to update several of these items.  Additionally, this can be used to change a guest from a static IP address to a DHCP address as well.

Hopefully this script will help you when presented with a similar task of updating IP addresses/DNS/WINS settings.

For More Info
For more info on each of these commands, look here for the VMware documentation:

Update VMware Windows Guest DNS and WINS through PowerCLI

January 22nd, 2010 Jase No comments

I was really taken with Arnim van Lieshout’s post on running getting WMI from inside a guest through the PowerCLI, so I decided to play around a little bit with this.

The ability of the PowerCLI to use the Invoke-VMScript command is really a great addition to the set of tools the PowerCLI provides.

I typically only have Windows guests, minus a couple VMware appliances, so I decide to focus on how to leverage this functionality within Windows.  There are many articles out there on how to use netsh to update DNS and WINS settings.

A typical set of commands to update DNS and WINS look like this:

netsh interface ip set dns “Local Area Connection” static x.x.x.x
netsh interface ip add dns “Local Area Connection” x.x.x.y
netsh interface ip delete wins “Local Area Connection” x.x.x.a
netsh interface ip delete wins “Local Area Connection” x.x.x.b
netsh interface ip add wins “Local Area Connection” x.x.x.x
netsh interface ip add wins “Local Area Connection” x.x.x.y index=2

*** Where x.x.x.x is the new primary DNS/WINS, x.x.x.y is the new secondary DNS, x.x.x.a is the old primary WINS, and the old secondary WINS.

Not a difficult command, provided the guest’s network adapter is named the default of “Local Area Connection”.

Netsh can easily set a primary DNS and add a secondary DNS, which overwrites the current settings.  WINS on the other hand, can only have WINS addresses added or deleted.  So I chose to set the DNS, delete old WINS entries, and add new WINS entries.

My first attempt at creating this script looks like this:

$VIServer = Read-Host "Enter vCenter Server Name or IP: "
Connect-VIServer $VIServer

$HostCred = $Host.UI.PromptForCredential("Please enter credentials", "Enter ESX host credentials", "", "")
$GuestCred = $Host.UI.PromptForCredential("Please enter credentials", "Enter Guest credentials", "", "")
$PrimaryDNS = Read-Host "Primary DNS: "
$SecondaryDNS = Read-Host "Secondary DNS: "
$PrimaryOldWINS = Read-Host "Old Primary WINS: "
$SecondaryOldWINS = Read-Host "Old Secondary WINS: "
$PrimaryWINS = Read-Host "Primary WINS: "
$SecondaryWINS = Read-Host "Secondary WINS: "

get-vm |  %{ $_.Name; $_ | Invoke-VMScript -HostCredential $HostCred -GuestCredential $GuestCred -ScriptType "bat" -ScriptText "netsh interface ip set dns ""Local Area Connection"" static $PrimaryDNS" }
get-vm |  %{ $_.Name; $_ | Invoke-VMScript -HostCredential $HostCred -GuestCredential $GuestCred -ScriptType "bat" -ScriptText "netsh interface ip add dns ""Local Area Connection"" $SecondaryDNS" }
get-vm |  %{ $_.Name; $_ | Invoke-VMScript -HostCredential $HostCred -GuestCredential $GuestCred -ScriptType "bat" -ScriptText "netsh interface ip delete wins ""Local Area Connection"" $PrimaryOldWINS" }
get-vm |  %{ $_.Name; $_ | Invoke-VMScript -HostCredential $HostCred -GuestCredential $GuestCred -ScriptType "bat" -ScriptText "netsh interface ip delete wins ""Local Area Connection"" $SecondaryOldWINS" }
get-vm |  %{ $_.Name; $_ | Invoke-VMScript -HostCredential $HostCred -GuestCredential $GuestCred -ScriptType "bat" -ScriptText "netsh interface ip add wins ""Local Area Connection"" $PrimaryWINS" }
get-vm |  %{ $_.Name; $_ | Invoke-VMScript -HostCredential $HostCred -GuestCredential $GuestCred -ScriptType "bat" -ScriptText "netsh interface ip add wins ""Local Area Connection"" $SecondaryWINS index=2" }

It works, but it is a little ugly because it performs an action against a guest, then proceeds to the next, and so on.  When the first command is done, it loops through all the VM’s and performs the second command.  This isn’t really an efficient way of doing this.

So I pulled “&&” out of my old bag of DOS tricks to see if I could run multiple netsh commands simultaneous.

From inside a VM, I ran a combined netsh command, which looked something like this:

netsh interface ip set dns “Local Area Connection” static x.x.x.x && netsh interface ip add dns “Local Area Connection” x.x.x.y && netsh interface ip delete wins “Local Area Connection” x.x.x.a && netsh interface ip delete wins “Local Area Connection” x.x.x.b && netsh interface ip add wins “Local Area Connection” x.x.x.x && netsh interface ip add wins “Local Area Connection” x.x.x.y index=2

Success!

Now to incorporate this into my PowerCLI script.  Here’s what I came up with:

$VIServer = Read-Host "Enter vCenter Server Name or IP: "
Connect-VIServer $VIServer

$HostCred = $Host.UI.PromptForCredential("Please enter credentials", "Enter ESX host credentials", "", "")
$GuestCred = $Host.UI.PromptForCredential("Please enter credentials", "Enter Guest credentials", "", "")
$PrimaryDNS = Read-Host "Primary DNS: "
$SecondaryDNS = Read-Host "Secondary DNS: "
$PrimaryOldWINS = Read-Host "Old Primary WINS: "
$SecondaryOldWINS = Read-Host "Old Secondary WINS: "
$PrimaryWINS = Read-Host "Primary WINS: "
$SecondaryWINS = Read-Host "Secondary WINS: "

get-vm |  %{ $_.Name; $_ | Invoke-VMScript -HostCredential $HostCred -GuestCredential $GuestCred -ScriptType "bat" -ScriptText "netsh interface ip set dns ""Local Area Connection"" static $PrimaryDNS && netsh interface ip add dns ""Local Area Connection"" $SecondaryDNS && netsh interface ip delete wins ""Local Area Connection"" $PrimaryOldWINS && netsh interface ip delete wins ""Local Area Connection"" $SecondaryOldWins && netsh interface ip add wins ""Local Area Connection"" $PrimaryWINS && netsh interface ip add wins ""Local Area Connection"" $SecondaryWINS index=2" }

A much more efficient script, as it only initiates the netsh commands to the guest once per guest.  I can really use this on a project I will be implementing at some point in the future.

***Some things to note:

  • If there are any errors with WINS servers existing inside the guest (during the WINS removal piece), the DOS commands will bomb out.  This is just the nature of the beast when using DOS commands in this fashion.
  • This script assumes that the credentials for the Hosts is the same for all hosts.
  • This script assumes that the guest credentials are the same for all guests.
  • The guest has to be powered on with the VMware Tools running.

I have tested this on ESX 4.0 with Windows 2003 guests and have seen success.  Now off to test it against ESX 3.5 hosts and ESX 4.0 U1 hosts. I will also confirm that this does not work in Windows 2000 guests.  I have not tested this on Windows 2008/R2 guests.

Maybe I’ll put in some error checking into it, and possibly troubleshoot the Windows 2000 issue.

Hope it helps anyone out looking for a solution to this task.

Categories: Virtualization Tags: , , ,