Category: Uncategorized

Finding clustered VMs

Ran into an issue where a VM was being patched and rebooted, but would not boot afterwards. Turns out, there was another VM it was clustered with, and it was not noticed by the engineer that was patching. One quick little script later, and we were able to tell exactly what VMs were clustered.


$report = @()
Write-host "Report Generation is in Progress..."

foreach ($vm in Get-VM ){
$view = Get-View $vm
$settings = Get-AdvancedSetting -Entity $vm
if ($view.config.hardware.Device.Backing.sharing -eq "sharingMultiWriter" -or $settings.value -eq "multi-writer"){
$row = '' | select Name
$row.Name = $vm.Name
$report += $row
}

}
$report | Sort Name

 

Mass-Update VMtools

I ran into an issue over the last couple weeks that involved a mass upgrade of VMtools, but the customer did not want to take an outage required for the update. I was able to come up with a nice, quick little script that would find anything running Windows, check for old VMtools, and update without a reboot.

 

$oldtools = Get-VM | where-object {$_.PowerState -like “*on” -And $_.Guest -like “*Windows*” -And $_.ExtensionData.Guest.ToolsStatus -notlike “*Ok*”}
Foreach ($oldvm in $oldtools){
Update-Tools -VM $oldvm -RunAsync -NoReboot
Write-host “Updating VMtools on $oldvm”
}

Get Unmounted Storage LUNs

While working through an issue today, I came up with a quick one-liner PowerCLI command to grab all unmounted storage LUNs. This will give you Hostname, RuntimeName, Display Name, Canonoical Name, Operational State, and Capacity.


get-vmhost | get-scsilun -LunType disk | where {$_.ExtensionData.OperationalState -like "off"} | select VMHost,@{N="LUN";E={[int]($_.RuntimeName.Split(‘:’)[3].TrimStart(‘L’))}},@{N="Name";E={$_.ExtensionData.DisplayName}},CanonicalName,@{N="OperationalState";E={$_.ExtensionData.OperationalState}},CapacityGB

And if you want to pull all storage LUN information, wether mounted or unmounted

get-vmhost | get-scsilun -LunType disk | select VMHost,@{N="LUN";E={[int]($_.RuntimeName.Split(‘:’)[3].TrimStart(‘L’))}},@{N="Name";E={$_.ExtensionData.DisplayName}},CanonicalName,@{N="OperationalState";E={$_.ExtensionData.OperationalState}},CapacityGB

Get VM IP Address and Change NIC from e1000 to VMXNET

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