[Из песочницы] Проверка статуса антивируса в корпоративной сети посредством VBScript

Предисловие


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

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

Что же собственно нужно и как это сделать?


Первым делом было установлено, что же нужно получать от антивируса и как это сделать в короткий промежуток времени со всего домена.

Получать нужно было:

1) Наименование установленного антивируса
2) Активен ли антивирус
3) Обновлены ли на нем базы

Собственно способ был найден моментально — использовать WMI (Windows Management Instrumentation).

Пришлось погрузиться в изучение самой структуры WMI на ПК, в этом мне помог замечательный набор утилит WMI Tools.

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

Разбор полетов


Сценарий обрабатывает 3500 хостов примерно за 1 час. Собственно сам код сценария:

Код сценария
WScript.Interactive = true

compid = 0

On Error Resume Next
        
Set objDomain = GetObject("LDAP://DOMAIN/OU=Workstations,DC=DOMAIN") 

comps = Array() 

for each objDomainItem in objDomain 
        if objDomainItem.objectClass = "Computer" then
                idxLast = UBound (comps)
                ReDim Preserve comps(idxLast + 1)
                comps(idxLast + 1) = objDomainItem.dNSHostName
        end if
next

Set objFS = CreateObject("Scripting.FileSystemObject") 
Set objNewFile = objFS.CreateTextFile("C:\TEMP\AV_Check\Reports\AV_Status_Scan_is_Running.WAIT") 

a =    ""


objNewFile.WriteLine ""
objNewFile.WriteLine ""
objNewFile.WriteLine ""
objNewFile.WriteLine "AntiVirus status information"
objNewFile.WriteLine a & ""
objNewFile.WriteLine "

AVSI -- Date: " & Now() & "

" objNewFile.WriteLine " '" objNewFile.WriteLine " , base64 = function(s) { return window.btoa(unescape(encodeURIComponent(s))) }" objNewFile.WriteLine " , format = function(s, c) { return s.replace(/{(\w+)}/g, function(m, p) { return c[p]; }) }" objNewFile.WriteLine "return function(table, name) {" objNewFile.WriteLine " if (!table.nodeType) table = document.getElementById(table)" objNewFile.WriteLine " var ctx = {worksheet: name || 'Worksheet', table: table.innerHTML}" objNewFile.WriteLine " window.location.href = uri + base64(format(template, ctx))" objNewFile.WriteLine "}" objNewFile.WriteLine "})()" objNewFile.WriteLine "" objNewFile.WriteLine "" objNewFile.WriteLine "" objNewFile.WriteLine "" for each comp in comps compid = compid + 1 Set WshShell = WScript.CreateObject("WScript.Shell") Ping = WshShell.Run("ping -n 1 " & comp, 0, True) Select Case Ping Case 0 On Error Resume next Set oWMI = GetObject("winmgmts:\\" & comp & "\root\SecurityCenter2") On Error Resume next Set colAVItems = oWMI.ExecQuery("Select * from AntiVirusProduct") If colAVItems.count = 0 Then objNewFile.WriteLine "" ElseIf colAVItems.count = 1 Then For Each AntiVirus in colAVItems If (AntiVirus.displayName) <> "Windows Defender" Then AVStatus = hex(AntiVirus.ProductState) If (AVStatus = "61000") _ OR (AVStatus = "51000") _ OR (AVStatus = "41000") Then objNewFile.WriteLine "" ElseIf (AVStatus = "41010") _ OR (AVStatus = "61010") _ OR (AVStatus = "51010") Then objNewFile.WriteLine "" ElseIf (AVStatus = "60000") _ OR (AVStatus = "50000") _ OR (AVStatus = "40000") Then objNewFile.WriteLine "" Else objNewFile.WriteLine "" End if End If Next End If Case 1 objNewFile.WriteLine "" End Select Next objNewFile.WriteLine "
idComputerAV NameAV StatusAV BasesHost Status
" & compid & "" & comp & "No AntiViruses foundDisabledNOT Up to DateOnline
" & compid & "" & comp & "" & AntiVirus.displayName & "ActiveUp to DateOnline
" & compid & "" & comp & "" & AntiVirus.displayName & "ActiveNOT Up to DateOnline
" & compid & "" & comp & "" & AntiVirus.displayName & "On Access scanning disabled!Up to DateOnline
" & compid & "" & comp & "" & AntiVirus.displayName & "UnknownUnknownOnline
" & compid & "" & comp & "UnknownUnknownUnknownOffline
" objNewFile.WriteLine "" objNewFile.WriteLine "

End of scan: " & Now() & "

" objNewFile.WriteLine "" objNewFile.WriteLine "" objNewFile.Close objFS.MoveFile "C:\TEMP\AV_Check\Reports\AV_Status_Scan_is_Running.WAIT", "C:\TEMP\AV_Check\Reports\AV_Status_" & Date & "_" & Hour(Now()) & "." & Minute(Now()) & ".htm"


Что же собственно происходит? А происходит именно вот что:

1) Мы подключаемся к домену и заходим в каталог Workstations:

Подключение к домену посредством LDAP
Set objDomain = GetObject("LDAP://DOMAIN/OU=Workstations,DC=DOMAIN")



2) Создаем пустой массив, в который будут добавляться ПК пользователей с соответствующим классом Computer:

Создание и заполнение массива
for each objDomainItem in objDomain
        if objDomainItem.objectClass = "Computer" then
                idxLast = UBound (comps)
                ReDim Preserve comps(idxLast + 1)
                comps(idxLast + 1) = objDomainItem.dNSHostName
        end if
next



3) Создаем файл отчета. Отчет было решено формировать в .htm формате и соответственно формируем страницу в самом сценарии:

Формирование htm страницы
Set objFS = CreateObject("Scripting.FileSystemObject") 
Set objNewFile = objFS.CreateTextFile("C:\TEMP\AV_Check\Reports\AV_Status_Scan_is_Running.WAIT") 

a =    ""


objNewFile.WriteLine ""
objNewFile.WriteLine ""
objNewFile.WriteLine ""
objNewFile.WriteLine "AntiVirus status information"
objNewFile.WriteLine a & ""
objNewFile.WriteLine "

AVSI -- Date: " & Now() & "

" objNewFile.WriteLine "" objNewFile.WriteLine "" objNewFile.WriteLine "" objNewFile.WriteLine "" { ... } objNewFile.WriteLine "
idComputerAV NameAV StatusAV BasesHost Status
" objNewFile.WriteLine "" objNewFile.WriteLine "

End of scan: " & Now() & "

" objNewFile.WriteLine "" objNewFile.WriteLine "" objNewFile.Close


Для удобства был использован HTML Table Filter Generator, который формирует фильтры по завершению выполнения сценария по сформированной таблице с полями id, Computer, AV Name, AV Status, AV Bases.

Также добавлена кнопка выгрузки таблицы в Excel, которую я нашел на каком-то форуме (честно сказать с ней я даже не возился и оставил как есть, работает криво и, как показала практика, только под FireFox).

4) Массив у нас сформирован и хранится в памяти, теперь рассмотрим заполнение таблицы отчета. Первым делом мы ставим счетчик для присваивания id каждому хосту из массива. После этого вызываем Shell скрипт для проверки доступности хоста путем отправки на него 1 icmp пакета. Создаем условия на обработку отклика, Case 0 — хост доступен и выполняем сценарий сбора данных для заполнения таблицы, Case 1 — выводим в таблицу данные о том, что хост не доступен:

Проверка доступности хоста
for each comp in comps 
        compid = compid + 1
                
        Set WshShell = WScript.CreateObject("WScript.Shell")
        Ping = WshShell.Run("ping -n 1 " & comp, 0, True)
        Select Case Ping
        Case 0
                { ... }
        Case 1
                objNewFile.WriteLine "" & compid & "" & comp & "UnknownUnknownUnknownOffline"
        End Select
Next



5) Проверяем есть ли у нас ошибки, а если есть, то просто переходим к следующему хосту. Информация по Антивирусам, Антишпионам и Межсетевым экранам в WMI хранится в каталоге \root\SecurityCenter2, по-этому подключаемся к нему и создаем WQL запрос, который собственно и вытаскивает нужную нам информацию по продукту. Проверяем есть ли вообще на хосте антивирус, а если есть, то проверяем не Windows Defender ли он, а если даже и он, то просто игнорируем его. Каждый антивирус имеет свой код состояния, об этом я узнал на форуме:

Проверка статуса Антивируса и заполнение таблицы
On Error Resume next 
Set oWMI = GetObject("winmgmts:\\" & comp & "\root\SecurityCenter2") 
On Error Resume next 
Set colAVItems = oWMI.ExecQuery("Select * from AntiVirusProduct") 
        If colAVItems.count = 0 Then 
                objNewFile.WriteLine "" & compid & "" & comp & "No AntiViruses foundDisabledNOT Up to DateOnline"
        ElseIf colAVItems.count = 1 Then 
                For Each AntiVirus in colAVItems
                        If (AntiVirus.displayName) <> "Windows Defender" Then 
                                AVStatus = hex(AntiVirus.ProductState) 
                                If (AVStatus = "61000")  _
                                OR (AVStatus = "51000") _
                                OR (AVStatus = "41000") Then 
                                        objNewFile.WriteLine "" & compid & "" & comp & "" & AntiVirus.displayName & "ActiveUp to DateOnline"
                                ElseIf (AVStatus = "41010") _
                                OR (AVStatus = "61010") _
                                OR (AVStatus = "51010") Then
                                        objNewFile.WriteLine "" & compid & "" & comp & "" & AntiVirus.displayName & "ActiveNOT Up to DateOnline"
                                ElseIf (AVStatus = "60000") _
                                OR (AVStatus = "50000") _
                                OR (AVStatus = "40000") Then
                                        objNewFile.WriteLine "" & compid & "" & comp & "" & AntiVirus.displayName & "On Access scanning disabled!Up to DateOnline"
                                Else 
                                        objNewFile.WriteLine "" & compid & "" & comp & "" & AntiVirus.displayName & "UnknownUnknownOnline"
                                End if
                        End If
                Next
        End If



Бонус


Ну и как бонус код на Python. Он создает текстовый файл, который можно использовать для выгрузки в Excel (в виде разделителя колонок — табуляция). К сожалению посредством LDAP выгружать список хостов у меня не получилось, а так же при использовании большого списка сценарий падает, возможно кто-нибудь доработает его для своих нужд:

Сам код
import wmi
import codecs
import os

with open('Comp_list.txt','r') as list:

        file = codecs.open('text.txt', 'w', 'utf-8')

        file.write("Computer" + "        AV Name" + "  Host Status" + "      AV Status" + "        AV Bases\n")

        for comp in list:
                response = os.system("ping -n 1 " + comp)
                if response == 0:
                        path = '//%s/root/SecurityCenter2' % comp
                        c = wmi.WMI(moniker=path)
                        wql = "Select * from AntiVirusProduct"
                        wql = c.query(wql)
                        if wql == []:
                                file.write(comp + "        no AntiVirus found" + "       Online" + "   Unknown" + "  Unknown\n")
                        else:
                                for AntiVirus in wql:
                                        ProductState_in_hex = str(hex(AntiVirus.ProductState))
                                        check_install = ProductState_in_hex[0:3]
                                        check_state = ProductState_in_hex[3:5]
                                        check_updates = ProductState_in_hex[5:7]
                                        if check_state == "10" and check_updates == "00":
                                                file.write(comp + "        " + AntiVirus.displayName + " Online" + "   Active" + "   Up to Date\n")
                                        elif check_state == "10" and check_updates == "10":
                                                file.write(comp + "        " + AntiVirus.displayName + " Online" + "   Active" + "   NOT Up to Date\n")
                                        elif check_state == "00" and check_updates == "00":
                                                file.write(comp + "        " + AntiVirus.displayName + " Online" + "   On Access scanning disabled!" + "     Up to Date\n")
                                        elif check_state == "00" and check_updates == "00":
                                                file.write(comp + "        " + AntiVirus.displayName + " Online" + "   On Access scanning disabled!" + "     NOT Up to Date\n")
                                        else:
                                                file.write(comp + "        " + AntiVirus.displayName + " Online" + "   Unknown state\n" + "  " + check_install)
                else:
                        file.write(comp + "        Unknown" + "  Offline" + "  Unknown" + "  Unknown\n")
        file.close()



© Habrahabr.ru