ESXi ships with SSH stopped and set to start manually, which is the right default and a nuisance the one week you need a shell on every host in a cluster. PowerCLI can enable SSH across the whole cluster in a single pipeline, set it to come back after a reboot, and silence the warning banner vCenter raises about it.
Everything below runs from a PowerCLI session connected to vCenter (Connect-VIServer vcenter.example.com).
Check the current state first
Get-VMHost | Get-VMHostService | Where { $_.Key -eq "TSM-SSH" } | select VMHost, Label, Running
VMHost Label Running
------ ----- -------
esxi-02.domain.local SSH False
esxi-10.domain.local SSH False
esxi-06.domain.local SSH False
esxi-01.domain.local SSH False
esxi-05.domain.local SSH True
esxi-07.domain.local SSH False
esxi-03.domain.local SSH False
esxi-04.domain.local SSH False
esxi-08.domain.local SSH False
esxi-09.domain.local SSH False
TSM-SSH is the service key for SSH; TSM on its own is the ESXi Shell, which is a different thing and not what you want here. Run this before and after, and keep the "before" output — it tells you which hosts already had SSH running, and those are the ones you must not switch off again at the end. Add Policy to the select if you intend to use the rollback below: it resets the policy on every host it touches, including a management host that was deliberately set to on long before you arrived.
PowerCLI serves this from cached host data, so when you re-run it add -Refresh — Get-VMHost | Get-VMHostService -Refresh | Where { $_.Key -eq "TSM-SSH" } — or you can see a stale False on a host where SSH is already up.
Enable SSH on every host
Get-VMHost | Foreach {Start-VMHostService -HostService ($_ | Get-VMHostService | Where { $_.Key -eq "TSM-SSH"} )}
Key Label Policy Running Required
--- ----- ------ ------- --------
TSM-SSH SSH off True False
TSM-SSH SSH off True False
The output repeats once per host, trimmed here to two rows. Note Policy is still off — the service is running now, and will be stopped again at the next host reboot. If that is all you wanted, stop here: it is the safer state to leave behind.
Make it survive a reboot
Get-VMHost | get-vmhostservice | where-object {$_.key -eq "TSM-SSH"} | set-vmhostservice -policy "On"
Key Label Policy Running Required
--- ----- ------ ------- --------
TSM-SSH SSH on True False
TSM-SSH SSH on True False
On means start and stop with the host. The other values are Off (manual) and Automatic, which starts the service if any of its ports are open in the firewall and stops it when they are all closed. On a default host the sshServer ruleset is already open, so Automatic behaves much like On — but on a hardened host where that ruleset was disabled the service will not come up, and it will go down again the moment someone closes the rule. On is the value that does what the heading says.
Suppress the shell warning
Get-VMHost | Get-AdvancedSetting -Name UserVars.SuppressShellWarning | Set-AdvancedSetting -Value 1 -Confirm:$false
Name Value Type Description
---- ----- ---- -----------
UserVars.Suppress... 1 VMHost
UserVars.Suppress... 1 VMHost
This is the setting behind the yellow "SSH for the host has been enabled" banner in vCenter (Broadcom KB 367599 describes it). It is worth being honest about what you are doing: the banner is not a bug, it is the only visible reminder that a management interface is open. Silencing it fleet-wide means nobody will notice next quarter that SSH is still on.
Scope it to one cluster
Get-VMHost with no argument hits every host in the connected vCenter, which is rarely what you want when you only meant to enable SSH on one cluster. Pipe from the cluster instead:
Get-Cluster "Cluster-01" | Get-VMHost | Get-VMHostService | Where { $_.Key -eq "TSM-SSH" } | select VMHost, Running
The same shape works for the other three commands — put Get-Cluster "..." | in front of each.
Undo it when you are done
Get-Cluster "Cluster-01" | Get-VMHost | Foreach {Stop-VMHostService -HostService ($_ | Get-VMHostService | Where { $_.Key -eq "TSM-SSH"} ) -Confirm:$false}
Get-Cluster "Cluster-01" | Get-VMHost | Get-VMHostService | Where {$_.Key -eq "TSM-SSH"} | Set-VMHostService -Policy "Off"
Get-Cluster "Cluster-01" | Get-VMHost | Get-AdvancedSetting -Name UserVars.SuppressShellWarning | Set-AdvancedSetting -Value 0 -Confirm:$false
Leave out the hosts that had SSH running before you started — that is what the first output was for. If you need this open permanently on a management cluster, that is a decision worth writing down somewhere, not a side effect of a troubleshooting session that nobody closed.
Verify before you rely on it
Re-run the check with -Refresh and confirm every host reports Running True and Policy on. If one is missing it was probably disconnected or in maintenance mode when the pipeline ran — Get-VMHost | where ConnectionState -ne "Connected" finds it, and you enable SSH on that one by hand afterwards.
The same Get-Cluster | Get-VMHost shape drives other fleet-wide changes, such as modifying an advanced setting on every host at once.