Выступая на конференциях, таких как Tech•Ed или
TechMentor, я приобретаю привычку обращаться к аудитории — объявлять общие
правила, которые помогут пользователям запомнить ключевые позиции таких
вещах, как Windows PowerShell. Мое последнее воззвание гласит: «Если вы
выполняете синтаксический анализ строки в Windows PowerShell, вы делаете
что-то не то».
Это проистекает из моей
философии относительно того, что Windows PowerShell является
объектно-ориентированным интерпретатором команд. Если вы выполняете
процедуру наподобие выгрузки списков служб в текстовый файл и последующего
анализа этого текстового файла, чтобы увидеть, какие службы запущены, то
очень затрудняете себе работу. Это — допустимый подход для основанных на
тексте ОС, таких как UNIX, но Windows PowerShell (также как и система
Windows® сама по себе) позволяет использовать
объекты более экономно.
На недавнем семинаре TechMentor
в г. Орландо, штат Флорида, один из моих студентов напомнил мне, что почти
все правила, особенно общие, имеют исключения. «Что насчет нахождения
всякой чепухи в файле журнала IIS? Разве вам не очень нужно анализировать
текст в этом случае?».
Хорошо, ошибка, да. Но, к
счастью, когда придется анализировать строки текста, Windows PowerShell не
подведет в силу своего умения работать с объектами. И сейчас, как вы уже
заметили, файлы журналов IIS, брандмауэра и другие основанные на тексте
журналы являются прекрасными примерами.
Пример из жизни
Однажды я должен был
проанализировать набор журналов брандмауэра компании, в которой работал.
Служащий был пойман при просмотре некоторых неуместных веб-узлов, и в
качестве части последующих разбирательств отдел кадров нуждался в полном
списке веб-узлов, которые он посетил. Несмотря на то, что вытащить файл
журнала за один день несколько сложно, люди в отделе кадров хотели
просмотреть историю за нескольких последних недель — задача, которую мне
совершенно не хотелось выполнять вручную.
Сервер протокола DHCP указал,
что компьютер служащего использовал один и тот же IP-адрес (скажем,
192.168.17.54) в течение нескольких месяцев. Что, конечно, не удивительно,
потому что это был настольный компьютер, который редко выключался. И,
поскольку в журнале брандмауэра хранились записи об IP-адресах источника,
я знал, что Windows PowerShell поможет.
Секрет состоит в команде выборки
строки Select-String, о которой часто забывают. Кроме того, также
требовалось предметное знание регулярных выражений (о которых я
рассказывал в статье о Windows
PowerShell за ноябрь 2007 г.).
Команда Select-String («Выбрать
строку») принимает полный путь, по которому находятся текстовые файлы,
регулярное выражение или просто строку, которую нужно найти. Затем она
выдаст каждую строку из каждого файла журнала, которая удовлетворяет
регулярному выражению или простой строке. Для начала мне просто нужно было
получить каждую строку, содержащую IP-адрес настольного компьютера этого
служащего. Каждая строка файла журнала содержала дату и отметку времени —
все, что было нужно сотрудникам отдела кадров.
Вот команда, с помощью которой
это делается:
select-string -path c:\logs\*.txt -pattern "192.168.17.54"
-allmatches –simplematch
Параметр –simpleMatch указывает,
что шаблон, предоставленный мною, — простая строка, а не регулярное
выражение. На
рис. 1 показана часть результата, который
также можно направить в файл. Важно отметить, что результат содержит как
имя файла, так и номер строки, в которой было найдено совпадение, что
может быть очень полезно, если захочется вернуться в это место и получить
дополнительную информацию.
Командлет месяца: Start-Sleep
Это командлет, который может
дать вам то, что нужно в середине долгого рабочего дня, — легкий отдых.
Start-Sleep предлагает короткую остановку для сценариев Windows
PowerShell.
Короткая остановка нечасто
требуется в сценариях. Например, скажем, вам нужно запустить службу,
подождать несколько секунд, пока она запустится, и затем выполнить другие
задания, которые зависят от этой службы. Именно для таких случаев
Start-Sleep и нужен. При выдаче команды Start-Sleep 10, например,
произойдет остановка PowerShell на 10 секунд. Если нужно более точное
управление, можно запустить Start-Sleep с параметром -milli, например
Start-Sleep -milli 100 для остановки на 100 милисекунд. Start-Sleep
полностью останавливает PowerShell, включая сценарии, конвейеры и все
остальное, на указанный период времени. Если сейчас кто-то захочет
написать Start-Nap командлет, я вздохну.
Рис. 1. Выходные данные команды
Select-String
Сложные совпадения
После того как я представил
отделу кадров именно то, о чем они просили, они поняли, что в итоге им
требовалось совсем другое. Мой отчет включал в себя посещения множества
IP-адресов, таких как 207.68.172.246 (Веб-узел MSN®). Следующее, что меня попросили сделать, – урезать
отчет до включения в него только посещений указанных IP-адресов, которые
они идентифицировали как принадлежащие одному из отслеживаемых веб-узлов.
В этой статье я не хочу открывать истинные IP-адреса, которые были
получены в этом расследовании. Вместо них здесь я буду использовать
207.68.172.246 (хотя веб-узел MSN обычно не рассматривается как
нежелательный).
Этот запрос мог быть чуть
посложнее. В файле журнала, с которым я работал, IP-адреса источника и
получателя находились рядом и были разделены запятой. Так что я просто
изменил мою строку поиска на «192.168.17.54,207.68.172.246» и повторил
поиск.
Однако в более сложном файле
журнала между двумя IP-адресами могли быть записаны переменные данные, так
что простое совпадение строк не сработало бы. В этой ситуации нужно было
бы прибегнуть к регулярному выражению, это также хорошо подходит для более
простых форматов журналов, что я и продемонстрирую.
В регулярном выражении символ
точки является символом подстановки для любого одиночного символа, и я
могу использовать подвыражение (.)* для поиска любого количества символов
между двумя указанными IP-адресами. Тем не менее, необходимо использование
обратной косой черты для экранирования символов точек, которые появляются
в самих IP-адресах.
select-string -path c:\logs\*.txt -pattern
"192\.168\.17\.54(.)*207\.68\.172\.246" –allmatches
Я удалил параметр –simpleMatch,
так как в этот раз использую регулярное выражение. В полученном результате
отражены только посещения веб-узлов, указанных как недопустимые, с
компьютера указанного служащего. Кроме того, в результат входили дата и
время, которые требовались для расследования. На рис. 2
показана часть результата, который можно получить при запуске подобной
команды.
Рис. 2 В результате суженного
поиска отображаются посещения только указанного узла.
Но я могу поступить лучше и
передать результ в командлет Format-Table, чтобы использовать его
возможности показа вычисленных столбцов. Я могу вставить в эту таблицу
имена файлов журналов и номер строки, где совпадение было обнаружено, и
даже могу показать саму найденную строку. Тем не менее, можно попросить
PowerShell заменить регулярное выражение пустой строкой так, что будет
показан только остаток строки — дата и время в моем примере. Это более
сложный прием, но он является дальнейшей иллюстрацией того, как Windows
PowerShell может работать со строковыми данными и производить глубоко
переработанный результат с помощью всего лишь одной командной строки:
select-string -path c:\logs\*.txt -pattern
"192\.168\.17\.54(.)*207\.68\.172\.246" -allmatches |
ft filename,linenumber,@{"Label"="Time";
"Expression"={$_.line.replace
($_.matches[0],"")}} –auto
Окончательный результат должен
выглядеть, как на рис. 3.
Рис. 3. Форматированный
результат команды Select-String
Это мир строк.
Я рад провозгласить
объектно-ориентированную сущность Windows PowerShell одной из его самых
сильных его сторон. Но, тем не менее, есть случаи, когда объекты — не
выход.
Windows PowerShell может жить в
объектно-ориентированном мире. К счастью, команда разработчиков Windows
PowerShell поняла, что мир часто содержит внешние днные в форматированных
строках, так что в PowerShell есть команда Select-String. Вооружившись
командой Select-String и знаниями о регулярных выражениях, можно
использовать Windows PowerShell для написания командных строк, которые
будут анализировать самые сложные строки.