No Theory Here: Adding ESXi Hosts to a Windows Domain

Here we go, round two for #Blogtober2018 – Tech Edition. The tricky thing about writing technical content for a blog is that most likely it has already been covered and covered in better detail. Today’s post is no different, so I’m going to post some links to great guides that go in depth on how to join an ESXi host to a domain. So if you want more detail or really want to know the “why” and “how”, check these out:

https://kb.vmware.com/s/article/2075361

https://www.altaro.com/vmware/how-to-join-esxi-to-active-directory-for-improved-management-and-security/

http://vcloud-lab.com/entries/esxi-installation-and-configuration/join-domain-esxi-to-an-active-directory-ou-powercli

But my goal in today’s post is function over depth. No theory, only practical application. I’m going to provide a script I wrote to join all the hosts in a specific cluster to my domain., focusing on providing something that quickly gets the job done, while avoiding theory if possible.

Part One: The Setup

There are two main things I needed to do in AD before adding ESXi hosts. First, I needed to create an AD Security group to hold accounts that will be used to log into ESXi. This is the group that users must be a part of to authenticate to the ESXi host once joined to the domain.

New-ADGroup -Name "VMware Admins" -Path "OU="VMware Admins",DC=domain,dc=root" -GroupScope Global -GroupCategory Security

Save the group name; it will be used as an argument for one of the parameters in the script we use.

The second thing I needed to do was get the canonical name where I wanted the newly created host computer accounts to land once it was created. I had previously created the OU, so all I needed now was to get the canonical name and save it:

Get-ADOrganizationalUnit -Filter "Name -eq 'ESXi Hosts OU you want to use'" -Properties canonicalname | Select-Object canonicalname

Same as before, save the canonical name since you will be using it as an argument later.

Finally, ensure the following are true before running the script to avoid any errors later on:

  • Ensure ESXi host and domain controllers share NTP source.
  • ESXi host must have an A record in the domain.
  • Proper firewall ports must be open on ESXi Hosts. If you have a restrictive setup, be sure to check that the appropriate ports are open.
  • Write down the canonical name and security group mentioned above.
  • Be sure to run this with both AD and vCenter permissions.
Part Two: Function Over Form

I used a function and mandatory parameters to help ensure we don’t forget anything. So to break it down:

  1. Connects to vCenter
  2. Loops through each host in cluster joining to domain
  3. Updates ESXi host advanced setting with the AD Security group
  4. Removes .domain.root for the Set-ADComputer cmdlet
  5. Updates AD description with the argument you passed to the $DescriptionUseQuotes parameter
function Set-JSESXiDomainJoin {
[CmdletBinding()]
param (
[Parameter(Mandatory=$true)]
[string]$clusterName,

[Parameter(Mandatory=$true)]
[string]$domainInCanonicalNameFormat,

[Parameter(Mandatory=$true)]
[string]$user,

[Parameter(Mandatory=$true)]
[string]$password,

[Parameter(Mandatory=$true)]
[string]$descriptionUseQuotes,

[Parameter(Mandatory=$true)]
[string]$ADAdminGroup,

[Parameter(Mandatory=$true)]
[string]$VIServer

)
#Does check for required modules
#Requires -Modules ActiveDirectory
#Requires -Version 3
#Requires -Modules VMware.VimAutomation.Core

#Connecting to vCenter
Connect-VIServer -Server $VIServer

#Loop through each host in cluster
foreach ($esxiHost in (Get-Cluster $clusterName | Get-VMHost)){

#Join host to domain
Get-VMHostAuthentication -VMHost $esxiHost | Set-VMHostAuthentication -Domain $domainInCanonicalNameFormat -User $user -Password $password -JoinDomain -Confirm:$false

#Updates advanced settings with AD security group
Get-AdvancedSetting -Entity $esxiHost -Name Config.HostAgent.plugins.hostsvc.esxAdminsGroup | Set-AdvancedSetting -Value $ADAdminGroup -Confirm:$false

#Removes domain name from the host, leaving only hostname.
$esxiHostName = $esxiHost.Name.Split(".")[0]

#Updates description in Active Directory
Set-ADComputer -Identity $esxiHostName -Description $descriptionUseQuotes
}
}
Part Three: Success

It should look something like this when you run it:

 Set-JSESXiDomainJoin -ClusterName "ClusterName" -DomainInCanonicalNameFormat "domain.root/ou/ou" -User "jamey"-Password "secret stuff" -DescriptionUseQuotes "ESXi Host - VMware is the best" -ADAdminGroup "VMware people" -ViServer vcenter.domain.root

Centralize ESXi Core Dumps

In my environment the majority of the hosts boot from SD cards, so persistent log storage is a big deal. I recently ran into a PSOD issue. VMWare requested the coredumps, which of course, I did not have. Thankfully we were able to sort out my issue via the PSOD screenshot I took from the console.

Obviously wanting to avoid this scenario in the future, I set off to find the best way to keep this from happening again. Interestingly, I found an easy way to do this. There is no direct way via GUI or even advanced host settings. Eventually I was able to get it setup. Below is my method. Enjoy.

Setup vCenter

Note: We are running VCSA 6.5 in my environment so the core dump location will be different than if you are using a windows based vCenter server.

First we setup the esxi dump collector on the vCenter server. While logged into the vCenter web interface with an administrator account, click on the Administration link in the vCenter home menu. Next under the Deployment section, click the System Configuration link. From here choose Services under the system configuration header on the left side of the screen. Finally choose “VMware vSphere ESXi Dump Collector.”

From here, click the Manage tab. Then click the pencil icon to change the startup type and set it to run automatically. Next hit the green play button. I can confirm this will not in anyway affect the vCenter server itself, so no worries about affecting production. I kept the defaults for port and size. As noted, if you try to change either of these two settings, it does require a vCenter reboot.

That’s it! Now the vCenter server is ready. Next we need to change the setting on the esxi hosts. I was surprised to find that this must be done at the command line via esxcli. There is no way via advanced settings on the host. The process is straight forward but heavy with administrative overhead. You must ssh to each host and run the following commands. You can also use Host Profiles but that is beyond the scope of this particular post.

Setup ESXi Hosts
### Gets the current coredump configuration ###
esxcli system coredump network get

### Sets server address and port to send kernel dump to ###
### vmk0 is management network in my environment
esxcli system coredump network set -v vmk0 -i vCenter IP -o 6500

### Enables sending of coredumps to vCenter server ###
esxcli system coredump network set -e true

### Shows new core dump configuration ###
esxcli system coredump network get

It now lists the settings compared to the first time we ran it.

 ### Sends test coredump to vCenter Server ###
esxcli system coredump network check

OK, we are done with the host setup. Now to confirm the last step on the vCenter server. Ssh to the vCenter server and check the following log file:

/var/log/vmware/netdumper/netdumper.log

You should see similar entries:

“Posting back a status check reply to…”    SUCCESS!!!

Quick credit to @lamw for this https://blogs.vmware.com/vsphere/2012/12/network-core-dump-collector-check-with-esxcli-5-1.html. This article lays out the steps of this setup in great detail.

Automate it

Having gotten it to work on one host, I now had to figure out how to get it working on the rest of my hosts with less typing and less time. Enter powercli. Borrowing a lot from this guy’s technique, I used the Get-EsxCli and a foreach loop to apply the above settings to each host. At the same time, I did a tail -f on the log file to witness the fruits of my labor. It was a good feeling knowing I had saved myself so much work. So without further adieu:

 

 

 

 

 

VMware PowerCLI to enable management services

I wrote this once when I needed to pull as much information as possible about the vmware environment I found myself in that day. It enables ssh and sets it to start at boot. It also enables SNMP, sets it to star at boot and sets the community string you define. I split it up into multiple for loops so I could easily track what I was doing with on screen commentary via write-host. I used it in a vSphere 5.5 environment. Beware results might vary by version.

<#####################################################################
I begin by letting you define your vCenter server, your datacenter object and your snmp community string
Next this script starts SSH, makes SSH start on boot, hides SSH warnings, starts SNMP, makes SNMP start on boot,
and sets the SNMP community string on each host in your defined data center.
######################################################################>

#Your Datacenter specific variables
$vCenter = "FQDN of vcenter server"
$datacenter = "datacenter object name"
$community = "SNMP Community String"

#Load VMware Cmdlets and connect to vCenter
Add-PSSnapin vmware*
Connect-VIServer -Server $vCenter

#Set VMHosts variable
$VMHosts = Get-VMhost -Location $datacenter | Sort-Object
  
# Start SSH on each host in the datacenter
ForEach ($HostMachine in $VMHosts) {
    Write-Host "Starting the SSH Service on $HostMachine " 
    $HostMachine | Get-VMHostService | Where-Object {($_.Key -eq "TSM-SSH") -and ($_.Running -eq $False)} | Start-VMHostService
}
  
# Change SSH to start on boot
ForEach ($HostMachine in $VMHosts) {
    Write-Host "Changing SSH to start on boot for $HostMachine " 
    $HostMachine | Get-VMHostService | where { $_.key -eq "TSM-SSH" } | Set-VMHostService -Policy "On" -Confirm:$false -ea 1
}
  
# Supress SSH warning
ForEach ($HostMachine in $VMHosts) {
    Write-Host "Hiding SSH Warning on $HostMachine "
    $HostMachine | Get-AdvancedSetting | Where-Object {$_.Name -eq "UserVars.SuppressShellWarning"} | Set-AdvancedSetting -Value "1" -Confirm:$false
}

#Start SNMP service on hosts
ForEach ($HostMachine in $VMHosts) {
    Write-Host "Starting SNMP on $HostMachine " 
    $HostMachine | Get-VMHostService | Where-Object {($_.Key -eq "snmpd") -and ($_.Running -eq $false)} | Start-VMHostService | Out-Null
}

#Change SNMP to start on boot
ForEach ($HostMachine in $VMHosts) {
    Write-Host "Changing SNMP to start with $HostMachine " 
    Get-VMHostService $HostMachine  | Where-Object { $_.key -eq "snmpd" } | Set-VMHostService -Policy "On" -Confirm:$false -ea 1 | Out-Null
}

#Set snmp community string and opens firewall for snmp
ForEach ($HostMachine in $VMHosts) {
    Write-Host "Setting snmp community string and opening firewall for $HostMachine"
    $esxcli = Get-EsxCli -VMHost $HostMachine
    $esxcli.system.snmp.set($null,$community,$true,$null,$null,$null,$null,$null,$null,$null,$null,$null,$null,$null,$null,$null,$null)
    $esxcli.network.firewall.ruleset.set($true, $true, "snmp")
}

Write-Host "Good Job"