Проверка статуса антивируса в корпоративной сети посредством 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 =    "<style>" a = a& "@import ""TableFilter/filtergrid.css"";" a = a& "BODY{background-color:Lavender ;}" a = a& "TABLE{font-size: 10pt; font-family: arial;}" a = a& "TH{background-color: buttonface; }" a = a& "</style>"   objNewFile.WriteLine "<html>" objNewFile.WriteLine "<head>" objNewFile.WriteLine "<script language=""javascript"" type=""text/javascript"" src=""TableFilter/tablefilter.js""></script>" objNewFile.WriteLine "<title>AntiVirus status information</title>" objNewFile.WriteLine a & "</head><body>" objNewFile.WriteLine "<h2>AVSI -- Date: " & Now() & "</h2>"  objNewFile.WriteLine "<script type=""text/javascript"">" objNewFile.WriteLine "var tableToExcel = (function() {" objNewFile.WriteLine "	var uri = 'data:application/vnd.ms-excel;base64,'" objNewFile.WriteLine "	, template = '<html xmlns:o=""urn:schemas-microsoft-com:office:office"" xmlns:x=""urn:schemas-microsoft-com:office:excel""><head></head><body><table>{table}</table></body></html>'" 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 "</script>" objNewFile.WriteLine "<input type=""button"" onclick=""tableToExcel('table1', 'Export data')"" value=""Export data to Excel"">" 	 objNewFile.WriteLine "<table id=""table1"" BORDER=""1"" width=""100%"">"  objNewFile.WriteLine "<tr><th width=""2%"">id</th><th>Computer</th><th>AV Name</th><th>AV Status</th><th>AV Bases</th><th>Host Status</th></tr>"  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 "<tr><th>" & compid & "</th><th>" & comp & "</th><th><font color=""red"">No AntiViruses found</font></th><th><font color=""red"">Disabled</font></th><th><font color=""red"">NOT Up to Date</font></th><th><font color=""green"">Online</font></th></tr>" 		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 "<tr><th>" & compid & "</th><th>" & comp & "</th><th>" & AntiVirus.displayName & "</th><th><font color=""green"">Active</font></th><th><font color=""green"">Up to Date</font></th><th><font color=""green"">Online</font></th></tr>" 					ElseIf (AVStatus = "41010") _ 					OR (AVStatus = "61010") _ 					OR (AVStatus = "51010") Then 						objNewFile.WriteLine "<tr><th>" & compid & "</th><th>" & comp & "</th><th>" & AntiVirus.displayName & "</th><th><font color=""green"">Active</font></th><th><font color=""red"">NOT Up to Date</font></th><th><font color=""green"">Online</font></th></tr>" 					ElseIf (AVStatus = "60000") _ 					OR (AVStatus = "50000") _ 					OR (AVStatus = "40000") Then 						objNewFile.WriteLine "<tr><th>" & compid & "</th><th>" & comp & "</th><th>" & AntiVirus.displayName & "</th><th><font color=""red"">On Access scanning disabled!</font></th><th><font color=""green"">Up to Date</font></th><th><font color=""green"">Online</font></th></tr>" 					Else  						objNewFile.WriteLine "<tr><th>" & compid & "</th><th>" & comp & "</th><th>" & AntiVirus.displayName & "</th><th><font color=""purple"">Unknown</font></th><th><font color=""purple"">Unknown</font></th><th><font color=""green"">Online</font></th></tr>" 					End if 				End If 			Next 		End If 	Case 1 		objNewFile.WriteLine "<tr><th>" & compid & "</th><th>" & comp & "</th><th><font color=""purple"">Unknown</font></th><th><font color=""purple"">Unknown</font></th><th><font color=""purple"">Unknown</font></th><th><font color=""red"">Offline</font></th></tr>" 	End Select Next objNewFile.WriteLine "</table>" 	 objNewFile.WriteLine "<script language=""javascript"" type=""text/javascript"">" objNewFile.WriteLine "//<![CDATA[" objNewFile.WriteLine "var tableFilters = {" objNewFile.WriteLine "	sort_select: true," objNewFile.WriteLine "	loader: true," objNewFile.WriteLine "	rows_counter: true," objNewFile.WriteLine "	col_2: ""select""," objNewFile.WriteLine "	col_3: ""select""," objNewFile.WriteLine "	col_4: ""select""," objNewFile.WriteLine "	col_5: ""select""," objNewFile.WriteLine "	on_change: true," objNewFile.WriteLine "	display_all_text: "" [ Show all ] ""," objNewFile.WriteLine "	alternate_rows: true," objNewFile.WriteLine "}" objNewFile.WriteLine "setFilterGrid( ""table1"",tableFilters);" objNewFile.WriteLine "//]]>" objNewFile.WriteLine "</script>"  objNewFile.WriteLine "<h2>End of scan: " & Now() & "</h2>"  objNewFile.WriteLine "</body>" objNewFile.WriteLine "</html>" 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 формате и соответственно формируем страницу в самом сценарии:

Заголовок спойлера

Set objFS = CreateObject("Scripting.FileSystemObject")  Set objNewFile = objFS.CreateTextFile("C:\TEMP\AV_Check\Reports\AV_Status_Scan_is_Running.WAIT")   a =    "<style>" a = a& "@import ""TableFilter/filtergrid.css"";" a = a& "BODY{background-color:Lavender ;}" a = a& "TABLE{font-size: 10pt; font-family: arial;}" a = a& "TH{background-color: buttonface; }" a = a& "</style>"   objNewFile.WriteLine "<html>" objNewFile.WriteLine "<head>" objNewFile.WriteLine "<script language=""javascript"" type=""text/javascript"" src=""TableFilter/tablefilter.js""></script>" objNewFile.WriteLine "<title>AntiVirus status information</title>" objNewFile.WriteLine a & "</head><body>" objNewFile.WriteLine "<h2>AVSI -- Date: " & Now() & "</h2>"  objNewFile.WriteLine "<script type=""text/javascript"">" objNewFile.WriteLine "var tableToExcel = (function() {" objNewFile.WriteLine "	var uri = 'data:application/vnd.ms-excel;base64,'" objNewFile.WriteLine "	, template = '<html xmlns:o=""urn:schemas-microsoft-com:office:office"" xmlns:x=""urn:schemas-microsoft-com:office:excel""><head></head><body><table>{table}</table></body></html>'" 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 "</script>" objNewFile.WriteLine "<input type=""button"" onclick=""tableToExcel('table1', 'Export data')"" value=""Export data to Excel"">" 	 objNewFile.WriteLine "<table id=""table1"" BORDER=""1"" width=""100%"">"  objNewFile.WriteLine "<tr><th width=""2%"">id</th><th>Computer</th><th>AV Name</th><th>AV Status</th><th>AV Bases</th><th>Host Status</th></tr>"  { ... }  objNewFile.WriteLine "</table>" 	 objNewFile.WriteLine "<script language=""javascript"" type=""text/javascript"">" objNewFile.WriteLine "//<![CDATA[" objNewFile.WriteLine "var tableFilters = {" objNewFile.WriteLine "	sort_select: true," objNewFile.WriteLine "	loader: true," objNewFile.WriteLine "	rows_counter: true," objNewFile.WriteLine "	col_2: ""select""," objNewFile.WriteLine "	col_3: ""select""," objNewFile.WriteLine "	col_4: ""select""," objNewFile.WriteLine "	col_5: ""select""," objNewFile.WriteLine "	on_change: true," objNewFile.WriteLine "	display_all_text: "" [ Show all ] ""," objNewFile.WriteLine "	alternate_rows: true," objNewFile.WriteLine "}" objNewFile.WriteLine "setFilterGrid( ""table1"",tableFilters);" objNewFile.WriteLine "//]]>" objNewFile.WriteLine "</script>"  objNewFile.WriteLine "<h2>End of scan: " & Now() & "</h2>"  objNewFile.WriteLine "</body>" objNewFile.WriteLine "</html>" 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 "<tr><th>" & compid & "</th><th>" & comp & "</th><th><font color=""purple"">Unknown</font></th><th><font color=""purple"">Unknown</font></th><th><font color=""purple"">Unknown</font></th><th><font color=""red"">Offline</font></th></tr>" 	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 "<tr><th>" & compid & "</th><th>" & comp & "</th><th><font color=""red"">No AntiViruses found</font></th><th><font color=""red"">Disabled</font></th><th><font color=""red"">NOT Up to Date</font></th><th><font color=""green"">Online</font></th></tr>" 	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 "<tr><th>" & compid & "</th><th>" & comp & "</th><th>" & AntiVirus.displayName & "</th><th><font color=""green"">Active</font></th><th><font color=""green"">Up to Date</font></th><th><font color=""green"">Online</font></th></tr>" 				ElseIf (AVStatus = "41010") _ 				OR (AVStatus = "61010") _ 				OR (AVStatus = "51010") Then 					objNewFile.WriteLine "<tr><th>" & compid & "</th><th>" & comp & "</th><th>" & AntiVirus.displayName & "</th><th><font color=""green"">Active</font></th><th><font color=""red"">NOT Up to Date</font></th><th><font color=""green"">Online</font></th></tr>" 				ElseIf (AVStatus = "60000") _ 				OR (AVStatus = "50000") _ 				OR (AVStatus = "40000") Then 					objNewFile.WriteLine "<tr><th>" & compid & "</th><th>" & comp & "</th><th>" & AntiVirus.displayName & "</th><th><font color=""red"">On Access scanning disabled!</font></th><th><font color=""green"">Up to Date</font></th><th><font color=""green"">Online</font></th></tr>" 				Else  					objNewFile.WriteLine "<tr><th>" & compid & "</th><th>" & comp & "</th><th>" & AntiVirus.displayName & "</th><th><font color=""purple"">Unknown</font></th><th><font color=""purple"">Unknown</font></th><th><font color=""green"">Online</font></th></tr>" 				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()  

ссылка на оригинал статьи https://habrahabr.ru/post/279049/


Комментарии

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *