WinForms-приложение для работы с DNS-сервером Windows - то, чего нет в dnsmgmt.msc: записи
внутри Zone Scope в виде дерева, клиентские подсети, Query Resolution Policies, удалённое
управление другим сервером со своей аутентификацией, автообновление с GitHub.
Работает через встроенный PowerShell-модуль DnsServer. Автор: foosber, 2026. v2.9.2.
- .NET Framework 4.8 - обычно уже стоит на Windows Server 2016+.
- Роль DNS Server там, куда направлены операции (локально или через "Целевой DNS-сервер"). RSAT: DNS Server Tools, если приложение работает только удалённо.
- Права администратора нужны только для локального режима (см. ниже) - при отказе приложение само предложит перезапуск с UAC.
- Visual Studio 2019/2022 - только для сборки из исходников.
Манифест - asInvoker: приложение стартует без UAC-запроса. Права нужны только когда
операция идёт локально (DNS-служба на этой же машине) - при удалённом управлении
(-ComputerName/CimSession) права проверяются на стороне целевого сервера через
Kerberos/NTLM, локальная элевация тут вообще не при чём.
Если локальная операция реально упёрлась в нехватку прав - приложение показывает окно
"Требуются права администратора" с предложением перезапуститься через UAC (Verb="runas").
Показывается один раз за сессию, не спамит при повторных отказах.
- Значки вместо текстовых кнопок на всех 3 вкладках - свои, через GDI+ (
IconFactory.cs). Действия с вводом данных (создать зону/scope/запись/подсеть/политику) открывают диалог по клику на "+". Фильтр остаётся обычным полем - живой поиск важнее компактности. - Подсказки "?" - круглый пастельный значок с текстом во всплывающей подсказке
(
HelpIcon.cs) вместо постоянного серого текста. - Баннер - справа в самой верхней панели окна, на всю её высоту (не отдельным блоком сверху и не втиснут в общую высоту элементов слева), клик открывает "О программе" (как и значок в футере).
- Двойной клик по записи - редактирование; правая кнопка мыши - меню проверить/изменить/удалить (на дереве записей - ещё и "создать папку").
- Сворачивание блока вывода без потери накопленного текста.
Отдельной вкладки "Зоны" больше нет - управление зонами переехало сюда же, а сам список зон стал одним из уровней общего дерева. Два явно разграниченных блока с рамкой, стоящие рядом по горизонтали (не друг под другом - экономит вертикальное место для дерева и списка записей ниже), шириной точно по содержимому - "Управление зонами" (создать/удалить/перезагрузить/экспортировать/обновить список) и "Управление scope/записями" (создать/удалить scope, обновить записи текущего scope) - чтобы не путать, какая кнопка к чему относится, раз теперь всё на одной вкладке.
Дерево: верхний уровень - серверы ("Локальный" + любой, к которому успешно
подключались через панель "Целевой DNS-сервер"); внутри каждого сервера - "Зоны прямого
просмотра", "Зоны обратного просмотра" и (если есть) "Прочие зоны (условная
пересылка, stub)". Категория берётся из самого объекта зоны: ZoneType Forwarder/Stub
→ "прочие"; IsReverseLookupZone → "обратного просмотра" (с откатом на суффикс
.in-addr.arpa/.ip6.arpa); остальное → "прямого просмотра". Служебные авто-зоны
(TrustAnchors, корневые подсказки ., 0/127/255.in-addr.arpa) не показываются - как
обычный, не "расширенный", вид dnsmgmt.msc. Зоны условной пересылки и stub - листья
(Zone Scopes они не поддерживают, WIN32 9603), по клику показывают только источник.
Внутри каждой категории - сами зоны; внутри зоны - её
scope'ы; внутри scope - записи, сгруппированные по составным именам в папки (как в
dnsmgmt.msc): admin.pro32connect → папка pro32connect, элемент admin. Каждый
уровень подгружается лениво (при первом выборе/раскрытии узла) - ничего не тянется с
сервера впустую. Группировка записей в папки - визуальная, из уже загруженных данных; папка -
только узел со своими дочерними узлами, одноуровневые записи не превращаются в лишние
ветки. Справа - содержимое текущей папки (папки сверху, как в проводнике). Позиция границы
запоминается (RecordsTreeSplitter). Узел-сервер в дереве подсвечен (синий фон, белый
жирный текст) - сразу видно верхний уровень, не путая его с зонами/scope на вкладке.
Управление зонами: создание (Add-DnsServerPrimaryZone, типы AD-домен/AD-лес/файловая),
удаление (Remove-DnsServerZone), перезагрузка с диска (значок с буквой "R" внутри -
dnscmd /ZoneReload, всегда локально, не учитывает целевой сервер) - все три действия
применяются к зоне, выбранной сейчас в дереве. Экспорт - имена зон текущего
(развёрнутого) сервера в .txt файл. Строка под блоками показывает источник выбранной зоны
с составным форматированием (не просто серый текст): слова "Источник" и "мастер-серверы"
подчёркнуты, тип зоны (Primary/Secondary/Stub) и сами адреса мастер-серверов/путь к файлу -
жирным.
Несколько серверов одновременно: подключение к серверу (см. "Управление другим сервером удалённо" ниже) сохраняется на весь срок работы приложения, и это верно сразу для нескольких серверов параллельно - переключение между ними в дереве не разрывает подключение к остальным. Клик по узлу сервера в дереве сам переключает панель "Целевой DNS-сервер" сверху на него.
Добавление записи учитывает текущую папку - запись test внутри pro32connect станет
test.pro32connect. @ внутри папки = сама папка. Поля Priority/Weight/Port видны только
для SRV/MX.
Создание "папки": правая кнопка на scope/папке → диалог с выбором режима. По умолчанию -
wildcard-запись * внутри нового поддомена (*.sales → IP): и настоящая запись, и способ
сделать поддомен видимым как папку (папка появляется, только если у узла есть свои дочерние
узлы - сама по себе запись sales без вложенности останется обычной строкой, не папкой).
Второй вариант - буквально как "Новый домен" в dnsmgmt.msc (запись с именем ровно как
папка, без *) - с явным предупреждением: так папка не появится в дереве, пока внутри
неё нет ещё одной вложенной записи.
Файловый режим (значок с блокнотом) - обходной путь для Secondary-зон, где обычное
добавление падает с WIN32 9611: правка .dns-файла scope напрямую, всегда локально, с
бэкапом и dnscmd /ZoneReload. Explicit предупреждение при каждом использовании.
Экспорт записей в .txt - имя сервера, с которого сделана выгрузка (DnsHelper.ComputerName,
если задан целевой сервер, иначе имя локальной машины), попадает и в имя файла, и первой
строкой внутрь самого файла вместе с датой - чтобы файл был понятен и без контекста, откуда
он взялся.
Импорт записей из такого файла (значок со стрелкой вверх): строки-папки ([FLDR] имя N запис.) распознаются и не импортируются как записи - вместо этого предлагается создать
соответствующий субдомен через wildcard (с IP на каждый, по желанию). Есть чекбокс
"Исключить @-записи". Импорт идёт в текущую выбранную папку/scope (как и обычное
добавление). Значения SRV/MX разбираются обратно из составного текста в экспорте
(target:port (priority=..., weight=...) / exchange (preference=...)); если запись из
файла уже существует в scope (по имени+типу) - диалог конфликта показывает и существующее,
и новое значение рядом (сразу видно, это точный дубль или реально отличается IP/имя), и
спрашивает перезаписать или пропустить, с массовым вариантом ("всё") - после него дальнейшие
конфликты решаются автоматически без повторных вопросов. Список "что уже есть в scope"
обновляется по ходу самого импорта (не только один раз в начале) - если в файле есть
повторяющаяся запись, второй дубль тоже распознаётся как конфликт с тем, что уже добавлено
в этом же прогоне, а не улетает в DNS Server напрямую с ошибкой "запись уже существует".
Командлеты: A/AAAA/CNAME/PTR/MX - типизированные (Add-DnsServerResourceRecordA и т.д.).
NS/TXT/SRV - только универсальный Add-DnsServerResourceRecord -NS/-Txt/-Srv (выделенных
командлетов нет). @ в имени - запись в корне зоны.
Редактирование - пересоздание (сначала новая, потом старая, чтобы не терять данные при
сбое), кроме CNAME: DNS не даёт CNAME сосуществовать с другой записью под тем же именем
ни на секунду, поэтому порядок обратный (сначала удалить, потом добавить, с откатом при
неудаче). Удаление - через -InputObject с полным объектом записи; можно выделить сразу
несколько записей (обычное множественное выделение списком, правый клик внутри уже
выделенной группы не сбрасывает её) - одно подтверждение на всю группу, папки среди
выделенного игнорируются молча.
Прогресс операций: каждое успешное добавление/удаление/импорт записи - отдельная строка
в блоке вывода вида OK: запись "имя" (тип) значение добавлена в зону "...", scope "..."
(для удаления - аналогично), а не просто финальная сводка в конце.
Проверка записи - nslookup (Resolve-DnsName, вывод причёсан) и Ping (с -t,
источником -S, кодировкой CP866).
Get/Add/Remove-DnsServerClientSubnet. Имя + CIDR.
Get/Add/Remove-DnsServerQueryResolutionPolicy. У результата Get-... подсеть лежит в
Criteria, scope - в Content (не ClientSubnet/ZoneScope, это имена параметров у
Add-..., не свойств у Get-...). Несколько подсетей через запятую (логическое ИЛИ).
Подсети в описании политики показаны только именами, без CIDR в скобках - раньше рядом
с именем подставлялся реальный диапазон (net_100 (10.0.1.0/24)), но это "(...)" не часть
имени подсети, и при копипасте такой строки в поле "Подсети" нового диалога создания политики
получалась ошибка ("такой подсети не существует"). CIDR по-прежнему виден - на вкладке
"Подсети".
Важно, легко забыть: политики (как и клиентские подсети) не реплицируются на резервные контроллеры домена - привязаны локально к этому серверу/зоне. Поэтому одно и то же имя политики у разных зон - не конфликт (диалог создания политики напоминает об этом явным текстом).
Поле "Целевой DNS-сервер" сверху - все операции идут через -ComputerName, без переноса
приложения. Если проверка подключения текущей учёткой не проходит - открывается окно
аутентификации (логин/пароль), через New-CimSession -Credential (у командлетов DnsServer
своего параметра -Credential нет). Сессия кэшируется на весь срок работы приложения, и
это отдельно для каждого сервера - переключение между несколькими подключёнными серверами
(в том числе через дерево на вкладке "Scopes и записи") не разрывает подключение к остальным;
закрывается всё только при закрытии самого приложения.
Транспорт - обычный WinRM: Kerberos (домен) или NTLM через TrustedHosts на клиенте (не
домен) - то же самое, что Enter-PSSession. Пароль не хешируется перед отправкой (Kerberos/
NTLM сам challenge-response, хеширование сломало бы аутентификацию), строится в памяти сразу
как SecureString. Подробный разбор - SECURITY.md.
Если клиент не в домене:
Set-Item WSMan:\localhost\Client\TrustedHosts -Value "<сервер>" -Concatenate -ForceИстория последних 10 серверов - в settings.ini.
Запись - обычное да/нет. Зона/scope/подсеть/политика - усиленное окно с 5-секундной задержкой кнопки "Удалить".
- Автоподгрузка списков зон/scope при первом заходе на вкладку.
changes.logрядом с exe - только реальные изменения и попытки аутентификации, без пароля.- Диагностика ошибок: полное разворачивание CIM/PowerShell исключений; понятные
сообщения вместо сырых дампов для типичных случаев - "не DNS-сервер" (
WIN32 1722), "нужны права администратора" (см. выше), "WinRM не достучался" (TrustedHosts/файрвол/ сетевой профиль), "зона не поддерживает Zone Scopes" (WIN32 9603- зоны условной пересылки и похожие типы структурно не поддерживают scope'ы, это не временная проблема). - Обновления: кнопка в "О программе" тянет последний релиз с GitHub, сравнивает версию
(
AppVersion.cs), качает и ставит через.bat-скрипт (ждёт закрытия процесса черезtasklist, копируетrobocopy, перезапускает).settings.ini/changes.log/*.dnsне трогает. Нужен исходящий HTTPS доgithub.com.
- Скачай папку на сервер, открой
DnsToolWinForms.csprojв Visual Studio (2019/2022). - NuGet восстановится сам. Переключи на
Release, собери (Ctrl+Shift+B). - Готовый
.exe- вbin\Release\net48\. Копируется на сервер как есть, ничего дополнительно ставить не нужно (сборка PowerShell берётся из самой Windows).
Антивирус ругается на exe - ожидаемо для неподписанного exe, хостящего PowerShell:
подписать (signtool.exe), добавить в исключения, либо отправить как false positive.
NuGet не находит Microsoft.PowerShell.5.1.ReferenceAssemblies - в .csproj есть
закомментированный HintPath-блок на системную сборку, раскомментируй вместо
PackageReference.
Program.cs- точка входа.MainForm.cs- вся форма (разметка кодом, без .resx).DnsHelper.cs- обёртка над PowerShell: вызовы командлетов, разбор ошибок,CimSessionдля удалённой аутентификации, проверка элевации.IconFactory.cs/HelpIcon.cs- значки и подсказки (GDI+).*Dialog.cs- все диалоговые окна (создание зон/scope/записей/подсетей/политик, аутентификация, подтверждение удаления, проверка записи, "О программе").UpdateChecker.cs- обновления через GitHub.FileLogger.cs-changes.log.AppVersion.cs- версия приложения.SECURITY.md- разбор безопасности удалённого подключения со ссылками на код.
- Просмотр записей вне scope; более строгая валидация ввода (IP/CIDR).
- Создание зоны условной пересылки (conditional forwarder) с теми же опциями, что в
dnsmgmt.msc(Add-DnsServerConditionalForwarderZone) - сейчас в блоке "Управление зонами" можно создать только Primary (AD-интегрированную или файловую); зоны условной пересылки не поддерживают Zone Scopes вообще (см. диагностикуWIN32 9603выше), поэтому это отдельная, самостоятельная ветка функциональности, не пересекающаяся с остальной частью приложения.
MIT - используй, форкай, меняй как угодно, сохраняя авторство (LICENSE). Без гарантий:
инструмент пишет напрямую в DNS-конфигурацию, тестируй на некритичном окружении.
- USDT (TRC20/TRON):
TQp9az9Nbnojg65qwvRjhwRkEnwEfFHK77 - ETH (ERC20):
0x40d1775df43a9ff67aabe21ccb000421c0d6f092