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

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

Сейчас параллельно с планировщиком я также использую возможность запуска сценариев в режиме служб. Эти два подхода удачно дополняют друг друга. Для упрощения запуска сценария в качестве службы я разработал специальное приложение HTML Application (HTA). Я выбрал HTA, поскольку, в первую очередь, мне понравилось использовать в Windows приложения данного типа. Но более важно, что пользователь точно знает, какую именно информацию он должен предоставить. В тех случаях, когда текстовое поле заполняется некорректно, пользователь может ввести необходимые данные повторно. И еще одно преимущество приложений HTA заключается в том, что в них достаточно просто получить справочную информацию.

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

Пользовательский интерфейс HTA

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

Рисунок 1. Интерфейс приложения Install_service.hta

Обратите внимание на кнопку BROWSE, которая находится рядом с полем, в котором пользователь указывает путь к сценарию. При нажатии на нее пользователи могут пролистывать каталоги для указания требуемого файла, подобно тому, как это делается в большинстве Windows-приложений. Для обеспечения данной функциональности HTA использует объект UserAccounts.CommonDialog. Этот объект предоставляет стандартное диалоговое окно открытия файла (File Open). К сожалению, он имеется только в Windows XP. Однако если вы явно данному объекту, поэтому сценарий может работать и на компьютерах с Windows 2000 и более новыми версиями. Более подробное описание объекта UserAccounts.CommonDialog можно найти по адресу: http://www.microsoft.com/technet/scriptcenter/resources/qanda/jan05/hey0128.mspx.

Помимо возможности пролистывания каталогов, в HTA имеется встроенная справочная система, доступ к которой пользователь может получить, щелкнув по ссылке help. В этом случае происходит не переход по адресу в Internet, а генерируется событие onclick, что, в свою очередь, инициирует запуск процедуры helpdoc. Данная процедура вызывает окно Microsoft Internet Explorer (IE), в котором отображается справка об использовании данной формы HTA.

Когда пользователь нажимает в окне интерфейса кнопку Install Service, сценарий вызывает процедуру getfile, показанную в Листинге 1. Данная процедура ищет на целевом компьютере в каталоге Admin$system32 файл srvany.exe. Программа srvany.exe, имеющаяся в любом пакете Windows Resource Kit, представляет собой службу Windows, которая может запускать другое приложение. Создание пользовательских служб с помощью srvany.exe описывается в статье http://www.support.microsoft.com/default.aspx?scid=http://support.microsoft.com:80/support/kb/articles/q137/8/90.asp& NoWebContent=1.

Если процедура getfile не может найти файл srvany.exe, то выводится окно сообщения об ошибке, в котором пользователю предлагается указать место размещения файла через интерфейс HTA. После того как пользователь указал путь, процедура вызывает функцию VBScript InStr, которая ищет в описании пути строку ftp, чтобы определить, где следует искать файл srvany.exe - в сетевом каталоге либо на сайте FTP. В компании, в которой я работаю, для хранения утилит и других файлов используется сайт FTP. Если выясняется, что srvany.exe хранится на сайте FTP, процедура обращается к объекту HttpRequest (Microsoft.XMLHTTP), с помощью которого данный файл загружается в каталог Admin$system32, что иллюстрирует код в Листинге 1, обозначенный меткой A. Если же файл srvany.exe находится в разделяемом сетевом каталоге, тогда вызывается объект FileSystemObject библиотеки Microsoft Scripting Runtime, с помощью которого файл копируется в каталог Admin$system32 (см. фрагмент с меткой B Листинга 1). С объектом FileSystemObject многие, вероятно, уже знакомы, но, возможно, не всем приходилось работать с объектом HttpRequest, который является составной частью объектной модели документа XML, Microsoft XML Document Object Model (DOM). Поэтому ниже я дам краткое описание того, как данный объект используется процедурой getfile.

Объект HttpRequest может применяться для отсылки HTTP-запроса по какому-либо адресу URL, приема ответа и обработки ответа исполнительным механизмом XML DOM. В нашем случае процедура getfile направляет через HTTP запрос файла на FTP-сайт и передает полученный ответ объекту Stream (adodb.stream). Объект Stream входит в состав ActiveX Data Objects (ADO) и может использоваться для чтения, записи и управления потоками двоичных данных или текста. В нашем случае объект Stream используется для записи ответа в двоичный файл на клиентском компьютере.

Как в HTA реализуется запуск сценария в качестве службы

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

Подключение к целевому компьютеру. Для подключения к целевому компьютеру, а также для получения и передачи информации, необходимой для корректного функционирования службы, HTA использует возможности интерфейса Windows Management Instrumentation (WMI). Чтобы создавать службы на удаленном компьютере, нужно обладать привилегиями администратора, поэтому в случае необходимости в форме HTA можно указывать альтернативные параметры учетной записи для подключения к удаленному компьютеру. Если вы уже являетесь администратором удаленного компьютера, то эти текстовые поля можно оставить незаполненными.

После подключения к компьютеру выполняется поиск папки %systemroot%, для чего используется свойство SystemDirectory класса Win32_OperatingSystem. Получив эти данные, HTA может копировать необходимые файлы (в первую очередь это файл srvany.exe и сам сценарий, который должен быть запущен в качестве службы) в нужное место и занести эту информацию в реестр, чтобы служба могла "знать", где искать нужные ей файлы. Если HTA не может скопировать файлы, то в этом случае будет предпринята попытка отобразить сетевой диск (Z: на Admin$system32) с использованием заданных альтернативных параметров учетной записи, с тем чтобы попытаться скопировать файлы. Если и в этом случае скопировать файлы не удается, сценарий завершает выполнение.

Создание службы. Создание службы на целевом компьютере осуществляется путем вызова метода Create класса Win32_BaseService. Данному методу может быть передано до 12 параметров. В рассматриваемой форме HTA используется только часть из них.

  • Первый параметр определяет имя службы. В данном случае это значение находится в переменной Service, которое HTA извлекает из второго текстового поля интерфейса.
  • Второй параметр задает отображаемое имя службы (display name). Здесь также используется значение, находящееся в переменной Service.
  • Третий параметр представляет собой полный (fully qualified) путь к исполняемому файлу, реализующему функциональность службы (в данном случае им является srvany.exe).
  • Четвертый параметр определяет тип службы. В данном случае в HTA задается тип "собственный процесс" (Own Process), чему соответствует число 16. Это означает, что сценарий будет запускаться в виде отдельного процесса. Для большей наглядности представления типа службы при анализе кода HTA другими пользователями данный тип службы определяется константой с именем OWN_ PROCESS.
  • Пятым параметром устанавливается уровень критичности ошибки, соответствующей случаю, когда после перезагрузки компьютера метод Create не может запуститься. В сценарии HTA для этого служит константа NORMAL_ERROR_CONTROL, в которой задан уровень критичности Normal (значение 1), который означает, что при возникновении данной ошибки пользователю будет послано уведомление.
  • Шестой параметр определяет тип запуска службы. В данном сценарии HTA данный параметр устанавливается в Automatic; это указывает на то, что служба будет запускаться при каждом перезапуске компьютера.
  • Седьмой параметр определяет, может ли служба интерактивно взаимодействовать с рабочим столом. В нашем случае в сценарии HTA используется константа NOT _INTERACTIVE, запрещающая службе интерактивное взаимодействие.

Чтобы ознакомиться с остальными параметрами метода Create, обратитесь к статье http://www.msdn.microsoft.com/library/default.asp?url=/library/en-us/wmisdk/wmi/create_method_in_class_win32_baseservice.asp.

Настройка параметров службы в реестре. Без соответствующего редактирования реестра служба не запустится. Для внесения необходимых изменений в реестр сценарий HTA обращается к классу WMI StdRegProv (Листинг 2). Данный класс предоставляет методы для записи и чтения данных из реестра.

Сначала создается раздел реестра HKEY_LOCAL_MACHINE/SYSTEM/CurrentControlSet/Services/service_name, где service_name соответствует имени создаваемой службы. Затем добавляется подключ Parameters. Далее, как показано во фрагменте с меткой B Листинга 2, в этот раздел добавляется два параметра. Первый из них называется Application, ему назначается тип данных REG_SZ и записывается значение, соответствующее описанию к серверу сценариев WScript (через который будет выполняться сценарий, запускаемый в качестве службы) и путь к файлу сценария. Второй параметр называется Descpition. Ему также назначается тип REG_SZ и он будет содержать описание службы, которое извлекается сценарием HTA из третьего текстового поля интерфейса HTA. Добавление описания очень полезно, поскольку тот, кто будет просматривать список служб через соответствующее окно панели управления, будет понимать, что делает данная служба.

Запуск службы. После внесения необходимых изменений в реестр целевого компьютера служба готова к запуску. Для запуска службы вызывается метод StartService класса Win32_ Service. Следует помнить, что после внесения каких-либо изменений в код сценария необходимо перезапустить соответствующую службу, чтобы внесенные изменения вступили в силу.

Отображение хода выполнения сценария. Для отображения хода выполнения сценария, запущенного в качестве службы, открывается окно IE. Использование окна IE в данном случае необходимо, поскольку другие приемы здесь работать не будут. Мы не можем использовать, например, функцию VBScript MsgBox или метод Popup объекта WScript.Shell, поскольку это приведет к приостановке выполнения сценария HTA. И хотя в сценарии HTA вызывается окно сообщений, предлагающее пользователю указать путь к srvany.exe, если сценарий не может найти эту утилиту сам, в данном случае приостановка не является критичной, поскольку без этих данных сценарий в любом случае выполняться не сможет. Метод Echo здесь также не годится, поскольку он является внутренним для исполнительных сред WScript и CScript, а сценарии HTA используют для своего выполнения механизмы программы mshta.exe. Отобразить ход выполнения в интерфейсе HTA также нельзя, поскольку это будет выглядеть как "зависание" сценария. И даже если сценарий будет продолжать выполняться, вы все равно не увидите никаких сообщений о ходе выполнения. Эти сообщения будут выведены только по завершении работы сценария или при прерывании его выполнения вследствие возникновения какой-либо ошибки. Если же используется окно IE, то HTA может выводить отчет о ходе выполнения на протяжении всего времени выполнения сценария.

Как адаптировать сценарий

Как упоминалось выше, сценарии, которые должны быть запущены постоянно, являются первыми кандидатами на запуск в виде служб. Примером такого сценария может служить MoveFiles.vbs, текст которого показан в Листинге 3. В данном сценарии с помощью объекта FileSystemObject выполняется перенос из локального каталога C:TempImages всех файлов, сохраненных пользователем, на некоторый сетевой ресурс. Обратите внимание, что данный сценарий не предоставляет отчет о результатах выполнения, в нем также отсутствует обработка ошибок. Поэтому, если вы захотите использовать его в промышленной эксплуатации, следует сделать его более надежным, добавив код обработки ошибок и генерации отчета о результатах.

Важно понимать, что в сценарии, который вы планируете запускать в качестве службы, должны быть абсолютно исключены какие-либо возможности вмешательства пользователя в его выполнение. В противном случае это может привести к нарушению его работы. Например, если в сценарии, запускаемом через сервер WScript, используется функция MsgBox, то он выведет соответствующее окно сообщения и приостановится до тех пор, пока не будет нажата какая-либо из кнопок в данном окне. Однако это окно может и не отобразиться на экране, например в том случае, если данный сценарий запущен в контексте учетной записи, отличной от той, под которой вы локально зарегистрировались на компьютере. Соответственно, в данной ситуации сценарий будет приостановлен на неопределенное время. Этот сценарий можно было бы запустить через Cscript, однако в данном случае есть риск появления на экране окна командной строки, если были заданы определенные параметры службы.

Отсюда следует вывод, что в таких сценариях необходимо исключить использование функции MsgBox и метода Popup. Также следует избегать использования метода Echo объекта WScript. Однако если вы хотите задействовать в сценарии метод Echo для последующей отладки, тогда можно добавить в начало сценария следующую строку (см. фрагмент с меткой A Листинга 3):

WScript.interactive = False 

При этом вывод всех подсказок будет отключен.

Если вы хотите удалить службу HTAcreated, то в Microsoft TechNet Script Center (http://www.microsoft.com/technet/scriptcenter/default.mspx) имеется сценарий, с помощью которого можно удалять эту службу как на локальном, так и на удаленном компьютерах.

Инструментарий для работы

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


Листинг 1. Подпрограмма Getfile

 

Sub getfile

  On Error Resume Next

  If Srvanyfile.value = "" Then

    MsgBox "Please enter either an FTP site address or local or network " & _

      "file name and path.",vbOKOnly,"Path required"

    Srvanyfile.focus

    Exit Sub

  End If

  ProgressWindow.focus

  sSmyfile = Srvanyfile.Value

  If Instr(lcase(sSmyfile), "ftp") Then

    ProgressWindow.document.body.insertAdjacentHTML "beforeEnd", _

      "Coping Srvany.exe to :"&strComputer & "Admin$system32
"

    Set oHTTP = CreateObject("Microsoft.XMLHTTP")

    oHTTP.open "Get", sSmyfile , False

    oHTTP.send()

    Set oStream = CreateObject("adodb.stream")

    oStream.type = adTypeBinary

    oStream.open

    oStream.write oHTTP.responseBody

    If Mapdrive = vbYes Then

      oStream.savetofile "Z:Srvany.exe", adSaveCreateOverWrite

    Else

      oStream.savetofile ""&strComputer & _

        "Admin$system32Srvany.exe", adSaveCreateOverWrite

    End If

    oStream.close

    If Err <> 0 Then

      OnError "Could not copy Srvany.exe to "&strComputer,Err.Description

      Err.Clear

      Exit Sub

    End If

  Else

    ProgressWindow.document.body.insertAdjacentHTML "beforeEnd", _

      "Coping Srvany.exe to :"&strComputer & "Admin$system32
"

    FSO.CopyFile sSmyfile,""&strComputer & "Admin$system32Srvany.exe"

    If Err <> 0 Then

      OnError "Could not copy Srvany.exe to "&strComputer,Err.Description

      Err.Clear

      Exit Sub

    End If

  End If

  RunScript

End Sub


Листинг 2. Код HTA для модификации реестра

 

Set RegService = SWBemlocator.ConnectServer(strComputer, _

  "rootdefault",UserName,Password)

Set objRegProv = RegService.Get("StdRegProv")

If Err <> 0 Then

  OnError "Could not connect to remote registy!",Err.Description

  Removesrv = msgbox("Would you like to remove "&Service&" from " & _

    "the list of services on the remote computer?",vbYesNo,"Remove Service")

  If Removesrv = vbYes Then RemoveService

  Err.Clear

  Exit Sub

End If

strKeyPath = "SYSTEMCurrentControlSetServices" & Service

objRegProv.CreateKey HKEY_LOCAL_MACHINE,strKeyPath & "Parameters"

strKeyPath1 = strKeyPath & "Parameters"

objRegProv.SetStringValue HKEY_LOCAL_MACHINE,strKeyPath1, _

  "Application", Windir & "WScript.exe " & Windir & "" & File

objRegProv.SetStringValue HKEY_LOCAL_MACHINE, strKeyPath, _

  "Description", Chr(34) & Descriptions.value & Chr(34)


Листинг 3. MoveFiles.vbs

 

Dim FSO, Files, Folder, Filename

WScript.interactive = False

On Error Resume Next

Set FSO = CreateObject("Scripting.FileSystemObject")

  Do

    runmovejob

    WScript.Echo "Waiting 30 seconds"

    WScript.Sleep 30000

  Loop

 

Sub runmovejob

  On Error Resume Next

  Set Folder = FSO.GetFolder("C:TempImages")

  Set Files = folder.Files

  WScript.Echo "checking folder for new files " & folder.path

  For Each objFile in Files

    WScript.Echo "Found File " & objFile.path

    Filename = objFile.Name

    FSO.MoveFile folder.path & "" & objFile.Name, _

      "servernamesharename" & objFile.Name

    If Err <> 0 Then WScript.Echo "Error Moving file " _

      & Err.Description:Exit Sub

    WScript.Echo "Moved File C:TempImages"&filename

    Filename = ""

  Next

End Sub