Using PowerCLI to set IP and Update VMware Tools

This is a continuation of my last post, Using PowerCli to Build multiple VMs.

After automating the building of VMs, what’s the sense of having to manually add the IP information or updating the VMware tools? It’s pointless. So we need to add the IP information to the CSV file that was used to build the VMs.

CSV file to pull configuration information for setting VM properties
CSV file to pull configuration information for setting VM properties

Starting where I left off, the newly built VMs will need to be powered on.

####### Start VM
foreach ($vm in $vms){
      $VMName = $vm.Name
      Start-VM -VM $VMName -Confirm:$False
}

That was simple enough. Now the VMs have been powered on, and are running through the VM customization that I set during the build process. So, I need to figure out a way to make sure that the script waits until the system has finished this process before continuing. When I first started this process, I thought about just using the sleep command.

Sleeep -seconds 300

Seems good, but what if am “sleeping” the script for longer than I need to, or not long enough? But I tried it anyway, it failed bad, and didn’t work the way I wanted it to. What about waiting for the VMware tools to be running? It has to be running when the OS is booted, right?

$VMTool = Get-VM $VMName | Out-Null
$VMTool | Select -ExpandProperty ExtensionData | Select -ExpandProperty guest
$VMToolStatus = $VMTool.ToolsRunningStatus
Write-host "Checking that VMWare Tools are running on"$VMName -ForegroundColor Yellow
Sleep -Seconds 5
Do {Write-host "Still checking for VMWare Tools on"$VMName -ForegroundColor Yellow; sleep -Seconds 5}
While ($VMToolStatus -eq "guestToolsRunning")
Write-Host "VMWare tools are now running on"$VMName -ForegroundColor Green

The above seems like the perfect fix for getting the system to wait until the system was finished doing the customizations. But as it turns out, it isn’t, and I’m back at the drawing board. Although I did leave it in my script, but only to make sure that the tools upgrade works. Then it hit me…

DO {(Get-VMGuest $VMName).HostName}
While (((Get-VMGuest $VMName).HostName) -Ne "$VMName")
General information about VM
General information about VM

I just need to wait until the DNS name, matches the name that is in the CSV file. I put this piece into the script, and it worked perfectly. The script waited just the correct amount of time for the customization to complete.

 

 

The next step in the script updates the VMware Tools

Get-VM $VMName | Update-Tools

Simple and straight forward command. Update-Tools. Now the fun part, configuring the NIC. This was a tough one to get to working correctly. A few PowerCli versions back, there was a cmdlet that could be used to set the network information, Set-VMGuestNetworkInterface, but it only worked with Windows Server 2008 R2 and below. This worked great, until Windows Server 2012 came out and then the cmdlet was deprecated. So at one time during this script’s evolution, I had two sections that would be used to set the network adapter. It was based on whether it was Windows Server 2008 R2 and below, or Windows Server 2012. So the solution that I was able to come up with is as follows:

$GC = $Host.UI.PromptForCredential("Please enter credentials", "Enter Guest credentials for VM", "Local_Admin_Account", "")

$Network = Invoke-VMScript -VM $VMName -ScriptType Powershell -ScriptText "(gwmi Win32_NetworkAdapter -filter 'netconnectionid is not null').netconnectionid" -GuestUser administrator -GuestPassword password
$NetworkName = $Network.ScriptOutput
$NetworkName = $NetworkName.Trim()
Write-Host "Setting IP address for $VMname..." -ForegroundColor Yellow
Sleep -Seconds 60
$netsh = "c:\windows\system32\netsh.exe interface ip set address ""$NetworkName"" static $IP $SNM $GW" 
$netsh2 = "c:\windows\system32\netsh.exe interface ip set dnsservers ""$NetworkName"" static $DNS1"
$netsh3 = "c:\windows\system32\netsh.exe interface ip add dnsservers ""$NetworkName"" $DNS2"
$netsh4 = "c:\windows\system32\netsh.exe interface ip set winsservers ""$NetworkName"" static $WINS1"
$netsh5 = "c:\windows\system32\netsh.exe interface ip add winsservers ""$NetworkName"" $WINS2"
Invoke-VMScript -VM $VMname -GuestCredential $GC -ScriptType bat -ScriptText $netsh  
Invoke-VMScript -VM $VMname -GuestCredential $GC -ScriptType bat -ScriptText $netsh2  
Invoke-VMScript -VM $VMname -GuestCredential $GC -ScriptType bat -ScriptText $netsh3  
Invoke-VMScript -VM $VMname -GuestCredential $GC -ScriptType bat -ScriptText $netsh4  
Invoke-VMScript -VM $VMname -GuestCredential $GC -ScriptType bat -ScriptText $netsh5  
Write-Host "Setting IP address completed." -ForegroundColor Green

I had to start with authenticating to the guest VM. This script works with multiple different operating sytems, so it needs to be universal. As a result, the first part of the script uses a WMI query to get the network card name, and scrubs the variable into a usable information. Then uses NETSH.exe to configure the network interface. So the line starting with $netsh sets the static IP address, subnet mask, and gateway using the information from the WMI query. Then the next 2 line sets the DNS settings and the last 2 lines sets the WINS. It then uses Invoke-VMScript to push these settings to the VM via the VMware Tools, which is why it so important that the tools are up to date.

So the completed script looks like this.

$vms = Import-CSV "C:\Scripts\VMWare\VM Creation\NewVMs.csv"
$GC = $Host.UI.PromptForCredential("Please enter credentials", "Enter Guest credentials for VM", "Administrator", "")

foreach ($vm in $vms){
$VMName = $vm.Name
$IP = $vm.IP
$SNM = $vm.SubnetMask
$GW = $vm.Gateway
$DNS1 = $vm.DNS1
$DNS2 = $vm.DNS2
$WINS1 = $vm.WINS1
$WINS2 = $vm.WINS2
$Network = $vm.Network
$Template = $vm.Template

DO {(Get-VMGuest $VMName).HostName}
while (((Get-VMGuest $VMName).HostName) -Ne "$VMName")

Get-VM $VMName | Update-Tools
$VMTool = Get-VM $VMName | Out-Null
$VMTool | Select -ExpandProperty ExtensionData | Select -ExpandProperty guest
$VMToolStatus = $VMTool.ToolsRunningStatus
Write-host "Checking that VMWare Tools are running on"$VMName -ForegroundColor Yellow
Sleep -Seconds 5
Do {Write-host "Still checking for VMWare Tools on"$VMName -ForegroundColor Yellow; sleep -Seconds 5}
While ($VMToolStatus -eq "guestToolsRunning")
Write-Host "VMWare tools are now running on"$VMName -ForegroundColor Green

$Network = Invoke-VMScript -VM $VMName -ScriptType Powershell -ScriptText "(gwmi Win32_NetworkAdapter -filter 'netconnectionid is not null').netconnectionid" -GuestUser administrator -GuestPassword password
$NetworkName = $Network.ScriptOutput
$NetworkName = $NetworkName.Trim()
Write-Host "Setting IP address for $VMname..." -ForegroundColor Yellow
Sleep -Seconds 60
$netsh = "c:\windows\system32\netsh.exe interface ip set address ""$NetworkName"" static $IP $SNM $GW"
$netsh2 = "c:\windows\system32\netsh.exe interface ip set dnsservers ""$NetworkName"" static $DNS1"
$netsh3 = "c:\windows\system32\netsh.exe interface ip add dnsservers ""$NetworkName"" $DNS2"
$netsh4 = "c:\windows\system32\netsh.exe interface ip set winsservers ""$NetworkName"" static $WINS1"
$netsh5 = "c:\windows\system32\netsh.exe interface ip add winsservers ""$NetworkName"" $WINS2"
Invoke-VMScript -VM $VMname -GuestCredential $GC -ScriptType bat -ScriptText $netsh
Invoke-VMScript -VM $VMname -GuestCredential $GC -ScriptType bat -ScriptText $netsh2
Invoke-VMScript -VM $VMname -GuestCredential $GC -ScriptType bat -ScriptText $netsh3
Invoke-VMScript -VM $VMname -GuestCredential $GC -ScriptType bat -ScriptText $netsh4
Invoke-VMScript -VM $VMname -GuestCredential $GC -ScriptType bat -ScriptText $netsh5
Write-Host "Setting IP address completed." -ForegroundColor Green
}

Hopefully that clarifies some of the issues from the last post, and if you have any questions, hit me up in the comments.

-Stuart

Find this and all of my scripts at https://github.com/NotesofaScripter/PowerCLI

2 thoughts on “Using PowerCLI to set IP and Update VMware Tools”

    1. If you have a single ESXi host you can use the Connect-VIServer to connect to the host and remove the instances of get-cluster from the script. If you have issues, post the part of the script giving errors and I’ll assist with updating it.

Leave a Reply

Your email address will not be published. Required fields are marked *