В помощь начинающим пользователям VBScript и WSH

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

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

1. Найдите документацию по WSH и пользуйтесь ею

Конечно, документация по WSH — не верх совершенства, и тем не менее она очень неплоха. Следует найти ее и обращаться к ней чаще, поскольку ответы на подавляющее большинство вопросов по WSH, VBScript и JScript можно найти именно там. Документацию по сценариям для Windows можно найти по следующему адресу: http://msdn.microsoft.com/scripting. Еще один хороший ресурс Microsoft по данной тематике — http://www.microsoft.com/technet/scriptcenter.

2. Подумайте, прежде чем использовать конструкцию On Error

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

On Error Resume Next

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

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

on error goto 0

в каждом из разделов Case.

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

3. При работе с методом Run используйте дополнительные двойные кавычки

Если при вызове метода Run объекта WshShell указывается путь, содержащий пробелы, то в этом случае следует использовать дополнительные двойные кавычки. Дело в том, что интерпретатор разбивает путь на аргументы. Допустим, требуется запустить следующий исполняемый файл: C:my appapp.exe. Если мы воспользуемся приведенным ниже синтаксисом команды запуска:

Set WshShell = _
CreateObject("WScript.Shell")
WshShell.Run _
"C:My Appapp.exe"

то получим сообщение об ошибке The system cannot find the file specified (разумеется, если в сценарии не используется утверждение On Error Resume Next). Если же на диске C: есть каталог my, тогда в соответствующем окне откроется данный каталог и сценарий продолжит свое выполнение здесь.

В чем же причина возникновения ошибки в случае с my app? Дело в том, что поведение метода Run подобно работе в командной строке — в рассматриваемом примере данный метод считает, что ему передан не один-единственный аргумент, а выполняемый или запускаемый из командной строки файл с именем C:my, за которым следует аргумент appapp.exe.

По моему глубокому убеждению, от путей, содержащих пробелы, нужно держаться подальше, но, к сожалению, в системе Windows пробелы встречаются в именах некоторых ключевых каталогов (таких, как documents and settings и program files). Поэтому необходимо разобраться, как правильно работать с такого рода именами. Для того чтобы метод Run мог корректно работать с путями, содержащими символы пробелов, следует заключать описание пути в дополнительные двойные кавычки таким образом, чтобы каждый фрагмент, заключенный в двойные кавычки, был окружен еще одними двойными кавычками. Правильный синтаксис вызова метода Run выглядит так:

WshShell.Run _
«»»C:My Appapp.exe»»»

Некоторые считают, что проще поступать следующим образом: набрать строку в том виде, в котором она должна быть (т. е. с двойными кавычками в начале и в конце), заменить каждые из двойных кавычек парными двойными кавычками, а затем добавить еще одни двойные кавычки в начале и в конце, чтобы привести данные к виду, соответствующему строке VBScript. Если вам не хочется видеть в своих сценариях такое количество двойных кавычек, в качестве альтернативы можно предложить использовать имеющуюся в VBScript функцию Chr, с помощью которой можно добавлять в начало и окончание описания пути не сами двойные кавычки, а соответствующий им код ASCII (в данном случае ASCII код 34). Пример такого подхода показан ниже:

WshShell.Run Chr(34) & _
"C:My Appapp.exe" & Chr(34)

Для предотвращения проблем советую придерживаться следующих рекомендаций.

  • Приобретите текстовый редактор, который может выделять цветом компоненты языка VBScript. Диапазон выбора продуктов здесь довольно широк: от бесплатных (SciTE) и сравнительно недорогих программ (TextPad от Helios Software Solutions) до дорогостоящих коммерческих продуктов (PrimalScript от SAPIEN Technologies). В данных продуктах строковые значения обычно выделяются другим цветом, что позволяет сразу же выявлять синтаксические ошибки, связанные с использованием кавычек.
  • Чтобы удостовериться в том, что вы правильно написали код, протестируйте аргумент, используемый в методе Run. Точное отображение той строки, которая будет обрабатываться в VBScript, можно получить с помощью метода Wscript.Echo: если результат, выводимый WScript.Echo, будет корректно работать в окне командной строки, то он будет работать и в качестве первого аргумента для метода Run.

Необходимость использования еще одних двойных кавычек при работе с методом Run объекта WshShell обусловлена тем, что, когда оболочка считывает строку, она пытается разбить ее на аргументы. Но не пытайтесь добавлять дополнительные кавычки, например, при описании имени файла или каталога для работы с методами объекта Scripting.FileSystemObject, поскольку в данном случае те методы, которые используют в качестве аргумента имя файла или каталога, считают аргументом полное описание имени и не пытаются его разбивать, поэтому дополнительные кавычки здесь не требуются.

4. При необходимости перехода в другой каталог пользуйтесь свойством CurrentDirectory

Меня часто спрашивают, как в WSH можно выполнять переход в другой каталог, несмотря на то что данный вопрос подробно рассматривается в документации. Напомню, что у объекта WshShell есть свойство CurrentDirectory, которое можно как читать, так и изменять. Например, если требуется перейти в каталог C:program files, то можно воспользоваться следующим кодом:

Set WshShell = _
CreateObject("WScript.Shell")
WshShell.CurrentDirectory = _
"C:Program Files"

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

5. Массивы всегда начинаются с 0

Если вы создаете или используете массивы в VBScript, помните, что нижняя граница по любому из измерений массива всегда равна 0. В документации данный факт умалчивается, однако наличие в VBScript функции LBound все еще приводит к ошибкам, поскольку начинает казаться, что можно присвоить нижней границе массива по какому-либо из измерений произвольное целочисленное значение, подобно тому как это делается в Visual Basic (VB).

Функция LBound была добавлена в VBScript потому, что вызовы метода COM в некоторых случаях могут возвращать массивы с произвольными нижними границами, поэтому в VBScript можно встретиться с массивами такого рода, хотя самим создать их в VBScript нельзя. В показанном ниже примере рассматривается случай, когда значение нижней границы массива может быть больше, чем значение его верхней границы:

Option Explicit
dim a: dim b()
a = array("paper", "rock", _
"scissors")
WScript.Echo LBound(a)
'Всегда возвращает 0
redim b(-1)
WScript.Echo "Lower bound of _
b() is greater than upper:", _
LBound(b), UBound(b)

6. MsgBox имеет ограничение в 1023 символа

Если в сценарии требуется организовать вывод более чем нескольких строк текста, то в этом случае лучше использовать не MsgBox, а Wscript.Echo. Эта рекомендация связана с тем, что MsgBox ограничивает вывод данных в строке 1023 символами, а все остальное отсекается. Что касается метода Wscript.Echo, то он позволяет обрабатывать существенно больший объем текста — мне лично доводилось выводить более 300 тыс. символов за один вызов. Еще одним достоинством WScript.Echo является то, что он может работать с обоими исполнительными модулями WSH: как с WScript.exe (с отображением сообщений в графическом окне), так и с CScript.exe (при этом текст передается в окно консоли).

В тех случаях когда требуется приостановить выполнение сценария до момента отклика пользователя на полученное сообщение (что можно реализовать в сценариях, выполняемых через Cscript.exe с помощью MsgBox), лучше воспользоваться методом PopUp объекта WshShell. При этом, если не была задана величина тайм-аута, сообщение PopUp останется на экране до тех пор, пока не будет закрыто вручную, что полностью аналогично поведению MsgBox.

Если вы все же решили использовать MsgBox и работаете с символами кодировки Unicode, не забывайте, что ограничение по количеству символов, свойственное MsgBox, базируется на истинном количестве символов. Даже если используются расширенные символы Unicode, MsgBox все равно покажет только первые 1023 символа.

7. Ищите документацию по используемым объектам в проверенных местах

Многие из тех, кто начинает использовать COM-автоматизацию, часто спрашивают: «Где взять полный перечень объектов, которыми можно управлять через сценарии?» К сожалению, такого перечня нет и существовать не может — программисты при создании управляемых сценариями объектов могут использовать большинство современных языков программирования для Windows, соответственно, на любом типовом персональном компьютере уже установлены сотни таких объектов COM. Способы управления тем или иным объектом с помощью сценариев зависят от того, как программист спроектировал данный объект, поэтому лучший способ изучения механизмов управления объектом состоит в том, чтобы обратиться к справочной документации, выпущенной разработчиком.

Как правило, объекты COM разрабатываются так, чтобы быть в известной степени «самодокументируемыми», поэтому, даже если объект не имеет формальной документации, информацию о способах работы с ним можно получить, открыв его с помощью специального средства просмотра объектов (Object Browser). Именно таким способом я начинал изучать компоненты, управляемые сценариями. В частности, любое из приложений пакета Microsoft Office имеет интегрированный компонент VBA Editor, в состав которого входит и Object Browser. Для просмотра объектов также можно использовать отдельные продукты, к ним относятся, например, Microsoft OLE/COM Object Viewer (http://www.microsoft.com/com/resources/oleview.asp) или приложение TLViewer (http://mysite.verizon.net/res1ur2j/tlviewer.htm). Object Browser включен в состав большей части современных средств разработки для Windows, таких как Visual Studio .NET. Более подробные сведения содержатся в документации по соответствующему продукту.

Двумя наиболее часто используемыми объектными библиотеками являются Active Directory Service Interfaces (ADSI) и Windows Management Instrumentation (WMI). К сожалению, в отличие от большинства объектов COM, эти две достаточно сложные и очень важные объектные модели не могут просматриваться с помощью компонента Object Browser. Подробную информацию об этих библиотеках можно получить по следующим адресам: http://msdn.microsoft.com/library/en-us/netdir/ adsi/active_directory_service_interfaces_adsi.asp и http://msdn.microsoft.com/library/enus/ wmisdk/wmi/wmi_start_page.asp. Однако, на мой взгляд, более полезным является популярный инструмент Scriptomatic, который можно загрузить по адресу http://www.microsoft.com/technet/scriptcenter/ tools/wmimatic.asp. Scriptomatic сканирует систему и возвращает перечень всех имеющихся на ней классов WMI. Когда выбирается какой-либо класс, Scriptomatic автоматически генерирует соответствующий сценарий, считывающий все свойства данного класса, и отображает этот сценарий, который затем можно редактировать, копировать или запускать. Обратите внимание на то, что в коде, полученном с помощью Scriptomatic, задействован механизм игнорирования ошибок периода выполнения. Одним из тех немногих примеров того, когда это безопасно, является сценарий, который выполняет только отображение данных — именно это и делает код Scriptomatic.

8. Из сценария нельзя вызывать функции Win32 API

Как вызвать функцию API из сценария — типичный вопрос, задаваемый теми, кто имеет опыт работы с VB или Visual Basic for Applications (VBA), а также теми, кто пытался конвертировать код VB/VBA в сценарии VBScript. Как написано в документации по VBScript, напрямую обратиться к Win32 API из сценария нельзя. Я слышал различные объяснения этого ограничения, однако главная причина, вероятно, заключается в том, что сама идея сценариев подразумевает относительно простое и безопасное программирование, в то время как наличие возможности вызова Win32 API внесло бы некоторые коррективы в безопасность сценариев.

Имея сегодня в своем распоряжении такие технологии, как WMI и ADSI, можно решать большинство классических задач администрирования, многие из которых могли бы потребовать обращения к функциям API. Если вам кажется, что для решения задачи необходимо обратиться к API, лучше сначала посоветоваться со специалистами, имеющими опыт разработки сценариев. Опишите им проблему, но не спрашивайте, как реализовать эквивалент вызова функции API. Исходя из личного опыта могу сказать, что в большинстве ситуаций, которые, казалось бы, неизбежно требовали обращения к функциям API, проблема могла быть решена с использованием возможностей какого-либо из проверенных компонентов системы Windows. Если вы все же не смогли найти в WMI или ADSI объект, позволяющий решить имеющуюся проблему, тогда можно предложить другой подход, а именно создать на каком-либо языке программирования объект COM, который может обращаться к функциям API. Далее этот объект можно вызывать из сценариев VBScript. Однако должен заранее предупредить, что разработка COM объектов — задача далеко не простая.

9. Ищите ответы на вопросы в форумах Web

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

Познакомиться с достижениями других разработчиков можно, в частности, на сервере новостей Microsoft (news://news.microsoft.com), где представлены очень полезные группы новостей, такие как microsoft.public.windows.admin_scripting, microsoft.public.scripting.wsh и microsoft.public.scripting.vbscript. Кроме того, много интересной информации можно почерпнуть из групп, посвященных конкретным инструментальным средствам, например ADSI (microsoft.public.adsi.general), WMI (microsoft.public.win32.programmer.wmi), а также другим технологиям Microsoft.

Алекс Ангелопулос - Cпециалист по сетям, консультирующий в Индиане. Имеет сертификаты MCSE, MCP+I и MVP. alexangelopoulos@hotmail.com