Содержание статьи
Находясь далеко от консоли, часто возникает необходимость в удаленном управлении машиной. Посмотреть работающие процессы, завершить сеанс пользователя, перезапустить зависший демон, запустить скрипт или перезагрузить хост. Для удаленного управления форточками на сегодня существует стандартное подключение к удаленному рабочему столу по протоколу RDP и множество ПО от сторонних производителей. Однако эти способы требуют отдельного подключения к каждому управляемому объекту, а также установки на них серверных частей, что зачастую блокируется антивирусным ПО (впрочем, о чем это я, ведь мы планируем управлять исключительно своей личной машиной?).
Но при подключении к своему компьютеру с помощью публичной точки доступа вероятен облом — некоторые порты TCP могут быть запрещены. Выход из этой ситуации я нашел в решении построить web-сайт, который будет размещен либо на управляемой машине, либо на любой машине домена, на которой запущен сервер с админскими правами.
Естественно, доступ к сайту ограничим паролем, а подключаться к нему будем по протоколу SSL.
К делу!
В качестве web-сервера применяется сборка "Денвер" (джентльменский набор web-разработчика) с PHP интерпретатором версии 5.2. Развернем web-сервер на управляемой машине, либо на любой машине домена под учеткой с административными правами доменного админа.
Денвер устанавливается крайне просто — на сайте разработчика есть подробная инструкция. В моём случае я просто установил диск с папками web-сервера как диск A, подключающийся при старте системы (флоппи-дисковода у меня нет и в BIOS он отключен). Каталог www, показанный на рисунке "Содержимое нашего каталога", будет содержать файлы (php-скрипты) нашей системы удаленного управления.
Для обеспечения безопасности доступа к сайту управления необходимо в каталоге WWW разместить файлы .htaccess и .htpasswd со следующим содержимым (для .htaccess):
<Files .htpasswd>
deny from all
</Files>
AuthType Basic
AuthName "Private zone. Only for Administrators!"
AuthUserFile a:homelocalhostwww.htpasswd
require valid-user
Здесь мы прописываем тип аутентификации (базовая) и путь к файлу с паролями.
Файл .htpasswd содержит зашифрованные пароли пользователей (файл создается с помощью утилиты htpasswd.exe из комплекта дистрибутива WEB-сервера Apache), вот пример его содержимого:
wmimin:$apr1$gg1.....$Si…p0RHtOvEsQzAkg3Y0
wmioper:$apr1$JxT6./..$X…WF94oRqOlKXRKsKrU0
У меня используются два юзера — в дальнейшем первый имеет право на перезагрузку и отключение машин, а второй — не имеет.
Если у тебя нет фиксированного IP-адреса, то для того, чтобы наш сайт управления был виден извне, необходимо зарегистрироваться на dyndns.com (либо аналогичном сайте, предоставляющем услугу динамического DNS), а затем в настройках маршрутизатора (например, для DLink при ADSL подключении) прописать полученный логин и пароль.
Для доступа снаружи на наш web-сервер необходимо также добавить IP-машины с сайтом в DMZ-зоне.
Разбираем принцип работы
Теперь расскажу о том, как осуществляется мониторинг либо управление машинами через наш сайт. Для этого мы используем подключение из PHP к подсистеме WMI виндовых машин посредством создания новых COM-объектов.
WMI (инструментарий управления осями Windows) предоставляет нам возможность подключаться к следующим провайдерам:
- Dsprov.dll, провайдер каталога Active Directory (Active Directory provider), позволяет обращаться к Active Directory как к объекту WMI;
- Ntevt.dll, провайдер журнала событий (Event Log provider), дает возможность управлять журналом событий;
- Wbemperf.dll, провайдер системных счетчиков (Perfomance Counter provider) — обеспечивает доступ к счетчикам произоводительности;
- Stdprov.dll, провайдер реестра (Registry provider), позволяет осуществлять чтение и изменение реестра;
- Snmpincl.dll, провайдер SNMP-устройств (SNMP provider), открывает шлюз доступа к SNMP (Simple Network Management Protocol);
- Wmiprov.dll, провайдер драйверов устройств (WDM provider), дает возможность получать информацию низкого уровня о драйверах устройств Windows Driver Model (WDM);
- Cimwin32.dll, провайдер подсистемы Win32 (Win32 provider), обеспечивает доступ к информации о компьютере, ОС, подсистеме безопасности, дисках, периферийных устройствах, файловых системах, файлах, папках, сетевых ресурсах, принтерах, процесах, сервисах и так далее;
- Msiprov.dll, провайдер установленного ПО (Windows Installer provider) — позволяет получать информацию об установленном ПО.
Для вывода на web-страницу информации о текущем состоянии машины (память, процессы, службы), а также для выполнения некоторых административных действий необходимо написать функции, которые будут вызываться с параметрами (имя машины или IP-адрес), а затем выводить результат своей работы в соответствующее поле web-страницы. Самые интересные и используемые в рамках нашего проекта функции будут требовать обращения к провайдерам подсистемы Win32 и провайдеру реестра.
Работаем с реестром удаленно
На сегодня у меня реализованы как мониторинговые, так и управляющие функции. Из мониторинговых стоит выделить функцию получения и вывода информации о версии BIOS, производителе и модели материнской платы. Данный функционал реализуется с помощью создания нового COM-объекта подключением к провайдеру StdRegProv подсистемы WMI. Все рассмотренные функции вызываются с переменной $server, которая содержит имя управляемой удаленной машины в локальной сети либо ее IP-адрес:
$obj = new COM('winmgmts:{impersonationLevel=impersonate}//'
.$server.'/root/default:StdRegProv’);
$obj->getStringValue(HKLM,$keypath1,$keyvalue_def,$key);
echo "BIOS release date: ".$key."rn";
$obj->getStringValue(HKLM, $keypath2,$keyvalue_mb_model, $key);
echo "Mainboard model: ".$key ."rn";
Таким образом, после создания нового COM-объекта методом getStringValue мы читаем раздел реестра HKLM (выбор раздела реестра задается константой, в нашем случае — объявлением define('HKLM',0x80000002);). При необходимости читать другие разделы реестра указываем другие константы:
Const HKEY_CLASSES_ROOT = 0x80000000
Const HKEY_CURRENT_USER = 0x80000001
Const HKEY_LOCAL_MACHINE = 0x80000002
Const HKEY_USERS = 0x80000003
Const HKEY_CURRENT_CONFIG = 0x80000005
В результате работы скрипт выводит нам следующие данные (в моем случае):
BIOS release date: 04/30/10
Mainboard manufacturer: Gigabyte Technology Co., Ltd.
Mainboard model: G31M-ES2L
Кроме используемого метода getStringValue существуют дополнительные методы работы с провайдером StdRegProv, среди них:
- GetBinaryValue — чтение значений типа BINARY;
- GetDWORDValue — чтение значений типа DWORD;
- GetExpandedStringValue — чтение значений типа EXPANDED STRING;
- GetMultiStringValue — чтение значений типа MULTI STRING;
- CreateKey — создание ключа реестра;
- SetBinaryValue — запись значения типа BINARY;
- SetDWORDValue — запись значения типа DWORD;
- SetExpandedStringValue — запись значения типа EXPANDED STRING;
- SetMultiStringValue — запись значения типа MULTI STRING;
- SetStringValue — запись строкового значения;
- DeleteKey — удаление ключа;
- DeleteValue — удаление значения ключа;
- EnumKey — получить перечисление ключей реестра;
- EnumValues — получить перечисление значений ключей;
- CheckAccess — проверка прав доступа к ключу реестра.
В данном случае они не используются, а подробнее узнать об их применении можно в великом MSDN.
Мониторим систему удаленно
Для осуществления функций мониторинга системы потребуется работать с пространством имен WMI (/root/cimv2), что даст нам возможность обращаться к необходимым провайдерам Win32_Processor, Win32_OperatingSystem, Win32_PerfFormattedData_PerfOS_System, Win32_OperatingSystem, Win32_Process, Win32_Service.
Итак, получаем информацию о центральном процессоре системы (CPU), включая его загрузку в процентах и данные CPUID, для этого сделаем так:
$obj = new COM ('winmgmts:{impersonationLevel=impersonate}//'
.$server.'/root/cimv2');
$pc = 0;
foreach ($obj->instancesof('Win32_Processor') as $mp)
{
echo "Processor (".++$pc.")rn";
echo "Name: ".trim( $mp->Name )." @ " .
$mp->CurrentClockSpeed . " MHzrn";
echo "CPU Load: ".$mp->LoadPercentage . "%rn";
}
Здесь мы создаем новый COM-объект и, обращаясь к методам провайдера Win32_Processor, получаем нужную нам информацию:
Processor (1)
Processor Id: BFEBFBFF0001067A
Name: Pentium(R) Dual-Core
CPU E5300 @ 2.60GHz @ 1196 MHz
CPU Load: 18%
CPU Status: OK
CPU Stepping:
CPU Revision: 5898
System Name: GUZY
Данные о температуре процессора мы можем получить, обратившись к пространству имен /root/WMI и провайдеру MSAcpi_ThermalZoneTemperature. Получение актуальной температуры CPU работает не на всех материнских платах ПК, зато прекрасно работает на ноутах.
Работа с пространством имен /root/WMI и провайдером MSAcpi_ThermalZoneTemperature:
$obj = new COM ('winmgmts:{impersonationLevel=impersonate}//'
.$server.'/root/WMI');
foreach($obj->instancesof ('MSAcpi_ThermalZoneTemperature') as $mp)
{
echo "<pre>rn";
$ctemp=($mp->CurrentTemperature);
echo "<b>Current CPU temperature: " . ( $ctemp — 2732)/10 . "C" . "rn";
}
Здесь перед выводом на страницу мне пришлось перевести температуру из кельвинов в привычные русскому глазу единицы Цельсия. Двигаемся дальше и с помощью старого доброго пространства имен /root/cimv2 получаем информацию об установленной оси, сервис-паках и аптайме. Здесь использованы методы провайдеров Win32_OperatingSystem и Win32_PerfFormattedData_PerfOS_System. Для перевода секунд при отображении uptime используется функция format_time($temp).
Выводим параметры OS’и и uptime:
foreach($obj->instancesof('Win32_OperatingSystem') as $mp )
{
$temp=($mp->Name);
echo "OS name: " .substr($temp,0,-40). "rn";
$temp2=($mp->ServicePackMajorVersion);
echo "Service pack: " . $temp2 . "rn";
}
foreach ($obj->instancesof('Win32_PerfFormattedData_PerfOS_System') as $mp)
{
$temp=($mp->SystemUpTime);
echo "System uptime: ".format_time($temp)."rn";
}
Результаты работы наших скриптов:
OS name: Microsoft Windows Server 2008 R2 Enterprise
Service pack: 0
System uptime: 23hour 32min 42sec
Таким образом, с помощью языка PHP в связке с WMI мы можем получать любую информацию о ПК удаленно.
Рулим виндами удаленно
Для реализации перезагрузки ПК необходимо обратиться к пространству имен /root/cimv2 и вызвать метод Reboot провайдера Win32_OperatingSystem. Для завершения работы необходимо вызвать метод ShutDown.
Удаленная перезагрузка системы:
$obj = new COM('winmgmts:{impersonationLevel=impersonate,(Shutdown)}//'
.$server.'/root/cimv2');
foreach($obj->instancesof('Win32_OperatingSystem') as $mp)
{
echo "<pre>rn";
echo "<b>Rebooting immediatelyrn</b>rn</pre>";
$ctemp=($mp->Reboot);
}
Для просмотра запущенных служб:
$process = $obj->execquery("SELECT * FROM Win32_Service");
foreach ( $process AS $row )
{
echo "<pre>rn";
echo "NAME: " . $row->Name .",
rnDISPLAY NAME:".strtolower($row->DisplayName).",
rnPATH: " . strtolower($row->PathName ). ",
rnSTATE: " . strtolower($row->state )."<br/>";
}
Для просмотра процессов:
$process = $obj->execquery("SELECT * FROM Win32_Process");
if ( $process->count > 0 )
{
foreach ( $process AS $row )
{
echo "<pre>rn";
echo "PID: ".$row->processid.",
rnPROCESS NAME: ".strtolower( $row->name ).",
rnMEMORY USAGE: ".number_format
( $row->workingsetsize )."<br/>";
}
}
Для запуска или остановки служб используем методы StartService и StopService объекта Win32_Service:
$process = $obj->execquery("SELECT * FROM Win32_Service Where Name='$servicesname'");
foreach ($process AS $row)
{
$row->StartService();
echo "Service started!";
}
А вот для запуска процессов придется использовать метод Create объекта win32_process:
$obj_win32_process=new COM('winmgmts:{impersonationLevel=impersonate}//'
.$server.'/root/cimv2:Win32_Process');
$obj_win32_process->Create($processname,Null,Null,lngProcessID2);
echo "Process created!";
Заключение
Таким образом, используя все возможности WMI-провайдеров из PHP, можно получать и публиковать на web-сайте любую информацию об удаленных машинах, а также практически без ограничений ими управлять, манипулируя процессами, службами и реестром. В рамках статьи показаны лишь наиболее простые варианты применения связки PHP и WMI для удаленного мониторинга и управления Windows-системами. В исходниках ты найдешь пример получения PTR (pointer) записей домена (файл dns_ptr.php), реализованный с помощью использования пространства имен /root/MicrosoftDNS и провайдера MicrosoftDNS_PTRType. Вся эта система у меня реализована в виде web-сайта с подключаемыми модулями-функциями.
В общем, теперь все рычаги управления Windows-системами c помощью php-интерпретатора в твоих руках — пользуйся, но не в деструктивных целях!