This is a quick script that will check your entire vcenter for VMs with the VMware tools ISO mounted and then attempt to unmounts that installer.
** Some Linux VMs will not successfully unmounts the tools installer so using the “eject” command inside the OS is needed.

#####Quick one-liner script
Import-Module -Name VMware.VimAutomation.Core
Connect-VIServer “ -User “administrator@vsphere.local” -password “password”
get-view -viewtype virtualmachine -property ‘name’ -Filter @{‘Runtime.ToolsInstallerMounted’=’True’} | foreach{$_.UnmountToolsInstaller()}
Disconnect-VIServer -confirm:$false


#####Long method: This script will log into your vcenter, use a View command to instantly check all your VMs for the mounted installer and then uninstall it. If any VMs are found it will add the name to a “report” array. I left this $report array open ended so  you can add more fields like OS or cluster ID etc for additional references.   I ran this script on a vcenter with 6,000 VMs and it completed in under a second.  It took an additional three seconds to run the unmount command on five detected VMs.

$vcenter = “
$vcu = “administrator@vsphere.local”
$vcp = “password”

Connect-VIServer  $vcenter -User $vcu -password $vcp

$vmlist = get-view -viewtype virtualmachine -property ‘name’ -Filter @{‘Runtime.ToolsInstallerMounted’=’True’}
$report = @()
foreach ($vm in $vmlist) {
#unmount command

#add to report with vcenter
$row = “” | select name,vcenter
$ = $
$row.vcenter = $vcenter
$report += $row

Disconnect-VIServer -confirm:$false

Here is a quick line of code you can throw in to your existing scripts if you want to do some validation based on the type of vcenter.
As more companies are moving to the vCenter appliance, MS Windows issues go away.   Until that time, it’s good to alert on disk space and CPU usage for the Windows vCenter.

The quick one-liner to check the vCenter OS:
if(($global:DefaultVIServer | %{$_.extensiondata.content.about.ostype}) -match “win”){ $windows}else{$Linux}

Here is a Windows vCenter “CPU and Disk space” check script:

$vcenter = “”
$localWindowsAccountUser = “user001”
$localWindowsAccountPass = “test”
## if you want to use a domain account then edit the “$pcstring” var below

Connect-VIServer $vcenter

if(($global:DefaultVIServer | %{$_.extensiondata.content.about.ostype}) -match “win”){
$pcstring = $vcenter+”\”+$localWindowsAccountUser
$Credential = New-Object -TypeName System.Management.Automation.PSCredential -ArgumentList $pcstring,(ConvertTo-SecureString -String $localWindowsAccountPass -AsPlainText -Force)
$temp = get-WmiObject win32_logicaldisk -Computername $vcenter -credential $Credential
foreach($b in ($temp | where {$_.drivetype -eq “3”})){
$reportrow = “” | select VMname, DriveLetter, VolumeName,CapacityGB, FreespaceGB,percentFree
$reportrow.vmname = $vcenter
$reportrow.driveletter = $b.DeviceID
$reportrow.VolumeName = $b.VolumeName
$reportrow.capacityGB = “{0:N3}” -f ($b.Size / 1073741824)
$reportrow.freespaceGB = “{0:N3}” -f ($b.FreeSpace / 1073741824)
$reportrow.percentfree = [System.Math]::floor(($b.FreeSpace / $b.Size)*100)
$report += $reportrow
$cpucheck = get-WmiObject win32_processor  -Computername $vcenter -credential $Credential | Measure-Object -property LoadPercentage -Average | Select Average
if(([int]($cpucheck.average)) -ge 90){
$smtpServer = “”
$msg = new-object Net.Mail.MailMessage
$smtp = new-object Net.Mail.SmtpClient($smtpServer)
$msg.From = “”
$sub = “vCenter HIGH CPU usage found for “+$vcenter
$msg.subject = $sub
$msg.Body = “”
Disconnect-VIServer -Server $global:DefaultVIServers -Force -confirm:$False

First: Thank you Mick Short for the idea.  When we think about adding vCPUs to a VM, we instantly think of the default, “adding sockets” and leaving core set to one.  This is “best practice” if you ask VMware and it allows DRS to make automatic decisions for CPU scheduling.

Unfortunately, software companies like to create weird licenses based on socket vs core of a server. Thus, comes the requirement of assigning more cores to our VM instead of sockets.

Here is a quick method to use to make this happen:  (VM has two sockets, three cores for six total vCPUs.)
$VMname= get-vm “VM1”

$spec=New-Object –Type VMware.Vim.VirtualMAchineConfigSpec –Property @{“NumCoresPerSocket” = $cores}
$VMname | set-vm -numcpu $TotalvCPU


Next step is getting Set-VM updated to support Socket and Core values.

After reviewing this Blog and KBs from VMware, it appears that security wins again.   VMware plans to disable Transparent Page Sharing (TPS) in all future releases.
*The above blog has a great GUI if you like GUIs.  Below I will post some simple Powershell code if you like exporting to Excel etc.  Quick note to Mark: Thank you for the script idea!  Check out my Plink command below so you can reduce your SSH sessions in half.  I also made some powershell commands so we don’t need to export and import text files.  This script was able to scan over 500 ESXi hosts across seven vcenters in under seven minutes.

What this script does:
1 – Pulls all hosts in your vcenter and collects the name, clusterMoRef, and if its in lock down mode
2 – Pulls all clusters in your vcenter and collects the name, MoRef, and total memory allocated in the cluster.
3 – It then uses Plink.exe to SSH into every ESX host (that is not in lockdown mode) and run two commands.
4 – It returns those commands into a fancy report that can be exported to CSV.

From there, you can make some fancy calculations between total cluster memory and TPS savings.  What I did was group all hosts by cluster, add up all of the “Free memory” reported by each host, then check if that number was smaller than the amount saved from TPS.
Thus :  if (Free Mem < TPS saved) then {bad news}


#edit the following four vars – then paste the code below it
###### The Vars:
cd e:\plink
$PuttyUser = “root”
$PuttyPwd = “salsa”
$avcenter = “MyvCenter”

#####  The Code:
$Plink = “./plink.exe”
$cmd1 = ‘vsish -e get /memory/comprehensive‘
$cmd2 = ‘vsish -e get /memory/pshare/stats‘
$RCommand = ‘”‘ + $cmd1 + ‘ & ‘+ $cmd2 + ‘”‘
$report = @()
$clusterReport = @()
Add-PSSnapin VMware.*
connect-viserver $avcenter -User “administrator@vsphere.local” -password “salsa”
$hostlist = get-view -viewtype hostsystem -property name,Parent,config | select name,parent -expandproperty config | where {$_.admindisabled -ne $true} | select name,parent
$allclusters = get-view -viewtype ClusterComputeResource -property name,summary | select name,moref -expandproperty summary | select name,moref,totalmemory
$clusterReport += $allclusters
foreach($hostname in ${
echo Y | ./plink.exe -l $PuttyUser -pw $PuttyPwd $hostname exit
$command = $Plink + ” -v -batch -pw ” + “`””+$PuttyPwd + ”`” -l ” + $PuttyUser + “ ” + $hostname + ” ” + $RCommand
$data1 = “”
$data1 = Invoke-Expression -command $command
$VMKernelMem = ((($data1 | where {$_ -match “Given to VMKernel”}).split(‘:’)[1]) -replace ‘kb’) / 1048576
$FreeMem = ((($data1 | where {$_ -match “Free:”}).split(‘:’)[1]) -replace ‘kb’) / 1048576
$Pageshared = ($data1 | where {$_ -match “psharing”}).split(‘:’)[1]
$PageZero = ($data1 | where {$_ -match “zero-pages”}).split(‘:’)[1]
if($pageshared -gt 0){$Pageshared=[math]::Round((([int]$Pageshared*4)/1048576),2)}
if($pageZero -gt 0){$pageZero=[math]::Round((([int]$Pagezero*4)/1048576),2)}
$row = “” | select vcenter,cluster,hostname,VMKernelMemGB,FreeMemGB,PagesharedGB,PageZeroGB
$row.vcenter = $avcenter
$row.cluster = ($allclusters | where {$_.moref.value -match ($hostlist | where {$ -match $hostname} | %{$_.parent.value})}).name
$row.hostname = $hostname
$row.VMKernelMemGB = $VMKernelMem
$row.FreeMemGB = $FreeMem
$row.PagesharedGB = $Pageshared
$row.PageZeroGB = $PageZero
$report += $row
Disconnect-viserver -confirm:$False
$report | export-csv c:\temp\TPSHostdata.csv
$clusterReport | select name,totalmemory | export-csv c:\temp\TPSClusterData.csv

#The following is a good starting template if you have a software suite that uses web based rest APIs.
#** Note,  using Powershell version 4 is highly recommended if the API requires HTTPS and/or uses Self Signed Certs.
# Be sure to edit the user,password and URL below.

# This single line helps get around Cert issues that can prevent you from connecting to the server.  Only use this line if you have connectivity or SSL issues.
[System.Net.ServicePointManager]::ServerCertificateValidationCallback = { $true }

#The Vars and code:
$User = “testUsername”
$PWord = ConvertTo-SecureString –String “testPassword” –AsPlainText -Force
$Cred = New-Object –TypeName System.Management.Automation.PSCredential –ArgumentList $User, $PWord

$wc = New-Object System.Net.WebClient
$wc.Headers.Add(“Authorization”, “Basic $( [System.Convert]::ToBase64String([System.Text.Encoding]::UTF8.GetBytes(“$($Cred.UserName.TrimStart(‘\’)):$($Cred.GetNetworkCredential().Password)”)) )”)
$temp = $wc.DownloadString(“”)

#From here you can use the $temp var to dig further into the API and then format what output you want.   You can review one of my older posts if you need help creating a report for easy exporting. If the API posts back something usable you can just use one of the many powershell Export- functions.

This Script will clone an existing vDS and its port groups.  **with new UUIDs**
This is great if you get a corrupted vDS and need to migrate away from it.
Or, if you want to recreate a new vDS in the image of an old one without using the export/import method.

** quick notes:
– This creates a new distributed switch and port groups with new IDs.  This isn’t good to use as an Export/Import when migrating hosts and VMs to a new vCenter.
– This script does not keep special Security Policies but its very easy to add it to the script. I left all of the vars complete so you can pull and assign the extension data for additional needs.
– This code pulls an old vDS and its port groups, then recreates a new one using a “-2” at the end of the names.  At the very end of the script, it then removes the “-2” from the names.   Keep this in mind if you have “-2” in the name of your vDS or port groups.  If you do use this “-2” string in your existing names, change it in the script to something like “QQQQ” so you can remove the trailing text at the end without impacting your existing names.

## Set your old vDS name and paste the rest.

Add-PSSnapin VMware.*
$oldVDSName = “dvs-MyvDS”

#Grab the old vDS info
$oldvDS = get-VDSwitch $oldVDSName

#Create the new one and rename its uplink
$newvDS = new-vdswitch -name ($”-2″) -location $ -NumUplinkPorts $oldvDS.NumUplinkPorts -mtu $oldvDS.Mtu
$oldUpLink = $oldvDS | get-vdportgroup | where {$_.IsUplink -eq “True”}
$newvDS | get-vdportgroup | where {$_.IsUplink -eq “True”}  | set-vdportgroup -name ($”-2″) -vlantrunkRange $oldUpLink.VlanConfiguration

#Pull the old vDS port groups and recreate them on the new vDS
$Portgroups = $oldvDS | get-vdportgroup | ?{$_.IsUplink -ne “True”}
foreach($port in $portgroups){
$Pname = $ + “-2”
$PVlanid = $port.VlanConfiguration.vlanid
$pNumPorts = $port.numports
$newvDS | New-VDPortgroup -Name $Pname -Vlanid $PVlanid -numports $pNumPorts
$newvDS | New-VDPortgroup -Name $Pname -numports $pNumPorts

#Here you can migrate ESXi Host links and VMs from your old vDS to your new vDS.
#If you want to migrate to the new vDS, you can get some code help here :
#If you copied the vDS to the same vCenter, keep in mind that vDS names and vDS Port group names are vcenter unique.
#You will need to delete your old vDS or rename it to remove the “-2” from the new one.

#Remove the old vDS if you no longer need it – Do this Manual so you can verify that everything has migrated…
#$oldvDS | remove-vdswitch -confirm:$False

#rename the new vDS and its port groups to match the orginal.
$newvDS | set-vdSwitch -name ($ -replace “-2″,””)
$Portgroups = $newvDS | get-vdportgroup

foreach($port in $portgroups){
$port | set-vdportgroup -name ($ -replace “-2″,””)


#Here is some extra code to set the Teaming Load Balancing policy for all port groups on your new vDS. This is configured to set all port groups to “Route based on Physical NIC load”
#Change the port group load policy to Load based
$newvDSPortgroups = get-VDSwitch $newVDS | get-vdportgroup
Function Set-VDPortGroupTeamingPolicy {
param (

Process {
$spec = New-Object VMware.Vim.DVPortgroupConfigSpec
$spec.configVersion = $VDPortgroup.ExtensionData.Config.ConfigVersion
$spec.defaultPortConfig = New-Object VMware.Vim.VMwareDVSPortSetting
$spec.defaultPortConfig.uplinkTeamingPolicy = New-Object VMware.Vim.VmwareUplinkPortTeamingPolicy
$spec.defaultPortConfig.uplinkTeamingPolicy.inherited = $false
$spec.defaultPortConfig.uplinkTeamingPolicy.policy = New-Object VMware.Vim.StringPolicy
$spec.defaultPortConfig.uplinkTeamingPolicy.policy.inherited = $false
$spec.defaultPortConfig.uplinkTeamingPolicy.policy.value = “loadbalance_loadbased”

foreach($port in $newvDSPortgroups){
$port| Set-VDPortgroupTeamingPolicy


Quick Report script to find those VMs that span more than one Numa Boundary.
Meaning:  If your ESX host has two – quad core CPUs and your VM is configured for six vCPUs,  then your VMs is spanning two NUMA boundaries.
Also, if your VM is configured with 32GB of memory but you only have 24GB of ram Per CPU Socket, your VM will cross memory NUMA boundaries!

Add-PSSnapin VMware.*


$temp = get-view -viewtype virtualmachine -property name,,config.hardware
$temphost = get-view -viewtype hostsystem -property name,hardware.cpuinfo,hardware.MemorySize
foreach($a in $temp){
$row = “” | select VMname,VMTotalvCPUs,VMSockets,VMCores,CPUCalcNumaNodes,MemCalcNumaNodes
$row.VMname = $
$row.VMTotalvCPUs = $a.config.hardware.numcpu
$row.VMsockets = ($a.config.hardware.numcpu)/($a.config.hardware.NumCoresPerSocket)
$row.VMcores = $a.config.hardware.NumCoresPerSocket
$t = $temphost | where {$_.moref -eq $}
$nodesCalc = try{[system.math]::ceiling($a.config.hardware.numcpu /($t.hardware.cpuinfo.numcpucores / $t.hardware.cpuinfo.NumCpuPackages))}catch{}
$row.CpuCalcNumaNodes = if($nodesCalc -gt $t.hardware.cpuinfo.NumCpuPackages){$t.hardware.cpuinfo.NumCpuPackages}else{$nodesCalc}
$nodesCalc = if(((($t.hardware.memorysize)/1048576)/$t.hardware.cpuinfo.NumCpuPackages) -lt ($a.config.hardware.MemoryMB)){$nodescalc + 1}else{$nodescalc}
$row.MemCalcNumaNodes = if($nodesCalc -gt $t.hardware.cpuinfo.NumCpuPackages){$t.hardware.cpuinfo.NumCpuPackages}else{$nodesCalc}
$report += $row

### format the below output as needed.  It currently reports any VMs that span across more than one NUMA boundary.
$report | where {($_.CPUCalcNumaNodes -ge 2) -or ($_.MemCalcNumaNodes -ge 2)} | ft




Some Quick One-Liners to help with Day to Day changes.  Copy and Adapt as needed.

Quick Notes***
Ram and HardDisk Capacity numbers are in GB.   The bottom code to increase a VMs existing HardDisk has a WMI call to get the Drive letters (For Windows VMs).  This will help match Hard Disk to Drive letter before you issue the last command to expand it.

####### Edit your VM name here #######
$theVM = get-vm “MySuperCoolVM”

######Increase vCPU#######
$thevm | set-vm -numcpu “3” -confirm:$false

#######Increase RAM#######
$thevm | set-vm -memoryGB “8” -confirm:$false

#######Rename to old_X and move to old folder
$thevm | set-vm -name (“old_”+($ -confirm:$false
$thevm | move-vm -destination (get-folder “old”)

#######add new Drive to VM#######
$thevm |new-harddisk -capacityGB “50”

#######increase drive on VM#######
$thevm | get-harddisk | select name,capacityGB,filename

$report = @()
$temp = get-WmiObject win32_logicaldisk -Computername ($
foreach($b in ($temp | where {$_.drivetype -eq “3”})){
$reportrow = “” | select VMname, DriveLetter, VolumeName,CapacityGB, FreespaceGB,percentFree
$reportrow.vmname = $
$reportrow.driveletter = $b.DeviceID
$reportrow.VolumeName = $b.VolumeName
$reportrow.capacityGB = “{0:N3}” -f ($b.Size / 1073741824)
$reportrow.freespaceGB = “{0:N3}” -f ($b.FreeSpace / 1073741824)
$reportrow.percentfree = [System.Math]::floor(($b.FreeSpace / $b.Size)*100)
$report += $reportrow

$report | ft

$thevm | get-harddisk | where {$ -eq “Hard disk 3”} | set-harddisk -capacityGB “50” -confirm:$false


#Upgrading a cluster from 5.1 to 5.5 or even updating past the Heart Bleed and need a quick double check that all of the host got the new build?
#I throw this at the entire vcenter but you can narrow it down to per datacenter or cluster if you like…

### Here is the quick (cluster only) code…

$Report = @()
get-cluster myCluster | get-vmhost | %{
$vmhost = Get-View $_.ID
$ReportRow = “” | Select-Object Hostname, build
$ReportRow.Hostname = $vmhost.Name
$ReportRow.Build = $
$Report += $ReportRow
$report | FT


### If you want to be more fancy, here is a multi vCenter scan… (check ALL the hosts!)

Add-PSSnapin VMware.VimAutomation.Core

$vcenters = @()
$vcenters += “vcenter1”
$vcenters += “vcenter2”
$vcenters += “vcenter3”

$Report = @()
foreach($vcenter in $vcenters){
Connect-VIServer $vcenter

$clusters = get-cluster
foreach($a in $clusters){
$a | get-vmhost | %{
$vmhost = Get-View $_.ID
$ReportRow = “” | Select-Object vcenter,cluster,Hostname, build
$ReportRow.vcenter = $vcenter
$ReportRow.cluster = $
$ReportRow.Hostname = $vmhost.Name
$ReportRow.Build = $
$Report += $ReportRow
Disconnect-viserver -confirm:$False
$report | FT