Powershell to manipulate host file

Powershell

Powershell Problem Overview


I am looking at to see if I can create powershell script to update the contents in the host file.

Anybody know if there are any examples that manipulate the host file using powershell or any other scripting lanaguages?

Thanks.

Powershell Solutions


Solution 1 - Powershell

All of these answers are pretty elaborate. This is all you need to add a hosts file entry:

Add-Content -Path $env:windir\System32\drivers\etc\hosts -Value "`n127.0.0.1`tlocalhost" -Force

IP address and hostname are separated by `t which is the PowerShell notation for a tab character.

`n is the PowerShell notation for a newline.

Solution 2 - Powershell

First up, if you're on Vista or Windows 7 make sure you run these commands from an elevated prompt:

# Uncomment lines with localhost on them:
$hostsPath = "$env:windir\System32\drivers\etc\hosts"
$hosts = get-content $hostsPath
$hosts = $hosts | Foreach {if ($_ -match '^\s*#\s*(.*?\d{1,3}.*?localhost.*)')
                           {$matches[1]} else {$_}}
$hosts | Out-File $hostsPath -enc ascii

# Comment lines with localhost on them:
$hosts = get-content $hostsPath
$hosts | Foreach {if ($_ -match '^\s*([^#].*?\d{1,3}.*?localhost.*)') 
                  {"# " + $matches[1]} else {$_}} |
         Out-File $hostsPath -enc ascii

Given this I think you can see how to use a regex to manipulate entries as necessary.

Solution 3 - Powershell

The Carbon module has a Set-HostsEntry function for setting a hosts entry:

Set-HostsEntry -IPAddress 10.2.3.4 -HostName 'myserver' -Description "myserver's IP address"

Solution 4 - Powershell

If anyone is looking for a more advanced example, I've always been particularly fond of this gist: <https://gist.github.com/markembling/173887>

#
# Powershell script for adding/removing/showing entries to the hosts file.
#
# Known limitations:
# - does not handle entries with comments afterwards ("<ip>    <host>    # comment")
#

$file = "C:\Windows\System32\drivers\etc\hosts"

function add-host([string]$filename, [string]$ip, [string]$hostname) {
	remove-host $filename $hostname
	$ip + "`t`t" + $hostname | Out-File -encoding ASCII -append $filename
}

function remove-host([string]$filename, [string]$hostname) {
	$c = Get-Content $filename
	$newLines = @()
	
	foreach ($line in $c) {
		$bits = [regex]::Split($line, "\t+")
		if ($bits.count -eq 2) {
			if ($bits[1] -ne $hostname) {
				$newLines += $line
			}
		} else {
			$newLines += $line
		}
	}
	
	# Write file
	Clear-Content $filename
	foreach ($line in $newLines) {
		$line | Out-File -encoding ASCII -append $filename
	}
}

function print-hosts([string]$filename) {
	$c = Get-Content $filename
	
	foreach ($line in $c) {
		$bits = [regex]::Split($line, "\t+")
		if ($bits.count -eq 2) {
			Write-Host $bits[0] `t`t $bits[1]
		}
	}
}

try {
	if ($args[0] -eq "add") {
	
		if ($args.count -lt 3) {
			throw "Not enough arguments for add."
		} else {
			add-host $file $args[1] $args[2]
		}
		
	} elseif ($args[0] -eq "remove") {
	
		if ($args.count -lt 2) {
			throw "Not enough arguments for remove."
		} else {
			remove-host $file $args[1]
		}
		
	} elseif ($args[0] -eq "show") {
		print-hosts $file
	} else {
		throw "Invalid operation '" + $args[0] + "' - must be one of 'add', 'remove', 'show'."
	}
} catch  {
	Write-Host $error[0]
	Write-Host "`nUsage: hosts add <ip> <hostname>`n       hosts remove <hostname>`n       hosts show"
}

Solution 5 - Powershell

Starting with Kevin Remisoski's excellent answer above, I came up with this which lets me add/update multiple entries at once. I also changed the regex in the split to look for any white space, not just tab.

function setHostEntries([hashtable] $entries) {
    $hostsFile = "$env:windir\System32\drivers\etc\hosts"
    $newLines = @()

    $c = Get-Content -Path $hostsFile
    foreach ($line in $c) {
        $bits = [regex]::Split($line, "\s+")
        if ($bits.count -eq 2) {
            $match = $NULL
            ForEach($entry in $entries.GetEnumerator()) {
                if($bits[1] -eq $entry.Key) {
                    $newLines += ($entry.Value + '     ' + $entry.Key)
                    Write-Host Replacing HOSTS entry for $entry.Key
                    $match = $entry.Key
                    break
                }
            }
            if($match -eq $NULL) {
                $newLines += $line
            } else {
                $entries.Remove($match)
            }
        } else {
            $newLines += $line
        }
    }

    foreach($entry in $entries.GetEnumerator()) {
        Write-Host Adding HOSTS entry for $entry.Key
        $newLines += $entry.Value + '     ' + $entry.Key
    }

    Write-Host Saving $hostsFile
    Clear-Content $hostsFile
    foreach ($line in $newLines) {
        $line | Out-File -encoding ASCII -append $hostsFile
    }
}

$entries = @{
    'aaa.foo.local' = "127.0.0.1"
    'bbb.foo.local' = "127.0.0.1"
    'ccc.foo.local' = "127.0.0.1"
};
setHostEntries($entries)

Solution 6 - Powershell

I have written a code to delete entries from host. You can easily change the code to add entries to it from the code.

$domainName = "www.abc.com"
$rplaceStr = ""
$rHost = "C:\Windows\System32\drivers\etc\hosts"
$items = Get-Content $rHost | Select-String $domainName
Write-host $items
foreach( $item in $items)
{
(Get-Content $rHost) -replace $item, $rplaceStr| Set-Content $rHost
}

For more information see http://nisanthkv.blog.com/2012/06/13/remove-host-entries-using-powershell/

Solution 7 - Powershell

99% of the time admin rights are needed to modify a host record. Try adding this code at the top of your Powershell script.

If (-NOT ([Security.Principal.WindowsPrincipal][Security.Principal.WindowsIdentity]::GetCurrent()).IsInRole([Security.Principal.WindowsBuiltInRole] "Administrator"))

{   
$arguments = "& '" + $myinvocation.mycommand.definition + "'"
Start-Process powershell -Verb runAs -ArgumentList $arguments
Break
}

Solution 8 - Powershell

For me the biggest pain in dealing with the hosts file is remembering where it is. I set a variable that points to my hosts file in my PowerShell profile, which makes it easy to edit in a text editor.

In PowerShell, type the following to open your profile:

C:\> Notepad $profile

Add this:

$hosts = "$env:windir\System32\drivers\etc\hosts"

Save the file, then close and re-open PowerShell, running as administrator. You can't edit the hosts file without elevated permissions.

Now you can edit your hosts file the same way you'd edit your profile:

C:\> Notepad $hosts

Solution 9 - Powershell

I wrote a quick script that creates a simple GUI for adding new records to the HOSTS file. It will open a window, ask for hostname and IP, then append your input to the HOSTS file.

I'm sure it could be simplified and look cleaner... but works fine for my use case.

Enjoy!

Add-Type -AssemblyName System.Windows.Forms
Add-Type -AssemblyName System.Drawing

$hostsfilelocation = "$env:windir\System32\drivers\etc\hosts"
$readhostsfile = Get-Content $hostsfilelocation

$form = New-Object System.Windows.Forms.Form
$form.Text = 'Update HOSTS File'
$form.Size = New-Object System.Drawing.Size(300,200)
$form.StartPosition = 'CenterScreen'

$AddHosts = New-Object System.Windows.Forms.Button
$AddHosts.Location = New-Object System.Drawing.Point(55,120)
$AddHosts.Size = New-Object System.Drawing.Size(90,25)
$AddHosts.Text = 'Add Record'
$AddHosts.DialogResult = [System.Windows.Forms.DialogResult]::OK
$form.AcceptButton = $AddHosts
$form.Controls.Add($AddHosts)

$CancelButton = New-Object System.Windows.Forms.Button
$CancelButton.Location = New-Object System.Drawing.Point(170,120)
$CancelButton.Size = New-Object System.Drawing.Size(75,25)
$CancelButton.Text = 'Cancel'
$CancelButton.DialogResult = [System.Windows.Forms.DialogResult]::Cancel
$form.CancelButton = $CancelButton
$form.Controls.Add($CancelButton)

$Hostslabel = New-Object System.Windows.Forms.Label
$Hostslabel.Location = New-Object System.Drawing.Point(10,20)
$Hostslabel.Size = New-Object System.Drawing.Size(280,20)
$Hostslabel.Text = 'Enter New HOSTNAME/FQDN:'
$form.Controls.Add($Hostslabel)

$HoststextBox = New-Object System.Windows.Forms.TextBox
$HoststextBox.Location = New-Object System.Drawing.Point(10,40)
$HoststextBox.Size = New-Object System.Drawing.Size(260,20)
$form.Controls.Add($HoststextBox)

$IPlabel = New-Object System.Windows.Forms.Label
$IPlabel.Location = New-Object System.Drawing.Point(10,60)
$IPlabel.Size = New-Object System.Drawing.Size(280,20)
$IPlabel.Text = 'Enter IP:'
$form.Controls.Add($IPlabel)

$IPtextBox = New-Object System.Windows.Forms.TextBox
$IPtextBox.Location = New-Object System.Drawing.Point(10,80)
$IPtextBox.Size = New-Object System.Drawing.Size(260,20)
$form.Controls.Add($IPtextBox)

$form.Topmost = $true

$form.Add_Shown({($HoststextBox,$IPtextbox).Select()})

$result = $form.ShowDialog()

if ($result -eq [System.Windows.Forms.DialogResult]::OK)
{
    $inputhosts = $HoststextBox.Text
    $inputip = $IPtextBox.Text
    $newrecord = "$inputip $inputhosts"
    Add-Content -Path $hostsfilelocation -Value $newrecord
}

Solution 10 - Powershell

This is the one I ended up using. I made an Active Directory group policy to run on every update, so if one of the entries is missing it is added, if it already exists you don't get a double entry:

function Test-FileLock {
  param (
    [parameter(Mandatory=$true)][string]$Path
  )

  $oFile = New-Object System.IO.FileInfo $Path

  if ((Test-Path -Path $Path) -eq $false) {
    return $false
  }

  try {
    $oStream = $oFile.Open([System.IO.FileMode]::Open, [System.IO.FileAccess]::ReadWrite, [System.IO.FileShare]::None)

    if ($oStream) {
      $oStream.Close()
    }
    return $false
  } catch {
    # file is locked by a process.
    return $true
  }
}

$hostsFile  = "$($env:windir)\system32\Drivers\etc\hosts"
$hostsEntry = @('192.168.223.223 w2012', '192.168.223.224 w2019', '192.168.223.5 tbstorage', '192.168.223.7 tgcstorage','192.168.223.202 paneladmin.local.com')

foreach ($HostFileEntry in $hostsEntry)
{
    While(Test-FileLock($hostsFile)) {
        Write-Host "File locked! waiting 1 seconds."
        Start-Sleep -s 1
    }
    # split the entry into separate variables
    $ipAddress, $hostName = $HostFileEntry -split '\s+',2
    # prepare the regex
    $re = '(?m)^{0}[ ]+{1}' -f [Regex]::Escape($ipAddress), [Regex]::Escape($hostName)
    # Write-Host $re

    If ((Get-Content $hostsFile -Raw) -notmatch $re) {
        Add-Content -Path $hostsFile -Value $HostFileEntry
        Write-Host "Writing $HostFileEntry"
    }
}

Solution 11 - Powershell

I have checked the entry if exists or not before write-in the host file.

$domainCheck = "installer.example.com"
$rHost = "C:\Windows\System32\drivers\etc\hosts"
$domainName = "`n8.8.8.8`tinstaller.example.com"
if((Get-Content $rHost | Select-String $domainCheck ).length -eq 0){
	Add-Content -Path $rHost -Value $domainName -Force
}

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionTonyView Question on Stackoverflow
Solution 1 - PowershellsherenatorView Answer on Stackoverflow
Solution 2 - PowershellKeith HillView Answer on Stackoverflow
Solution 3 - PowershellAaron JensenView Answer on Stackoverflow
Solution 4 - PowershellKevin RemisoskiView Answer on Stackoverflow
Solution 5 - PowershellJasonView Answer on Stackoverflow
Solution 6 - PowershellNisanth.KVView Answer on Stackoverflow
Solution 7 - PowershellJohn BView Answer on Stackoverflow
Solution 8 - PowershellJon CrowellView Answer on Stackoverflow
Solution 9 - PowershellTheRealCodeView Answer on Stackoverflow
Solution 10 - PowershellMarkos FView Answer on Stackoverflow
Solution 11 - PowershellMajedurView Answer on Stackoverflow