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.
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")
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