VMware Cloud Community
deryambn
Enthusiast
Enthusiast
Jump to solution

Edit multiple ESXi hosts file with powercli by chosing esxi and entry

Hello,

I would like add all ESXis' hosts file the entry and wanna do it to chosing ESXi and an entry. I found some codes but it doesnt work. Could you help me

Thanks.

I found codes from there:  https://github.com/herseyc/PowerCLI-Scripts/blob/master/Update-HostsFile.ps1

This is the code:

$vCenterServer = Read-Host -Prompt 'Enter the FQDN of the vCenter Server you want to connect to (ex. vcenter.domain.com)'
Try {
Connect-VIServer -Server $vCenterServer -ErrorAction Stop | Out-Null
}
Catch {
Write-Host -ForegroundColor Red -BackgroundColor Black "Could not connect to the vCenter Server [$vCenterServer]." `n
Exit
}

while ($True){
### Prompt the user for the cluster name within that vCenter Server
$ClusterName = Read-Host -Prompt 'Enter the full name of the cluster you want to work with (ex. ProdCluster01)'

### Get information about all hosts in the defined cluster
$vmHosts = Get-Cluster -Name $ClusterName | Get-VMHost | Sort-Object

$cont = ""
$contR = ""
Do {
### Ask the user what step to perform
Write-Host `n
Write-Host "Please enter a task to perform on each host in the cluster:"
Write-Host "1.) Add parameter"
Write-Host "2.) Add Another parameter"
Write-Host "3.) Next Cluster"
Write-Host "4.) Exit" `n
$choice = Read-Host

### Perform a particular task based on user input
Switch ($choice) {
### If task #1 is chosen, add parameter to /etc/hosts
1 {
Write-Host -ForegroundColor Yellow `n "Retrieving current /etc/hosts file from $esxihost"
ForEach ($vmHost in $vmHosts) {
#Connectivity Information
$Username = "root" # ESXi Username
$Password = Read-Host -Prompt 'ESXi Password'

#New Host Entry
$addIP = Read-Host -Prompt ' New Entry IP'
$addHostname = Read-Host -Prompt ' New Entry Hostname'
$addAlias= Read-Host -Prompt ' New Entry Alias'

### Create authorization string and store in $head
$auth = [System.Convert]::ToBase64String([System.Text.Encoding]::UTF8.GetBytes($Username + ":" + $Password))
$head = @{"Authorization"="Basic $auth"}

# Request current hosts file
Write-Host "Retrieving current /etc/hosts file from $esxihost" -ForeGroundColor Green
$requesthostsfile = Invoke-WebRequest -Uri https://$esxihost/host/hosts -Method GET -ContentType "text/plain" -Headers $head

if ( $requesthostsfile.StatusCode -ne "200" ) {
Write-Host "Unable to retrieve current /etc/hosts file from $esxihost" -ForeGroundColor Red
Exit
}

# Add new line to hosts file with $addIP and $addHostname and $addAlias
$newhostsfile = $requesthostsfile.Content
$newhostsfile += "`n$addIP`t$addHostname`t$addAlias"

Write-Host "Contents of new /etc/hosts" -ForeGroundColor Green
Write-Host "-------------------------------------------------------"
Write-Host $newhostsfile
Write-Host "-------------------------------------------------------"

# Put the new hosts file on the host
Write-Host "Putting new /etc/hosts file on $esxihost"
$puthostsfile = Invoke-WebRequest -Uri https://$vmHost/host/hosts -Method PUT -ContentType "text/plain" -Headers $head -Body $newhostsfile

if ( $puthostsfile.StatusCode -ne "200" ) {
Write-Host "Unable to put new /etc/hosts file on $esxihost" -ForeGroundColor Red
Exit
}
Write-Host "Done!" -ForeGroundColor Green
}
}
$cont=$True
}
### If task #2 is chosen, Add Another Entry
2 {
Write-Host -ForegroundColor Yellow `n "Retrieving current /etc/hosts file from $esxihost"
ForEach ($vmHost in $vmHosts) {
#New Host Entry
$addanotherIP = Read-Host -Prompt ' New Entry IP'
$addanotherHostname = Read-Host -Prompt ' New Entry Hostname'
$addanotherAlias= Read-Host -Prompt ' New Entry Alias'
}

# Request current hosts file
Write-Host "Retrieving current /etc/hosts file from $esxihost" -ForeGroundColor Green
$requesthostsfile = Invoke-WebRequest -Uri https://$esxihost/host/hosts -Method GET -ContentType "text/plain" -Headers $head

if ( $requesthostsfile.StatusCode -ne "200" ) {
Write-Host "Unable to retrieve current /etc/hosts file from $esxihost" -ForeGroundColor Red
Exit
}

# Add new line to hosts file with $addIP and $addHostname and $addAlias
$newhostsfile = $requesthostsfile.Content
$newhostsfile += "`n$anotheraddIP`t$addanotherHostname`t$addanotherAlias"

Write-Host "Contents of new /etc/hosts" -ForeGroundColor Green
Write-Host "-------------------------------------------------------"
Write-Host $newhostsfile
Write-Host "-------------------------------------------------------"


# Put the new hosts file on the host
Write-Host "Putting new /etc/hosts file on $esxihost"
$puthostsfile = Invoke-WebRequest -Uri https://$vmHost/host/hosts -Method PUT -ContentType "text/plain" -Headers $head -Body $newhostsfile

if ( $puthostsfile.StatusCode -ne "200" ) {
Write-Host "Unable to put new /etc/hosts file on $esxihost" -ForeGroundColor Red
Exit
}
$cont=$True
}
### If task #3 is chosen, next cluster
3 {
Write-Host "Next Cluster..."
$cont = $false
$contR = $false
}
### If task #4 is chosen, exit the script
4 {
Write-Host "Exiting..."
$cont = $false
$contR = $True
}

### If user enters anything other than 1-4, input is invalid and ask question again
default {
Write-Host -ForegroundColor Red ">>> Invalid input. Please select option 1-4."
$cont = $true
$contR = $false
}
### Loop through the script until task #4 (Exit) is chosen
While ($cont)

if ($contR) {
break
}

 

Reply
0 Kudos
1 Solution

Accepted Solutions
LucD
Leadership
Leadership
Jump to solution

You can do all escli commands via the Get-EsxCli cmdlet.

$esxcli = Get-esxcli -VMHost <ESXi-name> -V2
$esxcli.network.ip.hosts.remove.Invoke(@{ip='192.168.1.1';hostname='hostname.domain'})


Blog: lucd.info  Twitter: @LucD22  Co-author PowerCLI Reference

View solution in original post

Reply
0 Kudos
21 Replies
LucD
Leadership
Leadership
Jump to solution

Can you be a bit more specific?
What exactly doesn't work?


Blog: lucd.info  Twitter: @LucD22  Co-author PowerCLI Reference

Reply
0 Kudos
deryambn
Enthusiast
Enthusiast
Jump to solution

Hello @LucD

Those are the errors i got

 

At C:\Users\editHostFileinHost.ps1:77 char:13
+ $cont=$True
+ ~
Missing statement block in switch statement clause.
At C:\Users\editHostFileinHost.ps1:80 char:4
+ 2 {
+ ~
Unexpected token '{' in expression or statement.
At C:\Users\editHostFileinHost.ps1:119 char:7
+ 3 {
+ ~
Unexpected token '{' in expression or statement.
At C:\Users\editHostFileinHost.ps1:125 char:7
+ 4 {
+ ~
Unexpected token '{' in expression or statement.
At C:\Users\editHostFileinHost.ps1:138 char:18
+ While ($cont)
+ ~
Missing statement body in while loop.
At C:\Users\editHostFileinHost.ps1:19 char:5
+ Do {
+ ~
Missing closing '}' in statement block or type definition.
At C:\Users\editHostFileinHost.ps1:142 char:6
+ }
+ ~
Missing while or until keyword in do loop.
At C:\Users\editHostFileinHost.ps1:10 char:14
+ while ($True){
+ ~
Missing closing '}' in statement block or type definition.
+ CategoryInfo : ParserError: (:) [], ParseException
+ FullyQualifiedErrorId : MissingSwitchStatementClause

Reply
0 Kudos
LucD
Leadership
Leadership
Jump to solution

The script is having some issues (missing curly braces, curly braces in the wrong location, ...).
Attached a corrected version of your script, try that one.
Change the filetype .txt to .ps1


Blog: lucd.info  Twitter: @LucD22  Co-author PowerCLI Reference

Reply
0 Kudos
deryambn
Enthusiast
Enthusiast
Jump to solution

Hello @LucD 

Thank you so much for your help. I got an issue when tried

Retrieving current /etc/hosts file from
Invoke-WebRequest : Cannot bind parameter 'Uri'. Cannot convert value "https:///host/hosts" to type "System.Uri". Error: "Invalid URI: The hostname could not be parsed."
At C:\Users\edithostfile\Untitled5.ps1:49 char:64
+ ... stsfile = Invoke-WebRequest -Uri https://$esxihost/host/hosts -Method ...
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : InvalidArgument: (:) [Invoke-WebRequest], ParameterBindingException
+ FullyQualifiedErrorId : CannotConvertArgumentNoMessage,Microsoft.PowerShell.Commands.InvokeWebRequestCommand

Unable to retrieve current /etc/hosts file from

Reply
0 Kudos
LucD
Leadership
Leadership
Jump to solution

That line should read

$requesthostsfile = Invoke-WebRequest -Uri "https://$($esxihost)/host/hosts" -Method GET -ContentType "text/plain" -Headers $head

But there is the other issue that the variable $esxihost isn't assigned a value anywhere in your script.


Blog: lucd.info  Twitter: @LucD22  Co-author PowerCLI Reference

Reply
0 Kudos
deryambn
Enthusiast
Enthusiast
Jump to solution

I would like to choose all hosts in the cluster, and the script should add some lines in the hosts' /etc/hosts file. Is that possible with that script? @LucD 

Reply
0 Kudos
deryambn
Enthusiast
Enthusiast
Jump to solution

Hello @LucD 

This script works but keeps asking me for these entries over and over for all hosts in the cluster. I want it not to ask me again when I add these entries at first. Is that possible?

$addIP = Read-Host -Prompt ' New Entry IP'
$addHostname = Read-Host -Prompt ' New Entry Hostname'
$addAlias = Read-Host -Prompt ' New Entry Alias'

Reply
0 Kudos
LucD
Leadership
Leadership
Jump to solution

I'm not sure what you want me to do.

You wrote the script to prompt for these values inside your

ForEach ($vmHost in $vmHosts){

block, so it is normal it prompts for each ESXi node in the cluster.

Why did you place those prompts there in the first place? 


Blog: lucd.info  Twitter: @LucD22  Co-author PowerCLI Reference

Reply
0 Kudos
deryambn
Enthusiast
Enthusiast
Jump to solution

Actually i wanna give ip, hostname and alias at first and i wanna add these values each esxi host's hosts file in the cluster. When the script works it prompts the values again for each esxi host and i give those values again and again. Could you help me about that at the begining i give those values and script will add hosts and ask me other options 2,3 or 4. Could i explain what i wanna do?

Reply
0 Kudos
LucD
Leadership
Leadership
Jump to solution

In the meantime, I discovered you copied a large part of that script from here without so much as referring to the original author.

If you run the original script in a foreach loop over all the ESXi nodes in a cluster, you don't need to prompt for the new entry inside the foreach loop you are using.


Blog: lucd.info  Twitter: @LucD22  Co-author PowerCLI Reference

Reply
0 Kudos
deryambn
Enthusiast
Enthusiast
Jump to solution

Thanks @LucD , i didn't know, i added reference.

 

Reply
0 Kudos
LucD
Leadership
Leadership
Jump to solution

Did you make the changes like this?


Blog: lucd.info  Twitter: @LucD22  Co-author PowerCLI Reference

Reply
0 Kudos
deryambn
Enthusiast
Enthusiast
Jump to solution

Yes i did, the script works now. Thanks for everything.

There is the last version of the script. I made another changes.

In the second coice the script keeps asking for the new entries, i put the entries before foreach as you can see on the txt file. Now i wanna add try - catch in the scipt instead of exit. If i can do it i'll share the new version. I'm new about scripts 🙂 If i made a mistake sorry for that.

Thanks @LucD for your help.

Reply
0 Kudos
LucD
Leadership
Leadership
Jump to solution

If you mean the exit when the StatusCode from the Invoke-WebRequest is not 200?

In that case a Try-Catch would be rather unsuited for catching that 200 statuscode.
The Try-Catch is meant to capture terminating exceptions, i.e. the cmdlet fails.
A not 200 statuscode is saying that the cmdlet worked but that there was a possible issue with the HTTP request.
Those are 2 different things


Blog: lucd.info  Twitter: @LucD22  Co-author PowerCLI Reference

Reply
0 Kudos
deryambn
Enthusiast
Enthusiast
Jump to solution

I mean if i get an issue for one host the script can continue to the another host in the cluster. Not to stop working. I wanna add like this:

try{
Foreach()
......
}catch{
Write-host $vmhost “...”
}

Reply
0 Kudos
LucD
Leadership
Leadership
Jump to solution

Imho it would be a lot easier to not call the exit, just write a message and continue


Blog: lucd.info  Twitter: @LucD22  Co-author PowerCLI Reference

Reply
0 Kudos
deryambn
Enthusiast
Enthusiast
Jump to solution

The last version of the script @LucD  You can see what i meant

Tags (1)
Reply
0 Kudos
LucD
Leadership
Leadership
Jump to solution

If you just leave out the line with exit, the script will continue to the next ESXi nodes.

        if ( $puthostsfile.StatusCode -ne "200" ) {
          Write-Host "Unable to put new /etc/hosts file on $vmHost" -ForegroundColor Red
        }
        $cont = $True


Blog: lucd.info  Twitter: @LucD22  Co-author PowerCLI Reference

Reply
0 Kudos
deryambn
Enthusiast
Enthusiast
Jump to solution

I see, Thank you @LucD . Do you know how to delete an entry in the esxi host file content? I couldnt find it. It can be possible connect Esxi with ssh and run that command:

esxcli network ip hosts remove --hostname="hostname" --ip="IP"

But i couldnt find to do it with powercli for all hosts

Reply
0 Kudos