Script to join ESXi 5 hosts to Active Directory for Directory Services Authentication

I’m getting ready to upgrade a ton of our ESXi hosts to 5 and wanted a quick way to join all of them to AD after. I could probably do a fresh install and incorporate this into my ESXi Config Script, that’s a consideration, but for the time being, a script that targets clusters, folders, vDCs, etc, will work. The script can also target individual ESXi hosts, they do not have to be joined to vCenter.

There’s a bug in ESXi 5 that blocks DNS (fixed in Update 1), so you’ll get an error if you try to connect manually and see something like this in /var/log/syslog.log2012-04-20T15:56:25Z netlogond[3236247]: [LWNetDnsQueryWithBuffer() /build/mts/release/bora-396388/likewise/esxi-esxi/src/linux/netlogon/utils/lwnet-dns.c:1185] DNS lookup for '_ldap._tcp.dc._msdcs.ad.fqdn.com' failed with errno 110, h_errno = 2

The main guts of the script use Set-VMHostAuthentication, and that’s really it. To address the bug we have to use Set-VMHostFirewallDefaultPolicy to turn off the fw (or allow all incoming/outgoing), join the domain, then turn it back on. The rest of the script is logic, checking for needed stuff.

Take note I used $host.ui.PromptForCredential again, since I could let the user know which creds I need, AD versus ESXi login. I basically used the Get-WWN script as a template and changed/added what I needed.

When populating the $VMHosts variable, it only pulls hosts with ESXi version 5.*. Later in the script, you’ll see another check for version number, that’s for standalone hosts. I need to check when connecting directly to the host, then $foreach.movenext if it’s not 5.*, but I haven’t figured out an efficient way to get that done. A little help maybe?

Usage:Join-Domain.ps1 -VMHosts ("host1","host2","host3") -domain my.domain or Join-Domain -vc vcenterserver -container cluster1 -domain my.domain

I left container as required so you can target what you want. I tested it against a few clusters with different versions of ESXi, and everything seemed to work well.

One strange thing, though, is the host connection state has to be ‘connected’. If it’s in maintenance mode, set-vmhostauthentication won’t work. Why? I dunno, bug imo, it should work in either connected or maintenance mode.

I slapped this together quickly, so if you notice anything wrong, please let me know. If you know of another way, please tell me, too, I’m always happy to learn other ways to do things.

Script (also attached at the bottom below the code block):

param([string]$vc = "vc", [string]$container = "container", [string[]]$VMHosts = "VMHosts", [string]$domain = "domain")
 
Add-PSSnapin VMware.* -ErrorAction SilentlyContinue
 
#usage info
function usage()
	{
	Write-host -foregroundcolor green `n`t"This script is used to join ESXi 5 hosts to the AD Doamin provided."
	Write-host -foregroundcolor green `n`t"You can either specify -VMHosts as an array:"
	write-host -foregroundcolor yellow `n`t`t"Join-Domain -VMHosts (`"host1`",`"host2`",`"host3`") -domain my.domain"
	Write-host -foregroundcolor green `n`t"or specify -vc and -container, where container is a host name, cluster, folder, datacenter, etc:"
	write-host -foregroundcolor yellow `n`t`t"Join-Domain -vc vcenterserver -container cluster1 -domain my.domain" `n
    write-host -foregroundcolor green `t"You can use either -VMHosts or -vc and -container, not a combination of them."
    write-host -foregroundcolor red `n`t"remember, -domain is required!" `n
	}
 
function JoinDomain{
    #We need AD creds to join
    $AD_creds = $host.ui.PromptForCredential("AD Credentials Required", "Please enter Domain credentials to join computers: user@$domain", "", "")
 
    if ($esx -eq 1)
        #do this only if connecting directly to ESX hosts
        {
        $VMHosts_creds = $host.ui.PromptForCredential("ESX/ESXi Credentials Required", "Please enter credentials to log into the ESX/ESXi host.", "", "")
        }
 
    if ($vcenter -eq 1)
        #do this if connecting to vCenter to populate VMHosts
        {
        connect-viserver $vc > $NULL 2>&1
        write-host -fore green "Pulling ESXi 5 hosts from $container in $vc"
        $VMHosts = get-vmhost -location $container | ? {$_.Version -like "5.*"} | sort name 
        }
 
        foreach ($VMHost in $VMHosts){
        if ($esx -eq 1)
            #do this only if connecting directly to ESX hosts
            {
            connect-viserver $VMHost -credential $VMHosts_creds > $NULL 2>&1
            }
		Write-Host -foregroundcolor green "Server: " $VMHost
        $getvmhost = get-vmhost $vmhost
		if (($getVMhost.Version -like "5.*") -and ($getVMHost.ConnectionState -eq "Connected"))
        {
            #the next step is for 5.0 without update 1, there's a bug addressed in update 1
            $getvmhost | Get-VMHostFirewallDefaultPolicy | Set-VMHostFirewallDefaultPolicy -AllowIncoming $true -AllowOutgoing $true > $NULL 2>&1
            #what actually joins the machine to the domain
            $getvmhost | get-vmhostauthentication | Set-VMHostAuthentication -Domain $domain -Credential $AD_creds -JoinDomain -confirm:$false > $NULL 2>&1
            #lets turn this back on
            $getvmhost | Get-VMHostFirewallDefaultPolicy | Set-VMHostFirewallDefaultPolicy -AllowIncoming $false -AllowOutgoing $false > $NULL 2>&1
            write-host -fore green "done with $vmhost"
            if ($esx -eq 1)
            #disconnect from the current ESX host before going to the next one
            {
                disconnect-viserver -confirm:$false
            }
		}
        Else{Write-host -fore red `n`t "Skipping $VMHost, hosts cannot be in maintenance mode, retarded, I know, must be in a `'Connected`' state."`n}
	}
    if ($vcenter -eq 1)
        #disconnect from vcenter
        {
        disconnect-viserver -confirm:$false
        }
}
 
if ((($VMHosts -eq "VMHosts") -or ($domain -eq "domain")) -and (($vc -eq "vc") -or ($container -eq "container") -or ($domain -eq "domain")))
    #if VMHosts, vc, container, or domain is blank
	{
	usage
    break
	}
 
elseif (($VMHosts -ne "VMHosts") -and (($vc -ne "vc") -or ($container -ne "container")))
    #if VMHosts and vc or container is used
	{
	usage
    break
	}
 
elseif ((($VMHosts -ne "VMHosts") -and ($domain -eq "domain")) -and (($vc -eq "vc") -or ($container -eq "container") -or ($domain -eq "domain")))
    #if only VMHosts is used and domain was blank
	{
    usage
    break
    } 
 
elseif (($VMHosts -eq "VMHosts") -and (($vc -ne "vc") -and ($container -ne "container") -and ($domain -eq "domain")))
    #if vc and container are used, but domain is blank
	{
    usage
    break
	}
 
elseif (($VMHosts -ne "VMHosts") -and (($vc -eq "vc") -or ($container -eq "container") -or ($domain -eq "domain")))
    #if only VMHosts is used, set our esx variable to 1
	{
    $esx = 1
    JoinDomain
    }
 
elseif (($VMHosts -eq "VMHosts") -and (($vc -ne "vc") -and ($container -ne "container")))
    #if vc and container are used, 
	{
    $vcenter = 1
	JoinDomain
	}

Here’s the actual .ps1 file: Join-Domain.ps1

Tags: , , ,

// // // //

Leave a reply

 

Designed by ThepHuck
Wordpress Themes
Scroll to Top