. Руководству нужно выяснить, существуют ли учетные записи уволенных из компании сотрудников, которые не были заблокированы или удалены. Кроме того, известно, что для некоторых учетных записей установлен постоянно действующий пароль, в то время как вновь принятая политика безопасности требует регулярной смены паролей для всех пользователей.

Мною был разработан сценарий GetUserDetails.bat, показанный в Листинге 1, который с помощью внешних утилит извлекает детальную информацию о параметрах учетных записей пользователей (в том числе о блокировке учетной записи и статусе ее пароля). Информация, полученная от этих утилит, затем перенаправляется в отчет, оформленный в виде электронной таблицы. Отчет содержит 19 столбцов, содержащих данные по каждому пользователю, при этом можно легко выполнять сортировку таблицы, чтобы обеспечить представление данных о пользователях в нужном виде.

Преобразование выходных данных

В сценарии GetUserDetails.bat используется свободно распространяемая утилита GetUserInfo.exe от Joeware (http://www.joeware.net/win32/index.html). Данная утилита предоставляет информацию, сходную с той, которую выдает команда Net User, но, в отличие от Net User, позволяет указать компьютер, с которого вы хотите извлечь информацию. Кстати, Джо Ричардс из Joeware предлагает еще несколько полезных утилит, которые я использую в своих сценариях. Всем рекомендую познакомиться с этими утилитами поближе.

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

Утилита GetUserInfo прекрасно выручает нас в тех случаях, когда нужно получить информацию об одном пользователе. Пример выходных данных, полученных от этой утилиты, показан на Рисунке 1. Однако если эту же программу запустить для 100 учетных записей и перенаправить данные в текстовый файл, то полученные результаты будут трудны для восприятия, к тому же их будет невозможно сортировать без ручного вмешательства. Проанализировав выходные данные утилиты GetUserInfo, я понял, что для меня представляет интерес вся эта информация, за исключением сведений о локальных и глобальных группах, которые уже получены мною из другого отчета. Кроме того, я счел нужным преобразовать полученную информацию в формат электронной таблицы, где в каждой строке размещались бы данные по отдельной учетной записи пользователя, а столбцы содержали бы соответствующие сведения по этой учетной записи. Для решения таких задач существует несколько вариантов, давайте рассмотрим два из них.

Один из подходов заключается в том, чтобы многократно запускать программу сбора данных, получая каждый раз некоторый фрагмент информации, отфильтровывая с помощью команды Find все остальное. Например, если нам нужно извлечь два фрагмента данных, таких как User Profile (Профиль пользователя) и Account Expires (Срок окончания действия учетной записи), можно воспользоваться следующими командами:

GetUserInfo.exe domain1fred
  |find "User Profile"
GetUserInfo.exe domain1fred
  |find "Account Expires"

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

Другой способ, который и был реализован мною в GetUserDetails.bat, заключается в использовании системы "счетчик/метка" (counter/label). В сценарии эта технология применятся для записи каждого из 19 собираемых мною параметров пользовательской учетной записи в соответствующую переменную. Данный подход позволяет мне однократно запускать утилиту GetUserInfo для каждой учетной записи. Сценарий GetUserDetails.bat был разработан специально для сбора сведений о пользователях, однако описанную технологию счетчиков можно применять и при работе с другими утилитами.

Сталкиваясь с необходимостью фильтрации, сначала я анализирую выходные данные команды, с тем чтобы определить, какую информацию можно отсеять. В частности, в данных, выводимых утилитой GetUserInfo, мне не нужна первая строка (User information for SalesDLewis (dc-01)) (см. Рисунок 1). Для того чтобы проигнорировать эту строку, можно воспользоваться командой For с ключом skip =1, как показано во фрагменте с меткой B Листинга 1.

Далее требуется отфильтровать данные о членстве пользователя в локальных и глобальных группах. Для этого я использую команду Find (см. фрагмент с меткой B).

И, наконец, необходимо удалить из результирующих данных пустые строки. Как было сказано выше, в GetUserDetails.bat команда For используется для каждого элемента коллекции собранных данных. Команда For удаляет пустые строки автоматически, в чем вы можете убедиться, создав показанный в Листинге 2 файл testIPconfig.bat. Запустив этот файл, вы увидите, что из данных, выводимых командой ipconfig /all, все пустые строки удалены.

Отображение интересующих данных

Итак, ненужные данные отфильтрованы, теперь возникает следующая задача: собрать 19 необходимых выходных параметров и сформировать из соответствующих переменных требуемую строку. Первый интересующий меня фрагмент данных:

User Name             Dlewis

состоит из трех строк. Со строками User и Name дело обстоит довольно просто, поскольку формируемая таблица будет иметь заголовки столбцов. Важная информация (в данном случае это Dlewis) содержится в строке с маркером 3. Следующая интересующая нас информация – срок действия пароля (в днях) – имеется в строке с маркером 5. Бросив быстрый взгляд на другие строки, показанные на Рисунке 1, я понимаю, что есть несколько вариантов распределения маркеров, каждый из которых требует применения отдельной схемы фильтрации.

Таким образом, для того чтобы извлечь информацию с требуемым маркером, нужно к каждой из 19 строк применить команду For. Кроме того, необходим механизм перенаправления хода выполнения сценария на соответствующий цикл For, поскольку здесь будет использоваться еще одна команда For для отображения каждой строки выходных данных GetUserInfo. Если объединить все эти компоненты, в результате получается следующий псевдокод для реализации GetUserDetails:

  1. Передать в виде эха заголовков столбцов в файл формата .tsv (значения, разделяемые символом табуляции (tab- separated value)).
  2. Обработать входной файл, содержащий имена компьютеров, с помощью команды For.
  3. Запустить команду GetUserInfo для каждой учетной записи пользователя, выделенной на шаге 2.
  4. Обнулить содержимое счетчика для каждой новой учетной записи и применить команды:
      Set /A
    для приращения значения счетчика на 1 перед перенаправлением каждой из 19 строк параметров учетной записи во второй цикл For. Например, когда извлекается первая строка этих данных (User Name), счетчик будет равен 1, для второй строки (Full Name) он будет равен 2 и т.д.
  5. Для перенаправления строк вывода команды во второй цикл For используется метка на базе значения счетчика. Например, приведенная ниже команда:
      GOTO :lablno%Counter%
    позволяет организовать переход на метку :lablno1 на первом шаге, на метку :lablno2 – на втором шаге и так далее до :lablno19. Внутри каждой метки содержится цикл For, настроенный на извлечение нужного маркера и установки уникальной переменной. Затем все 19 собранных переменных, описывающих соответствующие параметры учетной записи пользователя, перенаправляются в файл .tsv.
  6. Повторить шаг 4 и шаг 5 для каждой пользовательской учетной записи.

Внимательно проанализируйте фрагмент кода, обозначенный в Листинге 1 меткой С, это поможет вам понять, как данный динамический код реализует переход выполнения сценария на соответствующие статические метки. Данная технология может оказаться весьма полезной для применения в других сценариях, поэтому рекомендую поэкспериментировать с ней немного, а затем смело взять на вооружение.

Запуск сценария

Для того чтобы можно было задействовать описанный сценарий в конкретной инфраструктуре, выполните следующие действия:

  1. Загрузите с Web-сайта Joeware утилиту GetUserInfo.
  2. Загрузите файл сценария GetUserDetails.bat.
  3. Создайте входной файл, содержащий имя домена и имена пользователей, по которым необходимо собрать информацию. Каждая строка входного файла должна содержать одно имя пользователя в виде <имя домена>. Пример содержимого входного файла показан ниже:
    Domain1fred
    Domain1wilma
  4. Во фрагменте сценария, обозначенном меткой A, модифицируйте соответствующим образом описания путей к входному файлу, выходному файлу и утилите GetUserInfo.

Использование сценария GetUserDetails.bat – достаточно простой способ получения всей необходимой информации об учетных записях пользователей с представлением результатов в виде отчета в табличном формате .tsv, данные которого можно легко сортировать необходимым образом. Кроме того, если вам когда-либо потребуется преобразовать выходные данные команды из "вертикального" формата в "горизонтальный", то теперь в вашем распоряжении есть технология, позволяющая решить эту задачу.


Контакты с авторами утилит

При работе с утилитами от независимых разработчиков, такими как программа GetUserInfo, обсуждаемая в основной статье, я порой сталкиваюсь с некоторыми проблемами или прихожу к мысли о том, что было бы неплохо, если бы данная утилита имела ту или иную дополнительную функциональность. Вы, наверное, будете удивлены, но даже авторы свободно распространяемых утилит обычно заинтересованы в обратной связи с пользователями. Время от времени, когда разработчики включают запрошенные мною возможности в свои программы, я выступаю в роли их бета-тестера. Большинство разработчиков утилит понимают, что если у одного пользователя есть те или иные пожелания, вероятно, они могут возникнуть и других.

Довольно редко приходится иметь дело с разработчиками, которые по тем или иным причинам не несут ответственности либо больше не поддерживают свои продукты. Когда вы обращаетесь к автору утилиты, не забудьте дать свою краткую оценку данной программы, а также рассказать о тех преимуществах, которые получили от ее использования. Если данный продукт является условно бесплатным (shareware) или рассчитанным на пожертвования (donationware), перешлите автору соответствующую сумму. Если вы являетесь официальным пользователем программы, вероятность получения положительного отклика от ее автора гораздо выше.

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


Рисунок 1

User information for SalesDLewis (dc-01) User Name DLewis Full Name Lewis, Richard J Description Employee A2247 User's Comment User Type Guest Enhanced Authority Account Type Global Workstations Home Directory M: dom1pdcusertestfred User Profile dom1pdcuserstestfredprofile Logon Script Logon2.bat Flags NO_PWD_CHG, NO_PWD_EXPIRE Account Expires Never Password age in days 117 Password last set 11/4/2003 1:03 PM Bad PWD count 0 Num logons (this machine) 235 Last logon 2/24/2004 6:50 AM Logon hours All Global group memberships *Domain Users *Domain Admins Local group memberships *GeneralAccess *MatrixAdmins *Publishing *DropMembers *Administrators *Users


Листинг 1: Фрагмент сценария GetUserDetails.bat  
Begin Callout A
Begin Comment
:: Укажите путь к файлу со списком пользователей. Каждая строка файла
:: должна содержать одно имя в виде "Имя домена""ID пользователя".
:: ПРИМЕР: domain1fred 
End Comment
Set UserList=D:GetUserInfoUserlist.txt
Begin Comment
:: Укажите путь к файлу результатов.
End Comment
Set OutputFile=D:GetUserInfooutlog.tsv
Begin Comment
:: Укажите путь к утилите GetUserInfo.exe.
End Comment
Set UtilPath=D:GetUserInfoGetUserInfo.exe
End Callout A
Begin Comment
:: Вывод заголовков в выходную таблицу.
End Comment
ECHO ListName     UserName     Fullname   Description   UserComment
     UserType     EnhAuth      AcctType   Workstations  HomeDir
     UserProfile  LogonScript  Flags      AcctExpires   PWage
     PWLastSet    BadPWCount   NumLogons  LastLogon
     LogonHours>"%OutputFile%"
Begin Comment
:: Далее не требуется вносить никаких изменений в текст, если не нужно
::  изменять формат команды GetUserInfo
:: **********************************************************************
:: Обработка списка пользователей.
End Comment
For /F "tokens=*" %%i in (%UserList%) Do (set ID=%%i) & (Call :getem) 
Begin Comment
:: Здесь завершается выполнение сценария.
End Comment
ECHO Run complete! Check %OutputFile% file for results.
Goto :EOF
:getem
Set Counter=0
Begin Callout B
for /f "tokens=* skip=1" %%i in ('%UtilPath% %ID% /Q^|Find /V 
  "*"^|Find /I /V "memberships"') Do (Set mainvar=%%i) & (Call 
  :next)
End Callout B
ECHO %ID%            %UserName%     %Fullname%     %Description%
     %UserComment%   %UserType%     %EnhAuth%      %AcctType%
     %Workstations%  %HomeDir%      %UserProfile%  %LogonScript%
     %Flags%         %AcctExpires%  %PWage%        %PWLastSet%
     %BadPWCount%    %NumLogons%    %LastLogon%
     %LogonHours%>>"%OutputFile%"
Begin Comment
:: Сброс значений переменных.
End Comment
Set UserName=N/A
Set Fullname=
Set Description=
Set UserComment=
Set UserType=
Set EnhAuth=
Set AcctType=
Set Workstations=
Set HomeDir=
Set UserProfile=
Set LogonScript=
Set Flags=
Set AcctExpires=
Set PWage=
Set PWLastSet=
Set BadPWCount=
Set NumLogons=
Set LastLogon=
Set LogonHours=
Goto :EOF
:next
Begin Comment
:: Приращение содержимого счетчика.
End Comment
Set /A Counter=%Counter%+1
Begin Comment
:: Проверка, все ли 19 нужных параметры обработаны?
End Comment
If %Counter% GTR 19 (GOTO :last)
Begin Comment
:: Переход на метку с номером, соответствующим содержимому счетчика.
End Comment
Begin Callout C
GOTO :lablno%Counter%
End Callout C
:lablno1
For /f "tokens=1,2,*" %%i in ("%mainvar%") Do (Set UserName=%%k) 
  & (GOTO :last)
GOTO :EOF
:lablno2
For /f "tokens=1,2,*" %%i in ("%mainvar%") Do (Set Fullname=%%k) 
  & (GOTO :last)
GOTO :EOF
:lablno3
For /f "tokens=1,*" %%i in ("%mainvar%") Do (Set Description=%%j) 
  & (GOTO :last)
GOTO :EOF
Begin Comment
:: Шаги с 4 по 19 не показаны.
End Comment
:last
GOTO :EOF

Листинг 2. testIPconfig.bat

@echo off
for /F "tokens=*" %%i in ('ipconfig /ALL') do Set line=%%i&call :next
Pause
GOTO :EOF
:next
for /F "tokens=*" %%i in ("%line%") do Echo %%i
GOTO :EOF