Практика написания сценариев

.

В Листинге 1 приведен сценарий GetGroupStats.bat; в нем используется встроенная команда Nbtstat и две дополнительные утилиты, PsLoggedOn и MemberOf, при помощи которых создается отчет, показывающий, членами скольких групп является зарегистрированный пользователь. В пояснениях к этому сценарию я представлю новый способ управления потоком команд сценария. Этот метод делает сценарий легким для чтения и упрощает синтаксис программы на языках Perl и VBScript. С тех пор, как появилась MS-DOS, в качестве механизма управления сценариями командной строки применялись операторы Goto и Call. Однако в других языках сценариев в качестве предпочтительного метода управления логикой используется условный оператор If.

Переполнение SID

Я написал GetGroupStats.bat для решения проблемы, которую называют SID token bloat (чрезмерное разрастание SID), описанной в статье Microsoft "Group Policy May Not Be Applied to Users Belonging to Many Groups" (http://support.microsoft.com/?kbid=263693). В этой статье речь идет о том, что Windows не смогла применить групповую политику для пользователя, который является прямым или неявным членом более 70-80 групп. Поскольку в нашей компании имели место случаи подобного сложного членства, я не мог определить, какие пользователи являются членами какого количества групп. Просматривая небольшую группу пользователей, нельзя с полной уверенностью сказать, имеются ли у компании потенциальные проблемы. Кроме того, у меня не было полного списка пользователей, поскольку сообщество пользователей состояло из множества организационных подразделений (OU), в которых я не являлся администратором. У меня был список компьютеров, на которых регистрировались пользователи, поэтому с помощью сценария надо было разобрать список имен компьютеров и узнать, кто из пользователей на нем зарегистрировался. Затем сценарий должен был создать табличный отчет о том, какому количеству групп принадлежит каждый из зарегистрированных пользователей. Впоследствии я использовал Microsoft Excel для сортировки данных отчета.

Другой целью применения GetGroupStats.bat может быть определение слишком большого количества членов в группе и идентификация связанных с этим проблем безопасности. Допустим, если известно, что большинство пользователей (не администраторов) являются членами 10 групп, и обнаружен пользователь, принадлежащий 25 или 30 группам, придется разобраться с этой ситуацией. Возможно, пользователь получил дополнительное членство после того, как был переведен в новое подразделение, или по неопытности администратор учетных записей предоставил пользователю слишком широкие права доступа. Мы можем идентифицировать потенциальные проблемы путем сортировки столбцов в выходном файле сценария, сохраненном в формате Excel (.TSV tab-separated value).

Утилиты PsLoggedOn и MemberOf

Сценарий GetGroupStats.bat для определения зарегистрировавшегося пользователя задействует утилиту PsLoggedOn компании Sysinternals. Также в сценарии используется утилита MemberOf, созданная Joe Richard. При помощи этой утилиты сценарий определяет, какому количеству групп принадлежит пользователь. В Windows NT 4.0 были утилиты Findgrp и IfMember, перечисляющие членство в группах, но в случае наличия вложенных локальных групп в окружении эти утилиты не могли правильно отразить действительное количество членов в группах. MemberOf предоставляет имена групп и их типы. Сценарий GetGroupStats.bat использует утилиту только для сбора информации о том, в каком количестве групп пользователи являются членами.

Nbtstat или Ping

Вы можете применять команды Nbtstat и Ping, чтобы определять, включена система или нет. Необходимо всегда проверять, включена ли система, перед выполнением каких-либо действий и запросов, поскольку некоторые команды имеют продолжительные периоды ожидания, что может привести к значительным задержкам в случае, если система не отвечает. Далее приведен пример основной команды Nbtstat, определяющей, включен ли компьютер с именем workst1.

Nbtstat -a workst1

Ключ -а возвращает таблицу имен заданной удаленной машины. После вставки Nbtstat в цикл For сценарий просматривает строки, которые являются частью таблицы, выведенной Nbtstat, возвращающей информацию о включенной системе. Блок кода выглядит примерно так, как показано в листинге 2. Код, приведенный в листинге 3, показывает использование утилиты PsLoggedOn для определения зарегистрированного пользователя.

Распрощайтесь с командами Call и Goto

Комнды Call и Goto позволяют перенаправить поток исполнения и работать подобно конструкции If...Then...Else, которая присутствует в VBScript. Если вы пишете собственный сценарий командной строки, то обычно используете команду For для установки значений переменных окружения команды и Call или Goto для передачи управления следующей команде. Команды Call и Goto также часто используются в условном операторе If для осуществления вызовов и переходов.

Стоит отметить, что большинство сценариев состоит из нескольких блоков кода, подобных сценарию, представленному в листинге 2. Использование команд Call и Goto в блоках, подобных приведенному, делает отслеживание логики затруднительным, поскольку приходится пролистывать страницы кода, чтобы понять, куда перенаправлено управление и в каком порядке будет выполняться код. Более того, команда Call отсылает поток в точку, следующую за строкой вызова Call. Команда Goto перебрасывает поток и никогда не возвращает его обратно к перенаправившей его команде Goto. По мере того, как сценарий становится все более длинным и сложным, вам требуется все больше и больше времени на отслеживание всевозможных переходов в случае, когда сценарий по каким-либо причинам не работает.

Вы можете использовать в своих сценариях более эффективную команду интерпретатора Setlocal ENABLEDELAYEDEXPANSION, поддерживаемую в Windows 2000 и более поздних версиях. Код, представленный в листинге 4, подобен коду листинга 2, но без команд Goto и Call.

Последний сценарий совсем не похож на сценарий предыдущего варианта. Заметим, что в сценарии листинга 4 имеется вложенная команда For и используется команда Setlocal ENABLEDELAYEDEXPANSION, позволяющая определить переменную и начать использовать ее немедленно, пока она еще в цикле команды For. Возможность использования переменных внутри команды For без применения Call для перехода к другой части кода программы очень полезна. Это свойство делает ваши сценарии командной строки пригодными для использования в других языках сценариев, которые вы, возможно, захотите изучить в будущем. К тому же сценарии станут более простыми для чтения и трассировки. Информацию об использовании Setlocal и возможностях этой технологии локализации изменений среды можно получить, открыв командную строку и набрав

Setlocal /?

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

Я тестировал работу сценария GetGroupStats.bat на Windows XP Service Pack 1 (SP1) и Windows 2000 Service Pack 3. Чтобы получить работающий сценарий, выполните следующие действия:

  1. Загрузите PsLoggedOn с http://www.sysinternals.com/ntw2k/freeware/pstools.shtml, и MemberOf с http://www.joeware.net/win32.
  2. Настройте сценарии, указав путь к папкам, содержащим эти две утилиты. Имейте в виду, что некоторые утилиты, включая PsLoggedOn, чувствительны к пробелам в записи пути. Убедитесь, что путь задан без пробелов.
  3. Настройте сценарий на использование списка компьютеров, расположенного во входном файле в заданном каталоге. Расположите целевые компьютеры в этом файле по одному на каждой строке.
  4. Настройте местоположение выходного файла. Сценарий будет создавать .tsv файл, который вы затем сможете открыть в Excel.
  5. Если у вас имеются пользовательские учетные записи и группы в нескольких доменах, утилита MemberOf возвратит более точные результаты, если указать сервер глобального каталога Global Catalog (GC) в качестве целевого сервера для команды. Чтобы это сделать, нужно добавить ключ -s servername в качестве аргумента команды MemberOf. Здесь servername - имя целевого сервера.

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


Листинг 1. GetGroupStats.bat
@ECHO OFF
SETlocal ENABLEDELAYEDEXPANSION

:: Configure location of PsLoggedOn and MemberOf tools.
:: PsLoggedOn is sensitive to spaces in path. 
SET ToolLoc=C:utilities

:: Configure PC input list path here.
SET Targetlist=D:GetMemberofPClist.txt

:: Configure output list path here.
SET OutputFile=D:GetMemberofGroupReport.tsv
FOR /F "tokens=1 usebackq" %%i in ("%Targetlist%") DO (
SET target=%%i
	SET response=
	FOR /F "tokens=1" %%j in ('nbtstat -a !target!
 ^| find "-----"') DO (
	SET response=%%j
		IF DEFINED response (
			SET User=
			FOR /F "tokens=4" %%k in ('%ToolLoc%psloggedon.exe
 -l !target! ^| find "/"') 
DO (
			SET User=%%k
				IF DEFINED User (
					SET counter=
					REM MemberOf command can use GC server to return more 
accurate metrics -s 
					FOR /F "tokens=*"
 %%l in ('%ToolLoc%MemberOf.exe -q -u 
!User! 2^>NUL') DO (
					SET /A counter+=1
					)
					IF DEFINED counter @ECHO !target!
	online	!User!
	!counter! groups>>"%OutputFile%"
					IF NOT DEFINED counter @ECHO !target!
	online	!User!
	Unable to determine group memberships>>"%OutputFile%"
				)
			)
			IF NOT DEFINED User @Echo !target!	online	No user logged 
in>>"%OutputFile%"
		)
	)
	IF NOT DEFINED response ECHO !target!
	offline>>"%OutputFile%"
)
IF NOT DEFINED target Echo Check target list
 location.>>"%OutputFile%"

Листинг 2. Код, определяющий, включена ли система
Set response=
For /F "tokens=1" %%i in ('Nbtstat -a workst1 ^|
 find "-----"') Do Set response=%%i
If Defined response Echo Looks like the PC is online & Goto :Next
Echo workst1 looks like it is offline.

Листинг 3. Код, определяющий, зарегистрирован ли пользователь
:Next
Set User=
for /F "tokens=4" %%i in ('C:psloggedon.exe
 -l workst1 ^| find "/"') DO (Set User =%%i)
If defined User %User% is logged in. & Goto :EOF
Echo User is not logged in.

Goto :EOF

Листинг 4. Код, использующий переменные внутри команды For
setlocal ENABLEDELAYEDEXPANSION
Set response=
For /F "tokens=1" %%i in ('nbtstat -a workst1 ^
| find "-----"') DO (
	Set response=%%i
	IF defined response (
		Echo workst1 is online
		Set User=
		For /F "tokens=4" %%j in ('C:psloggedon.exe
 -l workst1 ^| find "/"') DO (
		Set User=%%j
		If defined User Echo !User!
		)
		If Not defined User Echo No one is logged in right now
	)
)
If Not Defined response Echo workst1 offline