вторник, 24 июля 2018 г.

Wake-on-LAN и Powershell

У администраторов, часто бывают ситуации, когда надо включить компьютер, а физического доступа к нему нет. Например чтобы проводить в не рабочее время обновления системы или провести очередную проверку на наличие вирусов.

Сначала немного о Wake-on-LAN:
Wake-on-LAN — технология позволяющая включить компьютер, с помощью сетевой карты.
Для того, что бы это удалось сетевая карта данного компьютера должна получить «Magic packet».
На практике для этого компьютер должен удовлетворять следующим требованиям:
Блок питания должен соответствовать стандарту ATX 2.01
Материнская плата должна поддерживать Wake-on-LAN
Сетевая плата должна поддерживать Wake-on-LAN, если сетевая плата внешняя и не соответствует стандарту PCI 2.2 то необходим специальный трёхжильный кабель, для соединения разъёмов Wake-on-LAN на материнской плате и на сетевой карте.
Так же соответствующие настройки должны быть включены, как в биосе материнской платы, так и в драйверах сетевой карты.
На практике все современные компьютеры поддерживают эти технологии. Поэтому вопрос может возникнуть о включении Wake-on-LAN для этого рекомендую почитать инструкцию к материнской плате.
Так же следует учесть, что сетевая карта должна «слушать» сеть в ожидании «Magic packet». Для этого интерфейс ACPI не должен переходить в состояние G3, то есть в механическое выключение системы. Это может произойти при сбое питания компьютера.
Например:
Выключение компьютера из «розетки».
Аварийное выключение (зажатие кнопки питания на 10 секунд).
Выключение компьютера с блоком питания AT.
Что же такое Magic packet?
Это 6 байт забитых «0xFF» — называемые цепочкой синхронизации.
И дальше 96 байт, в которых mac адрес включаемого компьютера повторяется 16 раз.
Всё это можно упаковать в UDP или IPX пакет. Обычно используется UDP.
Следовательно, если компьютер с которого отсылается «Magic packet» и компьютер который мы хотим включить по Wake-on-LAN находится в одной подсети. То нам надо  знать mac адрес сетевой карты включаемого компьютера.
Если нам надо разбудить компьютер в другой подсети, то нам так же надо знать ip адрес который может переслать broadcast в подсеть с включаемым компьютером. В качестве такого ip может выступать ip самого включаемого компьютера, тогда UDP пакет уйдёт к нужному компьютеру. Однако у меня этот вариант не сработал из за частой очистки ARM таблицы на маршрутизаторах. Это выглядело так, что через некоторое время компьютер переставал включаться.
И так все технические моменты решены и нам надо сформировать «Magic packet».

Сформировать «Magic packet» можно следующим скриптом на Powershell:

# Здесь мы в переменную заносим мак адрес включаемого компьютера. Разделителем указываем «-»
$Mac='01-2C-34-4C-1C-12'
# Указываем ip адрес который сможет доставить наш пакет до сетевого интерфейса нашего компьютера если #компьютеры находятся в одной подсети, то это может быть ip адрес broadcast настроенный на сетевой карте #текущего компьютера ([System.Net.IPAddress]::Broadcast). Если же компьютеры находятся в разных подсетях, то #указываем либо ip адрес компьютера который надо включить, либо ip адрес через который можно переслать #broadcast в другую подсеть.

$BroadcastProxy=[System.Net.IPAddress]::Broadcast

#Указываем порт(группу портов) по которому будет пересылаться пакет, в нашем варианте пакеты будут #отсылаться через порт 0, порт 7 и порт 9.
$Ports = 0,7,9

#Создаём цепочку синхронизации «Magic packet»
$synchronization = [byte[]](,0xFF * 6)

# Преобразовываем mac адрес в тип [byte], если вы хотите изменить разделитель в mac адресе, например на ‘:’, то следует изменить ‘-‘ на ‘:’ то есть данная #строчка будет выглядеть следующим образом:
$bmac = $Mac -Split '-' | ForEach-Object { [byte]('0x' + $_) }

# Формируем пакет данных, где в начале идёт цепочка синхронизации, а потом 16 раз повторяется мак адрес.
$packet = $synchronization + $bmac * 16

#Запускаем конструктор класса UdpClient
$UdpClient = New-Object System.Net.Sockets.UdpClient

# Для каждого из портов, устанавливаем соединение с ip = BroadcastProxy и портом = port, далее отправляем #данные из packet количеством байт = packet.Length. Сообщение с результатом функции .Send не показываются #(отсылаются в Out-Null).
ForEach ($port in $Ports) {$UdpClient.Connect($BroadcastProxy, $port)
    $UdpClient.Send($packet, $packet.Length) | Out-Null}

#Закрываем соединение.

$UdpClient.Close()

Источник: здесь

Комментариев нет:

Отправить комментарий