Oct 172017

The folks on the VMware API team along with some Community Support ( <a href=”https://twitter.com/butch7903″ target=”_blank”>@butch7903</a> – Russell Hamker)
have created an amazing backup script for your vCenter Appliance.  Give it a once over.
<a href=”https://github.com/butch7903/PowerCLI/blob/master/Backup_VCSA_DB_to_File.ps1″ title=”Backup VCSA To Flat File – Github” target=”_blank”>https://github.com/butch7903/PowerCLI/blob/master/Backup_VCSA_DB_to_File.ps1</a>

Some quick notes:
- Only works on vSphere 6.5 and higher.
- It requires PowerCLI version 6.5.3 or greater.
- It needs the Powershell PSFTP or WinSCP Powershell module if you want to use FTP or WinSCP to copy the backup from vCenter to a storage location.
* (Optional) – I deployed a Photon OS VM and I use that as my SCP target to save my backups.

If you want to save all of the Command Line GUI in the 772 Line file, all you need are these lines to complete the backup.
Import-Module -Name VMware.VimAutomation.core
Import-Module -Name WinSCP
connect-cisserver “vcenter01″ -username “administrator@vsphere.local” -pass “myPass”
$BackupAPI = Get-CisService com.vmware.appliance.recovery.backup.job
$CreateSpec = $BackupAPI.Help.create.piece.Create()
$CreateSpec.parts = @(“common”,”seat”)
$CreateSpec.backup_password = “”
$CreateSpec.location_type = “SCP”
$CreateSpec.location = “”
$CreateSpec.location_user = “root” #username of your SCP location
$CreateSpec.location_password = New-Object –TypeName System.Management.Automation.PSCredential –ArgumentList “backup location username”, (ConvertTo-SecureString –String “backup location password” –AsPlainText -Force)
$CreateSpec.comment = $Comment
$BackupJob = $BackupAPI.create($CreateSpec)

Then you can use the following command to check on its status:
$BackupJob | select id, progress, state

Sep 222017

#This script is a Generic Host Profile that could be applied to an ESXi host after it is newly built from ISO or from a base build.  The configurations are for reference. Most commands are not required but do conform to most configuration baselines suggested in Performance and third party documents.  The commands do not require the host to be in Maintenance Mode to complete but some commands could cause an outage if not executed correctly.  Some commands below may require some additional changes, (editing the IP Address or vmnic numbers.)  Please review the commands before running against your Production hosts.

### Set the Vars
$myhost = “esx01.pcli.me”
$myDomain = “pcli.me”
$myDNSServer1 = “″
$myDNSServer2 = “″
$myNTPServer = “ntp.pcli.me”
$mySyslogServer = “loginsight.pcli.me”

$vmotionIP1 = “″
$vmotionIP2 = “″
$vmotionSubnetMask = “″
$vmotionVlanID = “0″

$myVDSwitch = “dvs-pcliCore”
$myVDSSwitchNICs = “vmnic6″,”vmnic7″,”vmnic8″,”vmnic9″

### Run the commands…
##Set the domain
get-vmhostnetwork -VMHost $myhost | set-vmhostnetwork -searchdomain $yourDomain -domain $yourDomain -DnsAddress @($myDNSServer1,$myDNSServer2)

##Set the NTP server and restart the service.
if(get-vmhostntpserver -vmhost $myhost){remove-vmhostntpserver -host $myhost -ntpserver (get-vmhostntpserver -vmhost $myhost) -confirm:$false}
add-vmhostntpserver -vmhost $myhost -ntpserver @($myNTPServer)
Get-VmHostService -VMHost $myhost | Where-Object {$_.key -eq “ntpd”} | Set-VMHostService -Policy “on” -Confirm:$false
Get-VmHostService -VMHost $myhost | Where-Object {$_.key -eq “ntpd”} | ReStart-VMHostService -confirm:$false

##Set the syslog server and open the firewall
set-VMHostAdvancedConfiguration -VMHost $myhost -Name “Syslog.global.logHost” -Value $mySyslogServer -confirm:$false
Get-VMHostFirewallException -name ‘syslog’ -vmhost $myhost | Set-VMHostFirewallException -Enabled:$true

##Enable SSH, restart service and set session vars to meet Security Requirements
Get-VmHostService -VMHost $myhost  | Where-Object {$_.key -eq “TSM-SSH”} | Set-VMHostService -Policy “on” -Confirm:$false
Get-VmHostService -VMHost $myhost  | Where-Object {$_.key -eq “TSM-SSH”} | ReStart-VMHostService -confirm:$false
set-VMHostAdvancedConfiguration -VMHost $myhost  -Name “UserVars.SuppressShellWarning” -Value “1″ -confirm:$false
set-VMHostAdvancedConfiguration -VMHost $myhost  -Name “UserVars.ESXiShellTimeOut” -Value “900″ -confirm:$false
set-VMHostAdvancedConfiguration -VMHost $myhost  -Name “UserVars.ESXiShellInteractiveTimeOut” -Value “900″ -confirm:$false
set-VMHostAdvancedConfiguration -VMHost $myhost  -Name “Security.AccountLockFailures” -Value “5″ -confirm:$false

##Rename the local datastore to “hostname-local”
$localDS = “”+(($myhost).split(“.”))[0]+”-local”
if(get-vmhost $myhost |get-datastore | where {$_.name -match “datastore”}){get-vmhost $myhost | get-datastore | where {$_.name -match “datastore”} | set-datastore -name $localDS}

##Create a new standard switch for vmotion, add two physical nics, set the security policy, then create two vmotion vmknics
#### ** BE SURE to edit the VMNIC numbers below (vmnic2 and vmnic3) to match your physical nic numbers.
#### ** If you want to combine vmotion vmknics on the management vSwitch (vSwitch0) skip to the code below this.
$thevmotionswitch = new-virtualswitch -vmhost $myhost -name “vSwitchVMotion” -mtu 9000 -nic “vmnic2″,”vmnic3″
$esx=get-vmhost $myhost
$esxid=$esx |% {get-view $_.Id}
$esxnsview=get-view $esxns
$esxvSwitch=$esxnsview.NetworkConfig.Vswitch | where {$_.Name -eq $thevmotionswitch}
$specChange= $esxvSwitch.Spec
new-VirtualPortGroup -virtualswitch $thevmotionswitch -name vmotion0 -vlanid $vmotionVlanID
New-VMHostNetworkAdapter -VMHost $myhost -PortGroup vmotion0 -VirtualSwitch $thevmotionswitch  -IP $vmotionIP1 -SubnetMask $vmotionSubnetMask -VMotionEnabled:$true
$vnicchange = get-virtualswitch -vmhost $myhost -name $thevmotionswitch | Get-virtualportgroup -name “vmotion0″ | get-nicteamingPolicy
$vnicchange | Set-NicTeamingPolicy -MakeNicActive “vmnic3″ -MakeNicStandby “vmnic2″
new-VirtualPortGroup -virtualswitch $thevmotionswitch -name vmotion1 -vlanid $vmotionVlanID
New-VMHostNetworkAdapter -VMHost $myhost -PortGroup vmotion1 -VirtualSwitch $thevmotionswitch  -IP $vmotionIP2 -SubnetMask $vmotionSubnetMask -VMotionEnabled:$true
$vnicchange | Set-NicTeamingPolicy -MakeNicActive “vmnic2″ -MakeNicStandby “vmnic3″
$vnicchange = get-virtualswitch -vmhost $myhost -name $thevmotionswitch | Get-virtualportgroup -name “vmotion1″ | get-nicteamingPolicy

##**** If you want to run vmotion on your management switch (vSwitch0) use this code instead.
##** Again, edit the vmnic numbers below as needed.
$thevmotionswitch = get-virtualswitch -vmhost $myhost -name “vSwitch0″
new-VirtualPortGroup -virtualswitch $thevmotionswitch -name vmotion0 -vlanid $vmotionVlanID
New-VMHostNetworkAdapter -VMHost $myhost -PortGroup vmotion0 -VirtualSwitch $thevmotionswitch  -IP $vmotionIP1 -SubnetMask $vmotionSubnetMask -VMotionEnabled:$true
$vnicchange = get-virtualswitch -vmhost $myhost -name $thevmotionswitch | Get-virtualportgroup -name “vmotion0″ | get-nicteamingPolicy
$vnicchange | Set-NicTeamingPolicy -MakeNicActive “vmnic0″ -MakeNicStandby “vmnic1″
new-VirtualPortGroup -virtualswitch $thevmotionswitch -name vmotion1 -vlanid $vmotionVlanID
New-VMHostNetworkAdapter -VMHost $myhost -PortGroup vmotion1 -VirtualSwitch $thevmotionswitch  -IP $vmotionIP2 -SubnetMask $vmotionSubnetMask -VMotionEnabled:$true
$vnicchange = get-virtualswitch -vmhost $myhost -name $thevmotionswitch | Get-virtualportgroup -name “vmotion1″ | get-nicteamingPolicy
$vnicchange | Set-NicTeamingPolicy -MakeNicActive “vmnic1″ -MakeNicStandby “vmnic0″

##Add the host to a vDS then add its Physcial NICs to the switch
Add-VDSwitchVMHost -vdswitch $myVDSwitch -vmhost $myhost
$hostadapter = get-vmhost -name $myhost | Get-vmhostnetworkadapter -physical -name $myVDSSwitchNICs
get-vdswitch $myVDSwitch  | add-vdswitchphysicalnetworkadapter -vmhostnetworkadapter $hostadapter -confirm:$false

##Create a portgroup on an existing Standard Switch
$vswitch0 = get-virtualswitch -vmhost $myhost -name “vSwitch0″
new-VirtualPortGroup -virtualswitch $vswitch0 -name “″

##Set the host Power Policy to “High Performance” to reduce cpu latency.
$view = (Get-VMHost $myhost | Get-View)
(Get-View $view.ConfigManager.PowerSystem).ConfigurePowerPolicy(1)

##Move the local datastore into a datastore folder named “localdisk”  Folder must exist.
get-vmhost $myhost | get-datastore | where {$_.name -match “-local”} | move-datastore -destination (get-folder “localdisk”)

##Make sure both physical adapters on your management switch (vSwitch0) are set to active,active to prevent an outage.
$theManagementSwitch = get-virtualswitch -vmhost $myhost -name “vSwitch0″
$thenics = get-virtualswitch -vmhost $myhost -name $theManagementSwitch | Get-vmhostnetworkadapter | where {$_.name -notmatch “vmk”}
$vnicchange = get-virtualswitch -vmhost $myhost -name $theManagementSwitch | Get-virtualportgroup -name “Management Network” | get-nicteamingPolicy
$vnicchange | Set-NicTeamingPolicy -MakeNicActive $thenics

##If you use NFS storage, set the host NFS Advanced Vars to NFS Storage Vender Specs:
$Cmyhost = Get-VMHost $myhost
$Cmyhost | get-advancedsetting -name VMFS3.hardwareacceleratedlocking | set-advancedsetting -Value 1 -confirm:$false
$Cmyhost | get-advancedsetting -name Net.TcpipHeapSize | set-advancedsetting -Value 32 -confirm:$false
$Cmyhost | get-advancedsetting -name Net.TcpipHeapMax  | set-advancedsetting -Value 1536 -confirm:$false
$Cmyhost | get-advancedsetting -name NFS.MaxVolumes  | set-advancedsetting -Value 256 -confirm:$false
$Cmyhost | get-advancedsetting -name NFS41.MaxVolumes  | set-advancedsetting -Value 256 -confirm:$false
$Cmyhost | get-advancedsetting -name NFS.MaxQueueDepth  | set-advancedsetting -Value 64 -confirm:$false
$Cmyhost | get-advancedsetting -name NFS.HeartbeatMaxFailures  | set-advancedsetting -Value 10 -confirm:$false
$Cmyhost | get-advancedsetting -name NFS.HeartbeatFrequency  | set-advancedsetting -Value 12 -confirm:$false
$Cmyhost | get-advancedsetting -name NFS.HeartbeatTimeout  | set-advancedsetting -Value 5 -confirm:$false

##If you need to add a vmknic for NFS traffic on a Virtual Distributed Switch:
$theswitch = get-vdswitch “myNFSVDSwitch”
$thePG = $theswitch | get-vdportgroup | where {$_.name -match “”}
New-VMHostNetworkAdapter -VMHost (Get-VMHost $myhost) -virtualswitch $theswitch -PortGroup $thePG -IP “″ -SubnetMask “″

##Mount up some NFS vols
Get-VMHost $myhost| New-Datastore -Nfs -Name “MyNFSDevice” -Path “/NFSShare1/MyNFSShare” -NfsHost “″


#Here is the PowerCLI 6.5 Command Reference to look up these commands.

Mar 082017

Here is a quick one-liner that will list your VM names and their Environment Tag.
- The assumption here is you use vCenter Tags, you created a tag category for Environment, created some tag types (like Production, Dev, etc) under that category, and assigned those Tags to your VMs.

$Thecategory = “Environment”
$thecluster = “TheCoolKidsCluster”
get-cluster $thecluster | Get-VM | Select Name,@{N=”Tag”;E={((Get-TagAssignment -category $Thecategory -Entity $_ | select -ExpandProperty Tag).Name -join “,”)}}

#The output can be sent to csv with  “|export-csv c:\temp\export.csv”
#The output looks like this:
VM1 Production
VM2 Development
VM3 Production…..
… etc

# Remember – you can change the get-cluster part to get-folder, get-datastore, get-datastorecluster, even a get-VDPortgroup!



Oct 312016

#A quick grep of all VMs in a vcenter, with the configured and running OS (detected by a valid version of VMware tools installed)
#This is a great report if you find out some Admins were running “upgrades” from windows 2008 to 2012 and never reconfigured the VM OS setting.


$temp = get-view -viewtype “virtualmachine” -property name,guest.ToolsRunningStatus,guest.guestfullname,config.guestfullname
$OSMisconfiguredReport = @()
foreach($a in $temp){
$row = “” | select name,toolsstate,OSConfigured, OSRunning
$row.name = $a.name
$row.toolsstate = $a.guest.ToolsRunningStatus
$row.OSConfigured = $a.config.guestfullname
$row.OSRunning = $a.guest.guestfullname
$OSMisconfiguredReport += $row

$OSMisconfiguredReport | where {$_.toolsstate -eq “guestToolsRunning” -and $_.osrunning -notlike “” -and $_.osconfigured -ne $_.osrunning}


Oct 312016

Quick One-liner to look for any VM in your entire vcenter that has the VMware tools installer mounted.

get-view -viewtype virtualmachine -property ‘name’ -Filter @{‘Runtime.ToolsInstallerMounted’=’True’}


#Here is the same command but with the additional text to unmount the installer if any are found.

get-view -viewtype virtualmachine -property ‘name’ -Filter @{‘Runtime.ToolsInstallerMounted’=’True’} | foreach{$_.UnmountToolsInstaller()}




May 242016

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 “my.vcenter.me -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 = “my.vcenter.me
$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.name = $vm.name
$row.vcenter = $vcenter
$report += $row

Disconnect-VIServer -confirm:$false

Jun 022015

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 = “vcenter.pcli.me”
$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 = “smtp.pcli.me”
$msg = new-object Net.Mail.MailMessage
$smtp = new-object Net.Mail.SmtpClient($smtpServer)
$msg.From = “Script@pcli.me”
$sub = “vCenter HIGH CPU usage found for “+$vcenter
$msg.subject = $sub
$msg.Body = “”
Disconnect-VIServer -Server $global:DefaultVIServers -Force -confirm:$False

May 282015

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.

Jan 282015

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 $hostlist.name){
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 {$_.name -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