В данной статье поговорим о VBScript. Рассмотрим следующие вопросы: - что такое VBScript?; - кому это нужно и для чего?; - пример программ на VBScript; - сравнение VBScript и JavaScript.
Википедия говорит, что VBScript (Visual Basic Scripting Edition) – это скриптовый язык программирования, интерпретируемый компонентом Windows Script Host. Он широко используется при создании скриптов в операционных системах семейства Microsoft Windows. Если сказать немного проще, то VBScript – это файл с расширением vbs, который Windows воспринимается как набор инструкций. Формат этого файла – текст (*.txt). В общем, открываешь «Блокнот» и программируешь в свое удовольствие. Но может возникнуть вопрос: А кто (или что?) это все выполняет? - Ответ: сервер сценариев Windows, который ставится или обновляется вместе с Windows или с Internet Explorer.
Рассмотрим следующий вопрос, кому и для чего нужен VBScript? Ответ прост: на мой взгляд, это идеальная платформа для создания простых приложений для рутинных задач быстро и просто. Например, при каждой загрузке необходимо удалять какую-либо папку или файл, пожалуйста. Кроме этого, применяются в следующих областях, использующих продукцию Microsoft:
- автоматизация администрирования систем Windows;
- серверный программный код в страницах ASP;
- клиентские скрипты в браузере Internet Explorer.
В основном VBS-сценарии применяются для обработки данных, управления системой, работы с учетными записями пользователей и компьютеров, взаимодействия с офисными приложениями, работы с базами данными и прочих сложных задач.
Как вариант удобен для вирусописателя, как ни подло это звучит. Только при написании вирусов компиляция практически обязательна. Один из самых громких вирусов, I love you, был написан именно на VBScript, в общем, есть куда расти.
Для того, что бы программировать в среде VBScript, без компилятора, вам понадобится Notepad++, в блокноте проще, но лучше когда подсвечивается синтаксис, а также Internet Explorer, так как 80% функционала идет в комплекте с браузером. Для того, что бы программировать с компилятором, нужно установить Visual Basic Scripting Edition. VBS может запускаться в виде текстового файла, или компилированного текстового файла. В отличие от текстового файла, в котором будут видны команды, их можно редактировать, компилированный текстовый файл прочитать не удастся (сплошные крякозябры).
Скажем пару слов о спецификации. Описание всего, что поддерживает VBScript, займет много места. В принципе, не бойтесь экспериментировать, пишите код также, как и в VB, если что-то не пойдет, Вы об этом узнаете.
- Переменные:
Все переменные здесь только Variant (может содержать данные любого типа.). Переменные задаются следующим образом:
Dim x – то, что хранит переменная VBScript сам разберется.
- Функции: Все функции Visual Basic.
- Константы:
Также как и в VB, константа вызывается, например так: vbNo.
Самая, на мой взгляд, приятная фича заключается в работе с FileSystemObject. Позволяет работать с файловой системой компьютера (удалять папки, писать в файлы и т.д.).
Теперь приведу пару примеров роботы с VBScript.
Напишем программу, которая будет суммировать два числа.
Для начала, создадим файл с именем sum.vbs в него запишем следующее:
Dim a,b,c 'переменные для чисел
a = inputbox ("Введите первое число")
b = inputbox ("Введите второе число")
c = cint(a) + cint(b) 'суммируем
msgbox ("Результат: " & c) 'вывод результата
Сохраняем, запускаем, получаем следующее (рисунок анимированный):
На первый взгляд все понятно, кроме одного: cint. Так как все переменные у нас Variant, а inputbox возвращает только строку как результат, то строка c = a + b будет интерпретирована как сложение двух строк, а не чисел, при вводе чисел 1 и 2 результат будет 12. Использование функции cint возвращает значение типа Integer, после этого складывает числа.
Рассмотрим программу для работы с файловой системой. Создаем файл FileSystem.vbs и запишем в него:
Dim fso, FolderName, FileName 'переменные
'создаем объект FileSystemObject в переменную fso
Set fso = CreateObject("Scripting.FileSystemObject")
FolderName = InputBox("Имя папки?") 'имя папки
FileName = InputBox("Имя файла для создания?") 'имя файла
fso.CreateFolder ("c:\" & FolderName) 'создадим папку
MsgBox "Создана папка: " & FolderName 'сообщим пользователю
fso.CreateTextFile ("c:\" & FolderName & "\" & FileName) 'создадим файл
MsgBox "Создан файл: " & FileName 'сообщим пользователю
Сохраняем, запускаем, получаем следующее (рисунок анимированный):
Теперь объясню более внятно. Во второй строке мы создали объект FileSystemObject в переменной fso. Потом вызвали метод CreateFolder для создания папки, указав в качестве аргумента путь к папке. Потом вызвали метод CreateTextFile для создания файла.
Теперь наполним текстовый файл информацией:
Dim fso, Text, FolderName, FileName 'переменные
'создаем объект FileSystemObject в переменную fso
Set fso = CreateObject("Scripting.FileSystemObject")
FolderName = InputBox("Имя папки?") 'имя папки
FileName = InputBox("Имя файла для создания?") 'имя файла
fso.CreateFolder ("c:\" & FolderName) 'создадим папку
MsgBox "Создана папка: " & FolderName 'сообщим пользователю
Set Text = fso.CreateTextFile ("c:\" & FolderName & "\" & FileName) 'создадим файл
MsgBox "Создан файл: " & FileName 'сообщим пользователю
Text.Write "Это"
Text.WriteLine " статья о VBScript"
Text.WriteBlankLines 2
Text.WriteLine "специально для ibm.at.ua"
Text.Close
Думаю, тут все понятно. Объяснять не будем.
Рассмотрим вариант программы посложнее. Нужно узнать спецификацию своего компьютера, то есть полные данные компьютера, которые будут собраны в один файл.
Создадим файл spec_report.vbs, в который запишем следующее:
[spoiler=Код программы:]
Const SILENT = False 'тихий режим отключен, будет запрошено имя компьютера
'Const SILENT = True 'режим отчета о локальном компьютере без вывода диалогов
'где сохранять отчет
Const DATA_DIR = "comp\" 'локальный каталог + "\" в конце
'Const DATA_DIR = "\\SRV\Invent\comp\" 'сетевой ресурс + "\" в конце
'прочее
Const TITLE = "Спецификация компьютера" 'заголовок диалоговых окон
Const DATA_EXT = ".csv" 'расширение файла отчета
Const HEAD_LINE = True 'выводить заголовки в первой строке CSV-файла
'не завершать скрипт аварийно
'закомментировать на время отладки
On Error Resume Next
'== ВЫПОЛНЕНИЕ
'объект для доступа к файловой системе
Dim fso
Set fso = CreateObject("Scripting.FileSystemObject")
'объект WMI
Dim wmio
'файл отчета
Dim tf
'узнать имя локального компьютера
Dim nwo, comp
Set nwo = CreateObject("WScript.Network")
comp = LCase(nwo.ComputerName)
'запросить имя удаленного компьютера
If Not SILENT Then
comp = InputBox("Введите имя компьютера:", TITLE, comp)
'проверить доступность компьютера
If Unavailable(comp) Then
MsgBox "Компьютер недоступен:" & vbCrLf & comp, vbExclamation, TITLE
comp = ""
End If
End If
'проводим инвентаризацию данных машины
If Len(comp) > 0 Then InventComp(comp)
'если ошибка
If Len(Err.Description) > 0 Then _
If Not SILENT Then MsgBox comp & vbCrLf & "Ошибка:" & vbCrLf & Err.Description, vbExclamation, TITLE
'== ПОДПРОГРАММЫ
'инвентаризация данных компьютера, заданного сетевым именем или IP-адресом
'сохранение отчета с указанным именем
Sub InventComp(compname)
Set wmio = GetObject("WinMgmts:{impersonationLevel=impersonate}!\\" & compname & "\Root\CIMV2")
'некоторые WMI-классы поддерживаются не во всех версиях Windows
Dim build
build = BuildVersion()
'файл отчета
Set tf = fso.CreateTextFile(DATA_DIR & compname & DATA_EXT, True)
'первая строка - заголовки
If HEAD_LINE Then tf.WriteLine "Секция отчета;Параметр;Номер экземпляра;Значение"
'дата проверки
tf.WriteLine "Компьютер;Дата проверки;1;" & Now
Log "Win32_ComputerSystemProduct", _
"UUID", "", _
"Компьютер", _
"UUID"
Log "Win32_ComputerSystem", _
"Name,Domain,PrimaryOwnerName,UserName,TotalPhysicalMemory", "", _
"Компьютер", _
"Сетевое имя,Домен,Владелец,Текущий пользователь,Объем памяти (Мб)"
Log "Win32_OperatingSystem", _
"Caption,Version,CSDVersion,Description,RegisteredUser,SerialNumber,Organization,InstallDate", "", _
"Операционная система", _
"Наименование,Версия,Обновление,Описание,Зарегистрированный пользователь,Серийный номер,Организация,Дата установки"
Log "Win32_BaseBoard", _
"Manufacturer,Product,Version,SerialNumber", "", _
"Материнская плата", _
"Производитель,Наименование,Версия,Серийный номер"
Log "Win32_BIOS", _
"Manufacturer,Name,SMBIOSBIOSVersion,SerialNumber", "", _
"BIOS", _
"Производитель,Наименование,Версия,Серийный номер"
'не определяется Core 2 в XP SP2, см. http://support.microsoft.com/kb/953955
Log "Win32_Processor", _
"Name,Caption,CurrentClockSpeed,ExtClock,L2CacheSize,SocketDesignation,UniqueId", "", _
"Процессор", _
"Наименование,Описание,Частота (МГц),Частота FSB (МГц),Размер L2-кеша (кб),Разъем,UID"
Log "Win32_PhysicalMemory", _
"Capacity,Speed,DeviceLocator", "", _
"Модуль памяти", _
"Размер (Мб),Частота,Размещение"
'пропускаются USB-диски
Log "Win32_DiskDrive", _
"Model,Size,InterfaceType", "InterfaceType <> 'USB'", _
"Диск", _
"Наименование,Размер (Гб),Интерфейс"
'только локальные диски
'пропускаются USB-диски, размер которых обычно NULL
Log "Win32_LogicalDisk", _
"Name,FileSystem,Size,FreeSpace,VolumeSerialNumber", "DriveType = 3 AND Size IS NOT NULL", _
"Логический диск", _
"Наименование,Файловая система,Размер (Гб),Свободно (Гб),Серийный номер"
Log "Win32_CDROMDrive", _
"Name", "", _
"CD-привод", _
"Наименование"
'только для XP/2003 и выше
'пропускаются "двойники", имеющие в названии слово "Secondary"
If build >= 2600 Then
Log "Win32_VideoController", _
"Name,AdapterRAM,VideoProcessor,VideoModeDescription,DriverDate,DriverVersion", "NOT (Name LIKE '%Secondary')", _
"Видеоконтроллер", _
"Наименование,Объем памяти (Мб),Видеопроцессор,Режим работы,Дата драйвера,Версия драйвера"
Else 'для Windows 2000
Log "Win32_VideoController", _
"Name,AdapterRAM,VideoProcessor,VideoModeDescription,DriverDate,DriverVersion", "", _
"Видеоконтроллер", _
"Наименование,Объем памяти (Мб),Видеопроцессор,Режим работы,Дата драйвера,Версия драйвера"
End If
'только для XP/2003 и выше
'пропускаются отключенные сетевые адаптеры, в том числе минипорты
'пропускаются виртуальные адаптеры VMware
If build >= 2600 Then
Log "Win32_NetworkAdapter", _
"Name,AdapterType,PermanentAddress,MACAddress", "NetConnectionStatus > 0 AND NOT (Name LIKE 'VMware%')", _
"Сетевой адаптер", _
"Наименование,Тип,IP-адрес,MAC-адрес"
Else 'для Windows 2000
Log "Win32_NetworkAdapter", _
"Name,PermanentAddress,MACAddress", "", _
"Сетевой адаптер", _
"Наименование,IP-адрес,MAC-адрес"
End If
Log "Win32_SoundDevice", _
"Name", "", _
"Звуковое устройство", _
"Наименование"
Log "Win32_SCSIController", _
"Name", "", _
"SCSI контроллер", _
"Наименование"
'только для XP/2003 и выше
'пропускаются сетевые принтеры
'условия "Local = True Or Network = False" недостаточно для принт-серверов, поэтому проверяется порт
If build >= 2600 Then
Log "Win32_Printer", _
"Name,PortName,ShareName", "(Local = True OR Network = False) AND (PortName LIKE '%USB%' OR PortName LIKE '%LPT%')", _
"Принтер", _
"Наименование,Порт,Сетевое имя"
End If
Log "Win32_PortConnector", _
"ExternalReferenceDesignator,InternalReferenceDesignator", "", _
"Разъем порта", _
"Внешний,Внутренний"
Log "Win32_Keyboard", _
"Name,Description", "", _
"Клавиатура", _
"Наименование,Описание"
Log "Win32_PointingDevice", _
"Name", "", _
"Мышь", _
"Наименование"
'закрыть файл
tf.Close
If Not SILENT Then MsgBox "Отчет сохранен в файл:" & vbCrLf & DATA_DIR & compname & DATA_EXT, vbInformation, TITLE
End Sub
'составить WQL-запрос, выполнить и записать строку в CSV-файл
'входные параметры:
'from - класс WMI
'sel - свойства WMI, через запятую
'where - условие отбора или пустая строка
'sect - соответствующая секция отчета
'param - соответствующие параметры внутри секции отчета, через запятую
'для отображения в кратных единицах, нужно их указать в скобках
Sub Log(from, sel, where, sect, param)
Const RETURN_IMMEDIATELY = 16
Const FORWARD_ONLY = 32
Dim query, cls, item, prop
query = "Select " & sel & " From " & from
If Len(where) > 0 Then query = query & " Where " & where
Set cls = wmio.ExecQuery(query,, RETURN_IMMEDIATELY + FORWARD_ONLY)
Dim props, names, num, value
props = Split(sel, ",")
names = Split(param, ",")
num = 1 'номер экземпляра
For Each item In cls
For i = 0 To UBound(props)
'взять значение
Set prop = item.Properties_(props(i))
value = prop.Value
'без проверки на Null возможнен вылет с ошибкой
If IsNull(value) Then
value = ""
'если тип данных - массив, собрать в строку
ElseIf IsArray(value) Then
value = Join(value,",")
'если указана кратная единица измерения, перевести значение
ElseIf Right(names(i), 4) = "(Мб)" Then
value = CStr(Round(value / 1024 ^ 2))
ElseIf Right(names(i), 4) = "(Гб)" Then
value = CStr(Round(value / 1024 ^ 3))
'если тип данных - дата, преобразовать в читаемый вид
ElseIf prop.CIMType = 101 Then
value = ReadableDate(value)
End If
'вывести в файл непустое значение, заменить спецсимвол ";"
value = Trim(Replace(value, ";", "_"))
If Len(value) > 0 Then tf.WriteLine sect & ";" & names(i) & ";" & num & ";" & value
Next 'i
'перейти к следующему экземпляру
num = num + 1
Next 'item
End Sub
'преобразование даты формата DMTF в читаемый вид (ДД.ММ.ГГГГ)
'http://msdn.microsoft.com/en-us/library/aa389802.aspx
Function ReadableDate(str)
'объект недоступен в Windows 2000, поэтому см. далее
' Dim dto
' Set dto = CreateObject("WbemScripting.SWbemDateTime")
' dto.Value = str
' ReadableDate = dto.GetVarDate(True)
ReadableDate = Mid(str, 7, 2) & "." & Mid(str, 5, 2) & "." & Left(str, 4)
End Function
'узнать версию (билд) WMI-сервера
'вернуть целое число
Function BuildVersion()
Dim cls, item
Set cls = wmio.ExecQuery("Select BuildVersion From Win32_WMISetting")
For Each item In cls
BuildVersion = CInt(Left(item.BuildVersion, 4))
Next
End Function
'проверить доступность компьютера в сети
'вернуть True, если адрес недоступен
Function Unavailable(addr)
Dim wmio, ping, p
Set wmio = GetObject("WinMgmts:{impersonationLevel=impersonate}")
Set ping = wmio.ExecQuery("SELECT StatusCode FROM Win32_PingStatus WHERE Address = '" & addr & "'")
For Each p In ping
If IsNull(p.StatusCode) Then
Unavailable = True
Else
Unavailable = (p.StatusCode <> 0)
End If
Next
End Function
[/spoiler]
При запуске данного сценария, в ранее созданной папке comp появится отчет, который будет иметь имя <имя компьютера>.csv. Данные в нем хранятся в виде текста. Выдернуть их оттуда не очень удобно. Поэтому напишем еще один скрипт, для создания отчета.
Создадим файл с именем comp_report.vbs в который запишем следующее:
[spoiler=Код:]
'== НАСТРОЙКИ
Const TITLE = "Спецификация компьютеров" 'заголовок отчета и диалоговых окон
Const DATA_DIR = "comp\" 'каталог для сохранения отчетов + "\" в конце
'Const DATA_DIR = "\\SRV\Invent\comp\" 'сетевой ресурс для сохранения отчетов + "\" в конце
Const DATA_EXT = ".csv" 'расширение файлов с данными
Const HEAD_LINE = True 'пропустить первую строку в файле CSV - заголовок
Const REPORT_FILE = "comp_report_%DATE%.htm" 'имя файла для сохранения отчета
'количество, порядок и названия столбцов отчета
'значения должны соответствовать первым двум полям CSV файла!
Dim col(21) '<-- не забыть проверить верхний индекс!
col(0) = "Компьютер;Сетевое имя"
col(1) = "Компьютер;UUID"
col(2) = "Компьютер;Текущий пользователь"
col(3) = "Операционная система;Наименование"
col(4) = "Операционная система;Обновление"
col(5) = "Материнская плата;Производитель"
col(6) = "Материнская плата;Наименование"
col(7) = "Процессор;Наименование"
col(8) = "Процессор;Частота (МГц)"
col(9) = "Компьютер;Объем памяти (Мб)"
col(10) = "Модуль памяти;Размер (Мб)"
col(11) = "Модуль памяти;Частота"
col(12) = "Диск;Наименование"
col(13) = "Диск;Размер (Гб)"
col(14) = "Диск;Интерфейс"
col(15) = "CD-привод;Наименование"
col(16) = "Видеоконтроллер;Наименование"
col(17) = "Видеоконтроллер;Объем памяти (Мб)"
col(18) = "Сетевой адаптер;Наименование"
col(19) = "Сетевой адаптер;MAC-адрес"
col(20) = "Звуковое устройство;Наименование"
col(21) = "Принтер;Наименование"
'шапка и подвал отчета в формате XHTML
'оформление настраивается через CSS внутри тега <style>
Dim header, footer
header = "<html><head>" _
& "<title>" & TITLE & "</title>" & vbCrLf _
& "<meta http-equiv=""Content-Type"" content=""text/html; charset=windows-1251"" />" & vbCrLf _
& "<style><!--" & vbCrLf _
& "body,table {font: 10pt Arial, sans-serif}" & vbCrLf _
& "table {border-collapse: collapse}" & vbCrLf _
& "tr,td,th {border: 1px solid gray; padding: 8px}" & vbCrLf _
& "td {vertical-align: top}" & vbCrLf _
& "--></style>" & vbCrLf _
& "</head><body>" & vbCrLf _
& "<h3>" & TITLE & ", " & Date & "</h3>" & vbCrLf _
& "<table>" & vbCrLf
footer = "</table>" & vbCrLf _
& "</body></html>"
'не завершать скрипт аварийно
On Error Resume Next
'== ВЫПОЛНЕНИЕ
'файл отчета
Dim fso, report
Set fso = CreateObject("Scripting.FileSystemObject")
report = Replace(REPORT_FILE, "%DATE%", Date)
Set rep = fso.CreateTextFile(report, True)
rep.Write header
'шапка таблицы
rep.WriteLine "<tr><th>" & Replace(Join(col, "</th><th>"), ";", ":<br />") & "</th></tr>"
'прочитать все CSV-файлы
Dim dir, fc, f, row
Set dir = fso.GetFolder(DATA_DIR)
Set fc = dir.Files
For Each f in fc
If Right(f.Name, 4) = DATA_EXT Then row = ReadCSV(dir.Path & "\" & f.Name)
If Len(row) > 0 Then rep.WriteLine row
Next
'закрыть файл отчета
rep.Write footer
rep.Close
MsgBox "Отчет сохранен в файл:" & vbCrLf & report, vbInformation, TITLE
'== ПОДПРОГРАММЫ
'определить индекс элемента массива по его значению
'если значение не найдено, вернуть -1
Function IndexCol(s)
IndexCol = -1
Dim i
For i = 0 To UBound(col)
If col(i) = s Then
IndexCol = i
Exit For
End If
Next
End Function
'извлечь данные из файла CSV
'сформировать и вернуть строку таблицы в формате XHTML
'в случае ошибки вернуть пустую строку
Function ReadCSV(fname)
Dim tf, s, a, k, i
Dim v()
ReDim v(UBound(col))
'значение по умолчанию - "-"
For i = 0 To UBound(v)
v(i) = "-"
Next
Set tf = fso.OpenTextFile(fname)
If HEAD_LINE Then tf.ReadLine 'пропустить первую строку
Do Until tf.AtEndOfStream
s = tf.ReadLine
a = Split(s, ";")
k = a(0) & ";" & a(1)
i = IndexCol(k)
If i > -1 Then
If a(2) > 1 Then 'несколько экземпляров разделяются ";"
v(i) = v(i) & ";" & a(3)
Else
v(i) = a(3)
End If
End If
Loop
tf.Close
'несколько экземпляров оформить списком в формате XHTML
For i = 0 To UBound(v)
'If InStr(v(i), ";") Then v(i) = Replace(v(i), ";", "<br />") 'более удачный для экспорта вариант?
If InStr(v(i), ";") Then v(i) = "<ul><li>" & Replace(v(i), ";", "</li><li>") & "</li></ul>"
Next
ReadCSV = "<tr><td>" & Join(v, "</td><td>") & "</td></tr>"
End Function
[/spoiler]
После этих манипуляций, при запуске созданного сценария, будет формироваться отчет, который состоит из таблицы с данными машины. Файл отчета будет иметь имя <comp_report_dd_mm_yy>.htm.
Разберемся теперь, в чем отличия и схожести VBScript и JavaScript.
Общие черты у них присущи в следующем:
- оба языка легко выучить, создание программы не требует вложения больших денег;
- оба используются для расширения функционала страницы сайта;
- оба работают на клиентских машинах, уменьшают нагрузку на сервер;
- оба могут выполнять злонамеренные сценарии на машинах пользователя;
Теперь разберем отличия, которые очень существенны:
- JavaScript – для браузеров, является сценаримв по умолчанию, а VBScript должен быть определен как сценарий;
- JavaScript – является кросбраузерным, чего нельзя сказать о VBScript который работает только в Internet Explorer;
- JavaScript – чувствителен к регистру, VBScript – нет;
Как видно, различий не так много. JS поддерживает только функции, VBS и функции и процедуры (подпрограммы). Так что можете сделать выводы, тем, кто знает ява скрипт, будет легко освоить VBS, а тем кто не знает пока ни того не другого будет еще легче, поскольку переучиваться не придется.
Учиться лучше на примерах.
Автор: Михайлов Дмитрий