I have a customer right now that currently has almost all e1000 NICs on their VMs. This environment has been close to a nightmare from the beginning, but we are slowly getting it into shape. They came to me wanting to change all of their NICs to VMXNET, whether it be for better performance or to just be within best practice. A couple of their requirements were limited downtime and a way to automate the process. When I heard “automate”, I immediately went to PowerCLI to see if there was a way to complete this request for them. After plugging away for a couple days, this script is what I came up with, and verified it working in my personal lab.
This script will go through the entire virtual environment, grab all the VM names and IP information, and export to a .csv file. It then prompts the user to verify the IP information before continuing. It will then go through each VM, one by one, to shut down the guest OS. Once it verifies the VM is powered off, it removes the e1000 NIC, adds the VMXNET NIC, and powers it back on. Once the VM is back up, and VMtools is running, it will set the IP information and re-register the VM with DNS.
Add-PSSnapin VMware.VimAutomation.Core
$VIServer = read-host "Enter vCenter name (FQDN)"
$VCusername = read-host "Enter vCenter Username"
$VCpassword = read-host "Enter vCenter Password" -assecurestring
$VMuser = read-host "Enter Username for VM - MUST BE LOCAL ADMIN ACCOUNT"
$VMpassword = read-host "Enter Password for VM" -assecurestring
$decodedVCpassword = [System.Runtime.InteropServices.Marshal]::PtrToStringAuto([System.Runtime.InteropServices.Marshal]::SecureStringToBSTR($VCpassword))
$decodedVMpassword = [System.Runtime.InteropServices.Marshal]::PtrToStringAuto([System.Runtime.InteropServices.Marshal]::SecureStringToBSTR($VMpassword))
Connect-VIServer $VIserver -username $VCusername -password $decodedVCpassword
$FileLoc = read-host "Enter path for Output file example: C:\scripts"
$VMlistLoc = read-host "Enter location of csv file VM List example: C:\scripts\VMlist.csv"
$IPList = "$FileLoc\IPfile.csv"
$VMList = "$VMlistLoc"
$IPtxtfile = "$FileLoc\IPfile.txt"
$IPfile = "$FileLoc\IPfile.csv"
new-item $IPtxtfile -type file
Import-csv $VMList |
foreach {
$vm = $_.name
foreach ($VM in (Get-vm $vm | where {$_.Guest.OSFULLName -like "*200*"}))
{
Write-Host "Working on $vm"
#PowerShell used by Invoke-VMScript to retrieve current IP Address
$currentIp = (Get-VMGuestNetworkInterface -VM $vm -GuestUser $VMuser -GuestPassword $decodedVMpassword | where {$_.Name -like "Local*"} | select IP)
$currentIp = $currentIp -replace "@|{|IP=|}",""
write-host "$vm, current IP Address is $currentIp"
$currentsubnet = (Get-VMGuestNetworkInterface -VM $vm -GuestUser $VMuser -GuestPassword $decodedVMpassword | where {$_.Name -like "Local*"} | select SubnetMask | foreach {$_.SubnetMask})
write-host "$currentsubnet is the current Subnet Mask"
$currentDefaultGateway = (Get-VMGuestNetworkInterface -VM $vm -GuestUser $VMuser -GuestPassword $decodedVMpassword | where {$_.Name -like "Local*"} | select DefaultGateway | foreach {$_.DefaultGateway})
write-host "$currentDefaultGateway is the current Default Gateway"
$currentDNS = (Get-VMGuestNetworkInterface -VM $vm -GuestUser $VMuser -GuestPassword $decodedVMpassword | where {$_.Name -like "Local*"} | select Dns | foreach {$_.Dns})
$currentDNS = $currentDNS -replace "@|{|Dns=|}",""
$currentDNS = $currentDNS -join ","
write-host "$currentDNS are the current DNS Servers"
$currentVMnetwork = (Get-vm $vm | get-networkadapter | select NetworkName | foreach {$_.NetworkName})
write-host "$currentVMnetwork is the current VM Network"
$vminfo = $_.name + "," + $currentIp + "," + $currentsubnet + "," + $currentDefaultGateway + "," + $currentDNS + "," + $currentVMnetwork
$vminfo | out-file $IPtxtfile -append
}
foreach ($VM in (Get-vm $vm | where {$_.Guest.OSFULLName -like "*2012*"}))
{
Write-Host "Working on $vm"
#PowerShell used by Invoke-VMScript to retrieve current IP Address
$ipscript = '(Get-NetIpAddress | where-object {$_.AddressFamily -eq "IPv4" -and $_.InterfaceAlias -like "Eth*"}).IPAddress'
$currentIp = invoke-vmscript -ScriptText $ipscript -ScriptType PowerShell -VM $vm -GuestUser $VMuser -GuestPassword $decodedVMpassword
$currentIp = $currentIp -replace "`t|`n|`r",""
write-host "$vm, current IP Address is $currentIp"
$subnetscript = '(Get-WmiObject win32_networkAdapterConfiguration | where-object {$_.IPAddress -ne $null} | select IPSubnet)'
$currentsubnet = invoke-vmscript -ScriptText $subnetscript -ScriptType PowerShell -VM $vm -GuestUser $VMuser -GuestPassword $decodedVMpassword
$currentsubnet = $currentsubnet -replace "`t|`n|`r",""
$currentsubnet = $currentsubnet -replace "IPSubnet|\s|-|{|}|64|,",""
write-host "$currentsubnet is the current Subnet Mask"
$gatewayscript = '(Get-WmiObject win32_networkAdapterConfiguration | where-object {$_.IPAddress -ne $null} | select DefaultIPGateway)'
$currentDefaultGateway = invoke-vmscript -ScriptText $gatewayscript -ScriptType PowerShell -VM $vm -GuestUser $VMuser -GuestPassword $decodedVMpassword
$currentDefaultGateway = $currentDefaultGateway -replace "`t|`n|`r",""
$currentDefaultGateway = $currentDefaultGateway -replace "DefaultIPGateway|\s|-|{|}|,",""
write-host "$currentDefaultGateway is the current Default Gateway"
$dnsscript = '(Get-WmiObject win32_networkAdapterConfiguration | where-object {$_.IPAddress -ne $null} | select DNSServerSearchOrder)'
$currentDNS = invoke-vmscript -ScriptText $dnsscript -ScriptType PowerShell -VM $vm -GuestUser $VMuser -GuestPassword $decodedVMpassword
$currentDNS = $currentDNS -replace "`t|`n|`r|{|}",""
$currentDNS = $currentDNS -replace "DNSServerSearchOrder|\s|-|{|}|64",""
write-host "$currentDNS are the current DNS Servers"
$currentVMnetwork = (Get-vm $vm | get-networkadapter | select NetworkName | foreach {$_.NetworkName})
write-host "$currentVMnetwork is the current VM Network"
$vminfo = $_.name + "," + $currentIp + "," + $currentsubnet + "," + $currentDefaultGateway + "," + $currentDNS + "," + $currentVMnetwork
$vminfo | out-file $IPtxtfile -append
}
}
Write-Host "Creating output file"
import-csv $IPtxtfile -delimiter "," -Header name,ip,subnetmask,gateway,pdns,sdns,vmnetwork | export-csv $IPfile -NoType
Write-Host "Removing Temporary Files"
remove-item $IPtxtfile -recurse
##############--Getting ready to change NIC and IP Address Information--##############
Invoke-Item $IPfile
read-host "Please verify IP Information, press ENTER to continue or CTRL-C to END"
#Guest Credentials - Must have required permissions to change IP address
$GuestUserName = $VMuser
$GuestPassword = $decodedVMpassword
Import-csv $IPList |
##############NO CHANGES BEYOND THIS POINT##############
foreach {
$vm = $_.name
$newIp = $_.ip
$newMask = $_.subnetmask
$newGateway = $_.gateway
$PrimaryDNS = $_.pdns
$SecondaryDNS = $_.sdns
$networkName = $_.vmnetwork
if (Get-vm $vm | get-networkadapter | where {$_.Type -Like "e1000*"}){
foreach ($vm in (Get-vm $vm | where {$_.Guest.OSFULLName -like "*200*"}))
{
Write-Host "Working on $vm"
get-vm $vm | Shutdown-VMguest -confirm:$false
Write-Host "Waiting for VM to shutdown"
if ($vm.PowerState -eq "PoweredOn") {
Write-Host "Shutting Down $vm"
#$vm | Shutdown-VMGuest -Confirm:$false
#Wait for Shutdown to complete
do {
#Wait 5 seconds
Start-Sleep -s 5
#Check the power status
$VM = Get-VM $vm
$status = $VM.PowerState
}until($status -eq "PoweredOff")
}
elseif ($VM.PowerState -eq "PoweredOff") {
Write-Host "$vm is powered down"
}
Get-NetworkAdapter -vm $vm | where {$_.Type -like "e1000*"} | Remove-NetworkAdapter -confirm:$false
Start-Sleep -s 10
New-NetworkAdapter -vm $vm -NetworkName "$networkName" -Type "vmxnet3" -StartConnected
Start-Sleep -s 10
write-host "Waiting on VMtools to load"
Start-VM $vm -confirm:$false | Wait-Tools
Start-Sleep -s 30
Write-Host "Working on $vm"
#PowerShell used by Invoke-VMScript to retrieve current IP Address
$currentIp = (Get-VMGuestNetworkInterface -VM $vm -GuestUser $VMuser -GuestPassword $decodedVMpassword | where {$_.Name -like "Local*"} | select IP)
$currentIp = $currentIp -replace "@|{|IP=|}",""
write-host "$currentIp is the current IP Address"
#Adjust Original IP to Replacement IP
$changeIp = $currentIp.replace("$currentIp", "$newIp")
$changeIp = $changeIp
Write-Host "Changing IP to $changeIp"
#Get the Interface Name (Alias)
$getIntAlias = (Get-VMGuestNetworkInterface -VM $vm -GuestUser $VMuser -GuestPassword $decodedVMpassword | where {$_.Name -like "Local*"} | select Name)
$getIntAlias = $getIntAlias -replace "@|{|Name=|}",""
write-host "The interface name is $getIntAlias"
#Change the IP Address
$changingIp = '%WINDIR%\system32\netsh.exe interface ipv4 set address name="' + $getIntAlias + '" source=static address=' + $changeIp + ' mask=' + $newMask + ' gateway=' + $newGateway + ' gwmetric=1 store=persistent'
Write-host "Changing IP Address of $vm interface $getIntAlias from $currentIp to $changeIp"
$setIp = invoke-vmscript -ScriptText $changingIp -ScriptType bat -VM $vm -GuestUser $GuestUserName -GuestPassword $GuestPassword
#Changing Primary DNS Server
Write-Host "Setting Primary DNS Server to $PrimaryDNS"
$changePDNS = '%WINDIR%\system32\netsh.exe interface ipv4 set dnsserver name="' + $getIntAlias + '" source=static address=' + $PrimaryDNS + ' register=primary'
$setPDNS = invoke-vmscript -ScriptText $changePDNS -ScriptType bat -VM $vm -GuestUser $GuestUserName -GuestPassword $GuestPassword
Write-Host "Setting Alternate DNS Server to $SecondaryDNS"
#Changing Secondary DNS Server
$changeSDNS = '%WINDIR%\system32\netsh.exe interface ipv4 add dnsserver name="' + $getIntAlias + '" address=' + $SecondaryDNS + ' index=2'
$setSDNS = invoke-vmscript -ScriptText $changeSDNS -ScriptType bat -VM $vm -GuestUser $GuestUserName -GuestPassword $GuestPassword
#Register with DNS
Write-Host "Registering with DNS"
$registeringDNS = '%WINDIR%\System32\ipconfig /registerdns'
$segDNS = invoke-vmscript -ScriptText $registeringDNS -ScriptType bat -VM $vm -GuestUser $GuestUserName -GuestPassword $GuestPassword
Write-Host "Finished with $vm"
}
foreach ($vm in (Get-vm $vm | where {$_.Guest.OSFULLName -like "*2012*"}))
{
Write-Host "Working on $vm"
get-vm $vm | Shutdown-VMguest -confirm:$false
#Write-Host "Waiting for VM to shutdown"
if ($vm.PowerState -eq "PoweredOn") {
Write-Host "Shutting Down $vm"
#$vm | Shutdown-VMGuest -Confirm:$false
#Wait for Shutdown to complete
do {
#Wait 5 seconds
Start-Sleep -s 5
#Check the power status
$VM = Get-VM $vm
$status = $VM.PowerState
}until($status -eq "PoweredOff")
}
elseif ($VM.PowerState -eq "PoweredOff") {
Write-Host "$vm is powered down"
}
Get-NetworkAdapter -vm $vm | where {$_.Type -like "e1000e"} | Remove-NetworkAdapter -confirm:$false
Start-Sleep -s 10
New-NetworkAdapter -vm $vm -NetworkName "$networkName" -Type "vmxnet3" -StartConnected
Start-Sleep -s 10
write-host "Waiting on VMtools to load"
Start-VM $vm -confirm:$false | Wait-Tools
Start-Sleep -s 30
Write-Host "Working on $vm"
#PowerShell used by Invoke-VMScript to retrieve current IP Address
$ipscript = '(Get-NetIpAddress | where-object {$_.AddressFamily -eq "IPv4" -and $_.InterfaceAlias -like "Eth*"}).IPAddress'
$currentIp = invoke-vmscript -ScriptText $ipscript -ScriptType PowerShell -VM $vm -GuestUser $GuestUserName -GuestPassword $GuestPassword
$currentIp = $currentIp -replace "`t|`n|`r",""
write-host "$currentIp is the current IP Address"
#Adjust Original IP to Replacement IP
$changeIp = $currentIp.replace("$currentIp", "$newIp")
$changeIp = $changeIp -replace "`t|`n|`r",""
Write-Host "Changing IP to $changeIp"
#Get the Interface Name (Alias)
$aliasscript = '(Get-NetIPAddress | where-object {$_.IPAddress -match "' + $currentIp + '" -and $_.AddressFamily -eq "IPv4"}).InterfaceAlias'
$getIntAlias = invoke-vmscript -ScriptText $aliasscript -ScriptType PowerShell -VM $vm -GuestUser $GuestUserName -GuestPassword $GuestPassword
$getIntAlias = $getIntAlias -replace "`t|`n|`r",""
write-host "The interface name is $getIntAlias"
#Change the IP Address
$changingIp = '%WINDIR%\system32\netsh.exe interface ipv4 set address name="' + $getIntAlias + '" source=static address=' + $changeIp + ' mask=' + $newMask + ' gateway=' + $newGateway + ' gwmetric=1 store=persistent'
Write-host "Changing IP Address of $vm interface $getIntAlias from $currentIp to $changeIp"
$setIp = invoke-vmscript -ScriptText $changingIp -ScriptType bat -VM $vm -GuestUser $GuestUserName -GuestPassword $GuestPassword
#Change DNS Servers
Write-Host "Setting DNS Server to $PrimaryDNS $SecondaryDNS"
$changeDNS = "Set-DnsClientServerAddress -InterfaceAlias $getIntAlias -ServerAddresses '$PrimaryDNS','$SecondaryDNS'"
$setDNS = invoke-vmscript -ScriptText $changeDNS -ScriptType Powershell -VM $vm -GuestUser $GuestUserName -GuestPassword $GuestPassword
#Register with DNS
Write-Host "Registering with DNS"
$registeringDNS = '%WINDIR%\System32\ipconfig /registerdns'
$segDNS = invoke-vmscript -ScriptText $registeringDNS -ScriptType bat -VM $vm -GuestUser $GuestUserName -GuestPassword $GuestPassword
Write-Host "Finished with $vm"
}
}
else {write-host "$vm NIC Type is already VMXNET3, Skipping"
}
}
Disconnect-VIServer -confirm:$false