Я искал простое решение, которое позволяло бы одной кнопкой удалённо включать и выключать компьютер.
С включением всё давно решено: отправляешь стандартный Wake‑on‑LAN magic packet — и компьютер запускается. Но с выключением оказалось сложнее. Готового и удобного варианта, который работал бы по такому же принципу, я не нашёл. Большинство решений требовали отдельного приложения, удалённого рабочего стола, SSH, умной розетки или установки целого комплекса для управления компьютером.
Хотелось, чтобы всё было максимально просто: одна и та же кнопка отправляет один и тот же Wake‑on‑LAN пакет. Если компьютер выключен — сетевая карта принимает пакет и включает его. Если Windows уже работает — пакет перехватывает фоновая служба и выключает компьютер.
В итоге я решил по‑быстрому накидать нужное решение с помощью нейросети. Получилась небольшая Windows‑служба, которая:
автоматически запускается вместе с Windows;
работает в фоне без открытых окон;
слушает выбранный UDP‑порт;
проверяет структуру Wake‑on‑LAN magic packet;
сверяет MAC‑адрес назначения;
выключает компьютер после получения правильного пакета.
Получается простой переключатель: один magic packet — компьютер меняет своё состояние. Если он выключен, то включается средствами Wake‑on‑LAN. Если включён — служба принимает тот же пакет и запускает штатное выключение Windows.
Служба уже работает на моём компьютере, поэтому решил привести проект в порядок и поделиться им со всеми. Исходники, инструкция по установке и готовая сборка опубликованы в репозитории WakeUpOnLan Shutdown.
Что представляет собой magic packet
Стандартный Wake‑on‑LAN пакет состоит из:
Шести байтов
FF.Шестнадцати повторений MAC‑адреса целевого устройства.
Минимальный размер такой последовательности — 102 байта:
FF FF FF FF FF FF AA BB CC DD EE FF AA BB CC DD EE FF ... MAC повторяется 16 раз
Служба не реагирует на любой пакет, прилетевший на UDP‑порт. Она ищет внутри полученных данных правильную последовательность и проверяет все 16 повторений MAC.
Упрощённо проверка выглядит так:
for (var offset = 0; offset <= packet.Length - 102; offset++) { if (!packet.Slice(offset, 6) .SequenceEqual(new byte[] { 255, 255, 255, 255, 255, 255 })) { continue; } var mac = packet.Slice(offset + 6, 6); for (var repetition = 1; repetition < 16; repetition++) { if (!packet .Slice(offset + 6 + repetition * 6, 6) .SequenceEqual(mac)) { return false; } } return true; }
Дополнительно MAC из пакета сравнивается с MAC сетевого адаптера компьютера. Если MAC не задан вручную, служба находит интерфейс по указанному локальному IP и определяет его физический адрес автоматически.
Таким образом, WoL‑пакет для другого устройства не приведёт к выключению ПК.
Прослушивание UDP
Адрес и порт задаются в appsettings.json:
{ "BindAddress": "192.168.1.50", "Port": 9, "TargetMac": "", "ShutdownDelaySeconds": 10, "ForceCloseApplications": false, "FirewallRemoteAddress": "Any" }
Служба создаёт UDP‑сокет и привязывается к конкретному локальному адресу:
using var udp = new UdpClient(AddressFamily.InterNetwork); udp.Client.Bind( new IPEndPoint(bindAddress, settings.Port) ); var received = await udp.ReceiveAsync(cancellationToken);
Привязка к конкретному IP помогает избежать неоднозначности на компьютерах с несколькими сетевыми адаптерами.
Если при старте Windows сеть ещё не поднялась или адрес временно отсутствует, служба не завершается окончательно, а повторяет попытку через 15 секунд.
Выключение Windows
После получения корректного пакета запускается стандартная системная команда:
shutdown.exe /s /t 10
По умолчанию я оставил задержку 10 секунд. За это время выключение можно отменить:
shutdown /a
Принудительное закрытие приложений отключено. Его можно включить параметром:
"ForceCloseApplications": true
Но в этом режиме возможна потеря несохранённых данных.
Почему именно Windows‑служба
Обычную программу пришлось бы добавлять в автозагрузку и запускать после входа пользователя. Windows‑служба работает независимо от интерактивного сеанса и стартует вместе с системой.
Служба устанавливается с типом запуска Automatic и работает от имени LocalSystem. Для взаимодействия с диспетчером служб используются функции Windows API:
StartServiceCtrlDispatcher(...) RegisterServiceCtrlHandlerEx(...) SetServiceStatus(...)
Такой вариант позволил не добавлять отдельные NuGet‑зависимости для Windows Services.
Приложение также поддерживает консольный режим:
.\WakeOnLanShutdown.exe --console
Он удобен для диагностики до установки службы.
Установка на другой компьютер
В разделе Releases находится готовая автономная сборка для Windows x64.
После распаковки нужно открыть appsettings.json и указать постоянный локальный IP компьютера:
"BindAddress": "192.168.1.50"
Лучше не назначать статический адрес непосредственно в Windows, а создать DHCP reservation на роутере. Тогда компьютер продолжит получать сетевые настройки автоматически, но всегда будет получать один и тот же IP.
После настройки нужно открыть PowerShell от имени администратора и выполнить:
Set-ExecutionPolicy -Scope Process Bypass .\install.ps1
Установщик:
копирует программу в
C:\Program Files\WakeOnLanShutdown;создаёт службу
WakeOnLanShutdown;включает автоматический запуск;
настраивает перезапуск после сбоя;
создаёт входящее правило брандмауэра Windows;
запускает службу.
Проверить состояние можно так:
Get-Service WakeOnLanShutdown Get-NetUDPEndpoint -LocalPort 9
Журнал находится здесь:
C:\ProgramData\WakeOnLanShutdown\service.log
Доступ через интернет
Если отправлять пакет не только из локальной сети, на роутере потребуется перенаправление UDP‑порта:
Внешний UDP-порт → локальный IP компьютера → порт 9
Например:
UDP 40009 → 192.168.1.50:9
В приложении‑отправителе тогда указывается публичный IP или DDNS‑имя роутера, внешний порт 40009 и MAC компьютера.
Внешний порт необязательно делать девятым. Нестандартный номер немного уменьшит количество случайного сетевого шума, хотя полноценной защитой это не является.
Если провайдер использует CG‑NAT, обычный port forwarding работать не будет. В таком случае нужен публичный IP либо VPN с доступом в домашнюю сеть.
Важный момент о безопасности
Wake‑on‑LAN не содержит нормальной аутентификации. MAC‑адрес — это идентификатор устройства, а не секретный пароль.
Если открыть UDP‑порт всему интернету, любой человек, узнавший MAC компьютера, теоретически сможет отправить подходящий пакет и инициировать выключение.
Поэтому для постоянного использования лучше:
подключаться к домашней сети через WireGuard или Tailscale;
не публиковать UDP‑порт напрямую;
либо ограничить
FirewallRemoteAddressсвоим постоянным внешним IP:
"FirewallRemoteAddress": "203.0.113.10"
Можно также указать CIDR‑подсеть.
Сборка из исходников
Для самостоятельной сборки нужен.NET 8 SDK:
git clone https://github.com/nikostap/WakeUpOnLan\_Shutdown.git cd WakeUpOnLan_Shutdown Set-ExecutionPolicy -Scope Process Bypass .\build.ps1
Скрипт создаёт self‑contained сборку для win-x64. На целевом компьютере устанавливать.NET Runtime не требуется.
Перед установкой можно запустить встроенный тест проверки пакетов:
.\publish\WakeOnLanShutdown.exe --self-test
Ожидаемый результат:
Self-test: OK
Удаление
Для удаления службы и правила брандмауэра достаточно выполнить от имени администратора:
.\uninstall.ps1
Установленные файлы намеренно не удаляются автоматически, чтобы случайно не потерять конфигурацию.
Что получилось
В результате получилась небольшая автономная Windows‑служба без внешней инфраструктуры и сторонних серверов. Она запускается вместе с системой, почти не требует обслуживания и использует обычный Wake‑on‑LAN пакет в качестве сигнала для выключения.
Исходники, инструкция и готовая сборка опубликованы на GitHub:

