По умолчанию администратор может получить информацию о системе, на которой работает «блуждающий пользователь», путем фильтрации журналов безопасности на контроллерах домена. Однако это решение работает слишком медленно и весьма высока вероятность возникновения ошибки, особенно если в системе два или более объемных журнала безопасности. Вместо этого для получения нужных сведений можно использовать один из двух методов. Если в сети не очень много систем, можно просто опросить каждый компьютер и узнать, зарегистрирован ли на нем данный пользователь. С другой стороны, по распоряжению администратора пользователи могут сообщать центральному серверу имя системы, на которой они зарегистрированы. Подобное уведомление может быть частью сценария регистрации для «блуждающих пользователей». Давайте разберем, как можно реализовать каждую из этих стратегий и рассмотрим их преимущества и недостатки.

Стратегия опроса

Если компьютеров в сети немного (менее 50), опрос каждого компьютера – самый простой способ обнаружить систему, на которой зарегистрировался перемещающийся пользователь. Один из вариантов – задействовать команду Net View для получения списка компьютеров сети, после чего запустить либо команду Nbtstat, либо утилиту PsLoggedOn компании Sysinternals, чтобы опросить каждую систему и проверить, не зарегистрирован ли на ней данный пользователь. Утилита PsLoggedOn является частью свободно распространяемого пакета PsTools компании Sysinternals, который можно найти на сайте http://www.sysinternals.com.

Команда Nbtstat использует службу NetBIOS по протоколу TCP/IP (NetBT), чтобы отобразить статистику протокола и текущие подключения TCP/IP. Параметр –а команды Nbtstat позволяет получить таблицу имен для любой указанной удаленной системы. Следует иметь в виду, что параметры команды Nbtstat чувствительны к верхнему и нижнему регистру клавиатуры. На выходе команды Nbtstat -a служба Messenger работает с именами, дополненными записью <03>. Кроме того, если пользователь авторизуется под учетной записью домена, на выходе появится запись с ID данного пользователя. Таким образом, можно определить, на какой системе зарегистрирован пользователь, запустив команду Nbtstat -a для списка компьютеров и применив команду Findstr для поиска на выходе записи <03>, которая соответствует указанному имени пользователя.

Используя данный подход, я создал сценарий FindUser.cmd, приведенный в Листинге 1. Этот сценарий можно использовать на системах Windows XP, Windows 2000 и Windows NT 4.0. Чтобы запустить сценарий, нужно ввести команду

finduser.cmd username

где username – имя перемещающегося пользователя; по нему производится поиск. Сценарий хранит значение параметра username в переменной usertofind.

Цикл For, показанный в блоке A Листинга 1, использует команду Net View для получения списка компьютеров сети. Команда Net View возвращает имена систем в формате «computername» (например, WKSTN1), а также другую информацию, например заголовки. Поскольку нас интересуют только имена компьютеров, команда Find очищает выходные данные команды Net View и оставляет только те строки, которые содержат символы «».

Для каждого имени системы сценарий запускает код с меткой :findit, приведенный в блоке B. Этот код определяет, зарегистрировался ли на данном компьютере искомый пользователь. Сначала этот код записывает значение «computername» из цикла For в переменную target. Поскольку команда Nbtstat требует, чтобы имена компьютеров были приведены без символов «», строка

Set target=%target:=%

убирает символы «» и записывает отредактированное имя системы в ту же переменную target. В результате переменная target содержит только имя компьютера.

Далее, код с меткой :findit запускает команду Nbtstat -a для имени компьютера, хранящегося в переменной target. Код передает выходные данные команды Nbtstat -a на вход команды Findstr /i, которая ищет среди этих данных строку, хранящуюся в переменной usertofind. Параметр /i отключает чувствительность к регистру. По умолчанию команда Findstr возвращает любые строки, содержащие указанное имя. Код фрагмента с меткой:findit перенаправляет выходные данные команды Findstr /i на указатель NUL, поскольку эта информация вам больше не понадобится. Вместо этого необходимо определить, успешно ли выполнена команда Findstr. Большинство команд, используемых при написании сценариев, в ходе работы возвращают номер или уровень ошибки. Можно использовать команду If с условием Errorlevel, чтобы определить, успешно ли была выполнена предыдущая команда. Уровень ошибки - 0 означает успешное выполнение, а уровень ошибки -1 или выше означает сбои при выполнении команды. В нашем случае, если переменная %ERRORLEVEL% равна 0, значит, команда Findstr нашла совпадение со значением из переменной usertofind, и код с меткой :findit выведет на экран имя компьютера, на котором зарегистрирован данный пользователь. Нужно иметь в виду, что данный метод не работает, если отключена служба Messenger, если тип <03> UNIQUE содержит имя компьютера вместо имени пользователя, или если отключена служба NetBT.

Чтобы использовать утилиту PsLoggedOn вместо команды Nbtstat, можно адаптировать сценарий FindUser.cmd. Для этого надо просто поместить утилиту PsLoggedOn в ту же папку или по тому же системному пути, что и сценарий, после чего заменить команду Nbtstat:

Nbtstat -a %target% | Findstr /i 
"%usertofind%" > NUL

командой psloggedon.exe

Psloggedon.exe -L 
\%target% | findstr /i
"%usertofind%" > NUL

Хотя команда psloggedon.exe здесь разбита на несколько строк, ее следует ввести одной строкой в сценарии FindUser.cmd. Параметр -L указывает, что вы хотите, чтобы утилита возвращала только учетные записи, с которыми локально зарегистрировались на указанном компьютере. По умолчанию команда PsLoggedOn также отображает учетные записи, через которые удаленно подсоединяются к компьютеру, например через общие сетевые папки.

Команды psloggedon.exe и Nbtstat дают одни и те же результаты, но есть несколько незначительных отличий в механизме работы. Сценарий FindUser.cmd не проверяет, включен компьютер или нет, перед тем как пытаться определить, зарегистрирован ли пользователь на системе. И утилита psloggedon.exe, и команда Nbtstat в итоге прекращает опрос, если опрашиваемый узел недоступен. Однако команда Nbtstat имеет преимущество, так как она прерывает работу не более чем на 2 секунды, в то время как утилита psloggedon.exe может простаивать до 7 секунд, прежде чем прекратит обращение к узлу. Эти дополнительные секунды могут существенно сказаться на быстродействии сценария. Однако преимущество утилиты PsLoggedOn заключается в том, что она работает с пользователями, которые регистрируются в системе под учетной записью службы или локального компьютера.

Следует иметь в виду, что можно также использовать утилиту PsLoggedOn из командной строки, а не из сценария FindUser.cmd. Чтобы провести поиск компьютера, на котором зарегистрирован пользователь, необходимо открыть окно командной строки и запустить команду

psloggedon.exe username

где username - имя перемещающегося пользователя, по которому проводится поиск.

Стратегия уведомления

Вторая стратегия обнаружения перемещающихся пользователей заключается в том, чтобы потребовать от пользователей уведомлять администратора о том, на какой системе они зарегистрированы. Самый простой способ – создать централизованную общую папку на одном из серверов, и заставить пользователей прописывать в текстовом файле, который будет храниться в данной папке, имя компьютера, на котором они зарегистрированы. Можно оптимизировать данный процесс, воспользовавшись приложением now.exe и изменив сценарий регистрации перемещающихся пользователей.

Приложение Now – это утилита из набора ресурсов Microsoft, которая выводит указанный текст, так же, как команда Echo, за тем лишь исключением, что служба now.exe добавляет в начало строки отметку времени. Так как приложение now.exe является утилитой из набора ресурсов Microsoft, потребуется скопировать ее в общую папку регистрации или в другую папку, входящую в область поиска перемещающихся пользователей.

Преобразовать сценарий несложно. Например, если на сервере с именем Server1 существует общая папка Logs, можно добавить следующую команду в сценарий регистрации:

Now.exe Logged on to 
%computername% >>
server1logs\%username%.txt

Хотя здесь эта команда разбита на несколько строк, в сценарии регистрации ее необходимо записать одной строкой. Каждый раз при регистрации перемещающегося пользователя сценарий регистрации добавляет строчку к текстовому файлу, с именем .txt, где - имя данного пользователя. Строка содержит время регистрации пользователя и имя компьютера, на котором эта регистрация произошла. Например, команда now.exe может добавить строку «Sat May 03 22:28:18 2003 -Logged on to WKSTN1» к файлу msmith.txt в общей папке Logs на сервере Server1.

Метод уведомлений через текстовый файл достаточно прост, и в этом его преимущество. Администратору требуется добавить в сценарий регистрации всего одну строчку кода, и поиск системы, на которой зарегистрирован пользовать, будет сведен к открытию текстового файла, названием которого является имя пользователя в системе. Этот метод также достаточно хорошо масштабируется, поэтому пригоден для использования в крупных организациях.

Другой метод уведомления заключается в хранении данных о регистрации в центральной базе данных, такой как служба Active Directory (AD). Так как данный метод хранит информацию в полях базы данных, можно через приложение сделать запрос по данной информации. Например, можно создать приложение Active Server Pages (ASP), которое сначала опрашивает службу AD и получает данные о компьютерах, на которых зарегистрированы путешествующие пользователи, после чего отображает эти значения на web-странице.

Для регулярно регистрирующихся пользователей большинство полей (или атрибутов) в службе AD доступны только для чтения. Исключениями являются атрибут wwwHomePage и связанный с ним многозначный атрибут url. Не только регулярно аутентифицирующиеся пользователи могут задавать атрибуты wwwHomePage и url; эти атрибуты видимы и изредка используются и через оснастку Active Directory Users and Computers консоли Microsoft Management Console (MMC). Таким образом, можно использовать оснастку Active Directory Users and Computers для поиска системы перемещающегося пользователя. Значение атрибута wwwHomePage отображается в поле Web Page диалогового окна Properties для данного пользователя, а значение атрибута url – в поле Web Page Addresses (Others).

Я создал модуль LogUser, который использует атрибуты wwwHomePage и url. Можно добавить этот код в сценарий регистрации перемещающихся пользователей для того, чтобы информация обновлялась при каждой регистрации таких пользователей. Принцип работы модуля LogUser заключается в опросе AD и получении данных о пользовательском объекте, который представляет текущего пользователя. Если существует старое значение атрибута wwwHomePage данного объекта (то есть модуль LogUser ранее использовался для данного пользователя), модуль копирует значение атрибута wwwHomePage в атрибут url. После этого модуль записывает в качестве значения атрибута wwwHomePage имя компьютера, на котором пользователь зарегистрирован в данный момент.

Модуль LogUser приведен в Листинге 2. Код модуля LogUser начинается обычными объявлениями переменных и выражениями обработки ошибок, после чего в переменную rootDN записывается корневая папка домена. Далее модуль получает указатель на объект WScript.Network и связывает этот указатель с переменной wshNetwork. В дальнейшем модуль использует этот указатель для определения уникального имени (DN) пользователя, запустившего сценарий регистрации, и имени компьютера, на котором данный сценарий был запущен.

Далее модуль LogUser создает экземпляр объекта ADODB.Connection, который используется для обращения к службе AD. После установки соединения модуль выполняет запрос, и, в случае успешного выполнения, возвращает уникальное имя пользователя, запустившего сценарий регистрации. Запрос осуществляет поиск значения атрибута sAMAccountName, который бы соответствовал имени данного пользователя (атрибут sAMAccountName службы AD хранит имя пользователя в системе.). Если модуль не находит совпадения, он отображает сообщение No Match и завершает работу. Если модуль находит совпадение, он записывает значение атрибута distinguishedName для данного пользователя (то есть уникальное имя пользователя) в переменную dn. Модуль использует переменную dn в качестве параметра функции etObject, чтобы получить указатель на объект, представляющий текущего пользователя. Программа сохраняет этот указатель в переменной oUser.

Модуль LogUser считывает и копирует значение атрибута wwwHomePage пользовательского объекта в переменную lastLogon. Если атрибут wwwHomePage уже содержит значение (то есть модуль LogUser ранее использовался для данного пользователя), модуль копирует существующее значение переменной lastLogon в атрибут url, а, следовательно, у вас есть возможность хранить список компьютеров, на которых зарегистрировался пользователь. В конце модуль записывает в атрибут wwwHomePage имя компьютера, на котором зарегистрирован пользователь, и задействует метод SetInfo для подтверждения изменений в службе AD.

Я тестировал модуль LogUser на системе с Windows 2000 Service Pack 3 (SP3). Перед тем как добавить код модуля LogUser в свой сценарий регистрации, необходимо модифицировать строку, приведенную в блоке A Листинга 2. В этой строке следует заменить значения DC=DOMAIN,DC=COM именем корня домена.

Метод уведомления через базу данных является более медленным и более сложным, чем метод уведомления через текстовый файл. Однако этот метод более гибкий, так как позволяет собирать информацию о системе из других служб.

Несмотря на функциональную полноту, метод уведомления через базу данных может иметь ограниченное применение в определенных средах. Так как модуль LogUser обновляет службу AD при каждой регистрации, обновления будут передаваться на все контроллеры домена, что может резко увеличить внутренний трафик. Однако эти обновления не вызывают проблем в однодоменных окружениях или системах с небольшим количеством доменов, в которых контроллеры домена связаны между собой с помощью высокоскоростных соединений, и в которых задействовано не более 1000 перемещающихся пользователей.

Нужно иметь в виду, что при работе со службой AD не рекомендуется хранить в атрибутах значения, для которых они не предназначены. В данном случае модуль LogUser сохраняет имена компьютеров в атрибутах wwwHomePage и url, предназначенных для хранения URL-адресов. Если вам не подходит хранение имен компьютеров в данных атрибутах, но вы все равно хотите использовать модуль LogUser, можно модифицировать код таким образом, что он будет записывать имена компьютеров в другую центральную базу данных, например в базу данных Microsoft SQL Server.

Лучшее решение

В этой статье я показал две основные стратегии и несколько средств и методов, пригодных для использования при поиске системы, на которой зарегистрирован «перемещающийся» пользователь. Какое из решений будет работать лучше, зависит от конкретного окружения (от количества пользователей и компьютеров в сети Windows) и от того, как вы захотите использовать эту информацию.

Стратегия опроса – простое решение, позволяющее найти систему, на которой зарегистрирован перемещающийся пользователь. Неважно, используете вы команду Nbtstat или утилиту PsLoggedOn, в любом случае вам не придется создавать центральное хранилище данных или модифицировать сценарий регистрации.

Преимущество стратегии уведомления состоит в том, что она позволяет быстро определить, на какой системе зарегистрирован пользователь, не запуская отдельного сценария. Добавив либо связывающую команду, либо код модуля LogUser в сценарий регистрации «перемещающихся» пользователей, можно легко получить данные не только о системе, на которой пользователь зарегистрирован сейчас, но и о тех системах, на которых он регистрировался ранее. Однако не стоит использовать информацию, полученную с помощью метода уведомления, в целях аудита. Информация о компьютерах, хранящаяся в центральной общей папке в текстовых файлах доступна для чтения и обновления перемещающимися пользователями, так как они имеют разрешения чтения/записи для соответствующих файлов. Хранение информации в базе данных AD чуть более безопасно, чем хранение в текстовых файлах. Хотя «блуждающие пользователи» имеют разрешения для атрибутов wwwHomePage и url, они не могут так просто модифицировать их, так как для этого требуется знать точное название атрибута и иметь доступ к необходимым средствам (например, оснастке Active Directory Users and Computers).

Вне зависимости от того, какое из решений вы выберете, быстрое определение системы, на которой зарегистрирован «перемещающийся» пользователь, поможет сэкономить ваше время и силы. Эти решения особенно полезны в тех окружениях, где часто возникают задачи удаленного администрирования и отладки, а пользователи не могут точно назвать имя компьютера, когда им требуется помощь.


Листинг 1. Сценарий FindUser.cmd
@Echo Off
Setlocal
 
If #%1#==## Goto syntax
Set usertofind=%1
Echo Locating %usertofind% (this may take a while)...
Echo.
:: BEGIN CALLOUT A
For /f %%i in ('Net View ^| Find ""') Do Call :findit %%i
:: END CALLOUT A
Echo.
Echo Done.
Endlocal
Goto :EOF
 
:: BEGIN CALLOUT B
:findit
Set target=%1
Set target=%target:=%
Nbtstat -a %target% | Findstr /i "%usertofind%" > NUL
If %ERRORLEVEL% Equ 0
               Echo %usertofind% is logged on to %target%
Goto :EOF
:: END CALLOUT B
 
:syntax
Echo.
Echo finduser.cmd ^
Echo.
Goto :EOF
Листинг 2. Модуль LogUser
Option Explicit
Dim oUser, usercontainer, rootDN, wshNetwork, conn
On Error Resume Next
 
 ‘ BEGIN CALLOUT A
rootDN="DC=DOMAIN,DC=COM"
‘ END CALLOUT A
 
BEGIN COMMENT
' Obtain a reference to the WScript.Network object.
END COMMENT
Set wshNetwork = CreateObject("WScript.Network")
BEGIN COMMENT
' Establish connection to AD.
END COMMENT
Set Conn = CreateObject("ADODB.Connection")
conn.Provider = "ADSDSOObject"
conn.Open "ADs Provider"
 
Dim RS, query, dn, lastLogon
query = ";(&(ObjectClass=User)" & _
               "(sAMAccountName=" & wshNetwork.UserName & "));" & _
               "distinguishedName,samAccountName,wwwHomePage,url;subtree"
Set RS = conn.Execute(cstr(query))
 
If RS.EOF Then
               WScript.Echo "No Match"
               WScript.Quit 1
End If
 
dn = RS("distinguishedName")
Set oUser = GetObject("LDAP://" & dn)
 
lastLogon = RS("wwwHomePage")
If Not(IsNull(lastLogon)) Then
               oUser.Put "url",lastLogon
End If
oUser.Put "wwwHomePage",WshNetwork.ComputerName oUser.SetInfo
 
If Err.Number = 0 Then
               WScript.Echo "Command successful"
Else
               WScript.Echo "Command Failed"
End If