Разнести файл hosts по удалённым системам групповыми политиками — дело не хитрое. Да и отредактировать сам файл проще простого. А что если нужно работать с файлом из консоли, адресно и (желательно) на удалённой машине?
Как раз для этих целей и можно использовать PowerShell-модуль PsHosts, не изобретая очередное колесо. Всю документацию по модулю можно найти в репозитории на котоосьминоге. Там даже есть классная гифка с демонстрацией работы модуля:

Модуль умеет работать с нестандартными расположениями файла hosts прямо из коробки. Это и позволит добираться до файла hosts на удалённых машинах при условии, что разрешена работа в админской шаре. Кроме того авторами проекта заявлена мультиплатформенность и поддержка директивы whatif.
К сожалению, до мультиплатформы я ещё не добрался, а вот на whatif обратил пристальное внимание во время тестирования командлетов. Теперь к теме поста.
Устанавливается модуль вполне стандартно:
# Установка для текущего пользователя # Install-Module PsHosts -Scope CurrentUser # Установка для всех пользователей # Install-Module PsHosts -Scope AllUsers
Потестировав командлеты и определив для себя необходимый минимум (Get-HostEntry, Test-HostEntry, Add-HostEntry и Remove-HostEntry), я принялся за написание функций-кирпичиков, которые мог бы использовать в финальном скрипте.
Начну с сопутствующего функционала. Прежде всего мне потребовалась вот эта функция, с помощью которой можно устанавливать или импортировать модули. Обращаю внимание, что для работы GetModule потребуется доступ к репозиториям PowerShell.
Первой я написал функцию проверки доступности удалённого хоста и самого сетевого пути до заветного файла:
function GetRemoteHostsPath
{
Param([Parameter(Mandatory=$true)]$ComputerName)
$ping = Test-Connection -ComputerName $ComputerName -Count 1 -Quiet
if ($ping)
{
$path = Test-Path -Path "\\$ComputerName\c$\windows\system32\drivers\etc\hosts" -PathType Leaf
if ($path) { return $true }
else { return $false }
}
else
{
return $false
}
}
GetRemoteHostsPath принимает в качестве аргумента имя удалённого компьютера, проверяет его доступность и пытается обратиться к файлу hosts. Если хоть одно из указанных действий завершается неудачей — функция возвращает False.
Затем мне потребовалась функция, возвращающая все правила, описанные в файле hosts:
function GetRemoteHosts
{
Param([Parameter(Mandatory=$true)]$ComputerName)
$remotehostspath = "\\$ComputerName\c$\windows\system32\drivers\etc\hosts"
$content = Get-HostEntry -HostsPath $remotehostspath
if ($content -eq $null)
{ return "Записей в файле hosts на $ComputerName не найдено!"}
else { return $content }
}
Всю основную работу берёт на себя командлет Get-HostEntry, а функция лишь передаёт ему путь до файла и обрабатывает пустой вывод. Данные, которые возвращаются в консоль уложены в таблицу и обращаться с ними можно соответствующе. Разумеется, ничего кроме вывода в консоль содержимого файла hosts функция не делает.
Приступим к основному функционалу. Логическая функция AddRemoteHosts для добавления записи в файл hosts:
function AddRemoteHosts
{
Param([Parameter(Mandatory=$true)]$ComputerName,
[Parameter(Mandatory=$true)]$IP,
[Parameter(Mandatory=$true)]$Name)
$remotehostspath = "\\$ComputerName\c$\windows\system32\drivers\etc\hosts"
$test = Test-HostEntry -HostsPath $remotehostspath -Name $Name
if (!$test)
{
Add-HostEntry -HostsPath $remotehostspath -Name $Name -Address $IP | Out-Null
return $true
}
else { return $false }
}
Принимает в качестве параметров имя удалённого компьютера, а также IP-адрес и DNS-имя для сопоставления.
Конечно, добавить запись в файл — полдела. Необходимо иметь функционал и удаления записи. Для этого написал функцию RemoveRemoteHosts:
function RemoveRemoteHosts
{
Param([Parameter(Mandatory=$true)]$ComputerName,
[Parameter(Mandatory=$true)]$Name)
$remotehostspath = "\\$ComputerName\c$\windows\system32\drivers\etc\hosts"
$test = Test-HostEntry -HostsPath $remotehostspath -Name $Name
if ($test)
{
Remove-HostEntry -HostsPath $remotehostspath -Name $Name | Out-Null
return $true
}
else { return $false }
}
Прежде чем удалить запись, функция RemoveRemoteHosts проверяет её наличие с помощью командлета Test-HostEntry.
Теперь объединяем весь этот набор функций в один скрипт с менюшкой и дружим с модулем ActiveDirectoryObjectPicker для понятного обращения к Active Directory:
## Функция для поиска модулей ##
function GetModule
{
Param([Parameter(Mandatory=$true)]$ModuleName)
$module = Get-Module -ListAvailable -Name $ModuleName
if ($module)
{
Import-Module $ModuleName
}
else
{
Install-Module $ModuleName -Scope CurrentUser
Import-Module $ModuleName -Force
}
}
## Проверка сетевого пути ##
function GetRemoteHostsPath
{
Param([Parameter(Mandatory=$true)]$ComputerName)
$ping = Test-Connection -ComputerName $ComputerName -Count 1 -Quiet
if ($ping)
{
$path = Test-Path -Path "\\$ComputerName\c$\windows\system32\drivers\etc\hosts" -PathType Leaf
if ($path) { return $true }
else { return $false }
}
else
{
return $false
}
}
## Получить записи из hosts ##
function GetRemoteHosts
{
Param([Parameter(Mandatory=$true)]$ComputerName)
$remotehostspath = "\\$ComputerName\c$\windows\system32\drivers\etc\hosts"
$content = Get-HostEntry -HostsPath $remotehostspath
if ($content -eq $null)
{ return "Записей в файле hosts на $ComputerName не найдено!"}
else { return $content }
}
## Добавить записи в hosts ##
function AddRemoteHosts
{
Param([Parameter(Mandatory=$true)]$ComputerName,
[Parameter(Mandatory=$true)]$IP,
[Parameter(Mandatory=$true)]$Name)
$remotehostspath = "\\$ComputerName\c$\windows\system32\drivers\etc\hosts"
$test = Test-HostEntry -HostsPath $remotehostspath -Name $Name
if (!$test)
{
Add-HostEntry -HostsPath $remotehostspath -Name $Name -Address $IP | Out-Null
return $true
}
else { return $false }
}
## Удалить записи из hosts ##
function RemoveRemoteHosts
{
Param([Parameter(Mandatory=$true)]$ComputerName,
[Parameter(Mandatory=$true)]$Name)
$remotehostspath = "\\$ComputerName\c$\windows\system32\drivers\etc\hosts"
$test = Test-HostEntry -HostsPath $remotehostspath -Name $Name
if ($test)
{
Remove-HostEntry -HostsPath $remotehostspath -Name $Name | Out-Null
return $true
}
else { return $false }
}
# Импорт и/или установка модулей #
GetModule -ModuleName PSHosts
GetModule -ModuleName ActiveDirectoryObjectPicker
# Получение имени удалённого компьютера #
[System.Console]::Title = "RemoteHostsFile"
Write-Host "Ожидание данных..." -ForegroundColor Cyan
$remotehost = (Show-ActiveDirectoryObjectPicker -AllowedLocations EnterpriseDomain -DefaultObjectTypes Computers -DefaultLocations EnterpriseDomain).Name
Clear
[System.Console]::Title = "RemoteHostsFile on $remotehost"
# Добавление/удаление записей #
$getpath = GetRemoteHostsPath -ComputerName $remotehost
if ($getpath)
{
while ($true)
{
Write-Host
Write-Host "Получаю содержимое файла hosts на $remotehost..."
GetRemoteHosts -ComputerName $remotehost
Write-Host
Write-Host "1. Добавить запись в файл hosts" -ForegroundColor Yellow
Write-Host "2. Удалить запись из файла hosts" -ForegroundColor Yellow
Write-Host
$choice = Read-Host "Выберите вариант"
Write-Host
switch($choice)
{
1 # Добавить запись в файл hosts
{
$name = Read-Host "Введите DNS имя нового правила"
$ip = Read-Host "Введите IP-адрес нового правила"
$add = AddRemoteHosts -ComputerName $remotehost -Name $name -IP $ip
Clear
if ($add) { Write-Host "Правило для $name успешно добавлено!" -ForegroundColor Green }
else { Write-Host "Что-то пошло не так!" -ForegroundColor Red }
}
2 # Удалить запись из файла hosts
{
$name = Read-Host "Введите DNS имя правила"
Clear
$remove = RemoveRemoteHosts -ComputerName $remotehost -Name $name
if ($remove) { Write-Host "Правило $name успешно удалено!" -ForegroundColor Green }
else { Write-Host "Что-то пошло не так!" -ForegroundColor Red }
}
default # Любой другой ввод
{
Clear
}
}
}
}
else
{
Write-Host "Что-то пошло не так!" -ForegroundColor Red
Sleep(15)
}
Скрипт можно смело компилировать в exe с помощью PS2EXE. Главное при сборке не забыть убрать параметр -noConsole и поставить галку с повышением прав запуска:

В следующей публикации покажу простейший скрипт для редактирования файла hosts на удалённой машине без установки и импорта дополнительных модулей.
Напоминаю: для любых манипуляций с файлом hosts нужны права администратора!