|
Установка патчей на ОС Windows через vbs-скрипт.
Вопросы безопасности так или иначе появляются перед любым человеком, работающим за компьютером. Конечно, больше других это касается администраторов, отвечающих за компьютеры и компьютерные сети в организациях. Вот и я, по долгу службы неся такую ответственность на своем предприятии, вынужден решать такие проблемы - поэтому стараюсь предупредить их появление. Вопросы, касающиеся безопасности информационных систем, очень разнообразны, но как-то получается, что большинство имеет вполне определенные решения, отличающиеся техникой исполнения, используемыми продуктами, вложенными деньгами, да много еще чем. Но вот одна из них - получение и установка патчей на используемые продукты, стоит как-то немного в стороне. Довольно серьезный вопрос, решений много, кто что только (не) использует. Только что-то они не привлекают, какие ценой, какие качеством или удобством использования. Многие администраторы пускают это на самотек, ограничиваясь установками сервис-паков, но практика показала пагубность такого подхода. Поэтому я хотел бы показать вам такое решение, какое использую сам вот уже не первый год, и пояснить свою точку зрения, почему оно мне кажется лучше. Все вольны выбирать то, что им больше подходит, поэтому может кому-то и придется по душе такой вот несложный подход.
Оговоримся, что речь идет о продуктах Microsoft, причем сейчас именно об операционных системах, в частности, то, что я использую. А в последнее время я использую ОС всего трех видов Windows XP Prof ENG, Windows XP Prof RUS и Windows 2003 Server. Раньше было больше, но потом их поубавилось. Этому есть свое объяснение, но не будем уходить в сторону.
Собственно, для меня, как и для многих, сам процесс состоит из нескольких этапов.
- Определение, что нужно ставить, что не нужно.
- Получение патчей.
- Установка патчей.
Определение, что нужно ставить, что не нужно.
Этот процесс полностью доверять программам, вроде Windows Update или некоторым продуктам сторонних фирм, я считаю, нельзя. Используя интернет сайты по безопасности, и сопоставляя с результатами, полученными от аналитических программ, нужно делать выводы самостоятельно, что необходимо сделать, узнать или установить. Собственно, многие продукты дают прямые ссылки на соответствующие статьи и файлы патчей, но не едиными ими надо жить - мир богат на информацию. Правда, иногда вообще в подробности вдаваться не обязательно. Достаточно нескольких пунктов, чтобы сделать выводы - заплатку ставить или нет. Например, обновления для Internet Explorer я стараюсь ставить не откладывая. На срочность некоторых других смотрю сквозь пальцы, иногда, узнав размеры патчей. Из аналитиков я использую MBSA(Microsoft Baseline Security Analyzer) - я считаю на сегодня правильным ориентироваться на скачиваемый им с сайта Microsoft mssecure.xml, содержащий информацию о проблемах ОС. Меня устраивает эта программа, позволяющая работать как в командной строке, так и в оконном режиме. Возможно, кого-то больше устроит и GFI LANguard Network Security Scanner, использующий эту же информацию о дырах в безопасности, либо что-то еще вообще другое, не суть.
Далее: получение патчей.
Microsoft считает, что и это надо доверить автомату - тому пример и Windows Update и SUS. А у нас нет. В условиях лимитированного трафика, а попросту говоря, экономии денег, этого делать не стоит. Поэтому мы имеем выбор - поторопиться ли со скачиваем заплаток, подождать до окончания/начала месяца (как там трафик?), или вообще обменяться со знакомыми - и принимаем решение. Если же пользоваться программой - автоматом, меня, как и любого нормального администратора душит вопрос, что же качают эти программы для автоматической установки, надо - не надо ли? Первый опыт с SUS 1.0 убил наповал охоту пользоваться такими программами. Конечно, теперь они сильно продвинулись, но охоты пока не прибавилось. Кого-то, возможно, насмешит разговор о трафике в наше время, но по-моему, даже если не жалко денег на мегабайты, тупо не контролировать этот процесс. В любом случае, у каждого - свой выбор. Итак, после принятия такого рода решений, мы получаем необходимые нам заплатки, выкладываем их для возможного общего доступа. У меня они для всех трех видов ОС лежат в каталогах с номерами патчей в качестве имен.
И последний: установка.
Собственно установку выполняет vbs - скрипт, запускаемый на каждой машине в домене при входе пользователя в систему. Запуск производится из процедуры регистрации и ход его на экране никак не отображается. Скрипт проверяет операционную систему на необходимость установки того или иного патча. Информацию для этого он берет из текстового файла, отличного для каждой ОС. Поэтому установка в нашем случае сводится к правке этого файла. У меня он имеет вид текстового файла, в котором каждая строка обрабатывается последовательно и имеет вид:
--------------------------------
896424,windir,\system32\gdi32.dll,5.1.2600.2770,/quiet /norestart /o,WindowsXP-KB896424-x86-RUS.exe
--------------------------------
Шесть полей, отделенных запятыми, назначение такое: 1 - номер патча, он же название директории с устанавливаемыми заплатками; 2 - расположение файла, по которому проверяется необходимость установки конкретной заплатки на конкретном компьютере; 3 - название этого файла; 4 - версия этого файла, т.е. при версии ниже указанной должна будет проводится установка; 5 - параметры запуска патча; 6 - название файла патча. Информацию о том, какие файлы и какие версии должны иметь, я черпаю из статей о дырах в безопасности. Хотя часто можно просто копировать эту информацию из отчетов MBSA.
Все. Теперь при очередном входе в систему, скрипт проверит весь файл построчно, и при отсутствии какого-либо из обновлений произведет установку. Пользователь ничего об этом знать не будет, да и не надо ему. Если кто-то озаботится срочностью применения заплатки, можно провести перезагрузку, я так делаю только при установке сервис-паков. При обычных заплатках достаточно того, что пользователь выключит компьютер вечером, и утром все будет в порядке. Файл лога можно и не просматривать, кто хочет, тот может дописать процедуру отправки сообщения при неустановленных или неустанавливаемых заплатках. Мне достаточно файла лога.
Теперь почему меня больше всего устраивает такое решение установки патчей:
- Минимум трафика. Заплатки прокачиваются один раз, только необходимое, и под моим личным контролем.
- Я лично имею достаточные для меня знания об устанавливаемых патчах, их основных параметрах: критичность, воздействие на систему, и так далее.
- Сама установка на сотни компьютеров проходит в полностью автоматическом режиме, остается только проконтролировать результат. Ходить никуда не надо - вот это работа! :-)
- Пользователи никак не могут повлиять на установку и вообще ничего не знают, и это хорошо, и это правильно!
- Скрипт, выполняемый при логоне, выполняется каждый раз при входе и тем не менее не напрягает ни сервер, ни компьютер пользователя. Зато любой новый компьютер при входе в домен автоматом устанавливает все заплатки.
- Возможность гибкого и быстрого реагирования на какие-либо изменения в мире информационных технологий, собственными силами, путем простой правки скрипта и/или условий его выполнения. За несколько лет его использования он неоднократно редактировался.
Текст скрипта, что используется у меня, я привожу ниже, в конце статьи. Вот некоторые комментарии.
Красоту кода предлагаю навести тем, кому это жизненно важно. Тут широкий простор, я осознаю. Имена переменных, стиль форматирования, остатки кусков кода и излишество - все это присутствует. Для меня в данном конкретном случае прежде всего работоспособность, я думаю, большинству администраторов, выполняющих рутинную работу, она важнее.
Чтобы не было бестолковых ошибок установки, файл vbs вызывается из основного скрипта логона после проверки на принадлежность пользователя к группе "администраторы".
Установку на сервера я таким образом не делаю. Логин на них редок да обычно и вовсе не нужен. Просто бат-файл с патчами в нужное время и ручная перезагрузка.
Рестарт системы - по желанию, как и некоторые дополнительные строчки лога для отладки, пропуск ошибок "On Error Resume Next" и отправку сообщений на "adminacomp". Достаточно снять ремарки.
После каждого патча - таймаут 30 + 5 секунд, проверка на существование процесса "Update", ожидание когда он закончится в течении примерно полутора минут, и только затем проверка необходимости установки следующего.
Раньше была еще проверка необходимости установки заплатки по ключу реестра, но потом она как-то сама собой отпала, хотя может, кому-нибудь и потребовалась бы.
Файлы, определяющие необходимость установки, располагаются в директории патчей и у меня носят названия для XP "wxpen.txt" и "wxpru.txt". Названия, понятно, можно исправить как кому нужно или, может, правильнее их заключить в переменные.
Выбор ОС 2000 оставил, это в общем-то лишнее, но, может, кому пригодится. Оставил выбор директории с патчами и файла лога - легко можно будет попробовать. Но, чтобы не было привязки к конкретному диску или серверу, я указываю относительные пути.
Директория с патчами, само собой, должна быть доступна только на чтение, файл лога - и на запись.
Скрипт выполняется в среде Wscript.
Комментарии, какие возможно кому-то потребуются, не нашел куда особо написать. Если есть вопросы, пишите, отвечу. Если для кого-то код покажется неинтересным или ненужным разбираться с ним, можно просто скопировать содержимое в файл с расширением vbs, поправить пути к каталогу с патчами и лог - файлом (переменные strpath и strrezfile), и запускать скрипт.
Собственно, вот скрипт ---------------------------------------------------
Sub writeline(strline)
Set objTextFile = objFSO.OpenTextFile (strrezfile, ForAppending, True)
objTextFile.WriteLine(strline)
objTextFile.Close
End Sub
Sub restartcomp(strcomputer)
Call writeline(Now & "-" & WSHNetwork.Computername & " - start restart")
Const AppName = "Информация от отдела ИТ"
nastr = MsgBox_
("На вашем компьютере установлены новые файлы, и его требуется перезагрузить."_
& vbNewLine & vbNewLine &_
"Перезагрузите, пожалуйста, ваш компьютер обязательно!,_
если он в течении минуты-двух не перезагрузится сам.", vbOkOnly, AppName)
WScript.Sleep 10000
Dim OpSysSet, obj
Set OpSysSet = GetObject("winmgmts:{impersonationLevel=impersonate," & _
"(Shutdown)}//" & strComputer & "/root/cimv2").ExecQuery _
("SELECT * FROM Win32_OperatingSystem" &_
" WHERE Primary=true")
For Each obj In OpSysSet
' obj.Win32Shutdown(2)
Next
End Sub
Sub timeoutprocess
'------------------------------------------------- ждем когда процесс закончится
numcircle = 0
WScript.Sleep 5000
Do
Set colProcesses = objWMIService.ExecQuery_
("Select * from Win32_Process Where Name = 'update.exe'")
If colProcesses.Count = 0 Then
Exit Sub
Else
End If
WScript.Sleep 1000
numcircle = numcircle + 1
Loop Until numcircle > 100
End Sub
Sub provpatch(strspisfile, strveros, strverlang)
'----------------------------------------- начинаем проверку и установку патчей
strinfopatchfile = strpath & "\" & strspisfile
Set objinfopatchfile = objFSO.OpenTextFile(strinfopatchfile, ForReading)
bookrwez = "no"
Do Until objinfopatchfile.AtEndOfStream
strNextLine = objinfopatchfile.Readline
arrServiceList = Split(strNextLine , ",")
numpatch = arrServiceList(0)
If numpatch = "" or UBound(arrServiceList) <> 5 Then
Else
strCheckFileDirEnv = arrServiceList(1)
strCheckFile = arrServiceList(2)
strCheckFileNeedVersion = arrServiceList(3)
strkey = arrServiceList(4)
strStartFile = arrServiceList(5)
'------------------------------ проверка необходимости установки по версии файла
strCheckFile = LCase(Shell.ExpandEnvironmentStrings_
("%" & strCheckFileDirEnv & "%") & strCheckFile)
If objFSO.FileExists(strCheckFile) Then
If objFSO.GetFileVersion(strCheckFile) < strCheckFileNeedVersion Then
'--------------------------------------------------- запускаем установку патча
If boolinstall(numpatch, strkey, strStartFile) = "yes" Then
bookrwez = "yes"
Else
End If
Else
' Call writeline(Now & "-" & WSHNetwork.Computername & "-" & numpatch & "=ok")
End If
Else
Call writeline(Now & "-" & WSHNetwork.Computername_
& "- is dont exist file " & strCheckFile)
End If
End If
Loop
objinfopatchfile.Close
If bookrwez = "yes" Then
strmessa = "net send adminacomp " & WSHNetwork.Computername & ", start restart."
' Shell.Run strmessa
' Call restartcomp(strcomputer)
Else
Call writeline(Now & "-" & WSHNetwork.Computername & "-ok")
End If
End Sub
'---------------------------------------------------------------- end sub provpatch
Function boolinstall(numpatch, strkey, strStartFile)
boolinstall = "no"
strZapuskFile = strpath & "\" & numpatch & "\" & strStartFile
If objFSO.FileExists(strZapuskFile) Then
strzapusk = strpath & "\" & numpatch & "\" & strStartFile & " " & strkey
Shell.run strzapusk
strmessa = "net send adminacomp " & WSHNetwork.Computername_
& ", start patch " & numpatch
' Shell.Run strmessa
Call writeline(Now & "-" & WSHNetwork.Computername_
& "-" & strveros & "-" & stroslanguage & "-install-" & numpatch)
boolinstall = "yes"
WScript.Sleep 30000
Call timeoutprocess
Else
Call writeline(Now & "- is dont exist file " & strZapuskFile)
End If
End Function
'---------------------------------------------------------------- main
On Error Resume Next
' скрипт сделан 23.10.2003
' Денисов Виктор, Тольятти, v-vag@mail.ru.
Sub writeline(strline)
Set objTextFile = objFSO.OpenTextFile (strrezfile, ForAppending, True)
objTextFile.WriteLine(strline)
objTextFile.Close
End Sub
Sub restartcomp(strcomputer)
Call writeline(Now & "-" & WSHNetwork.Computername & " - start restart")
Const AppName = "Информация от отдела ИТ"
nastr = MsgBox ("На вашем компьютере установлены новые файлы, и его требуется перезагрузить." & vbNewLine & vbNewLine & "Перезагрузите, пожалуйста, ваш компьютер обязательно!, если он в течении минуты-двух не перезагрузится сам.", vbOkOnly, AppName)
WScript.Sleep 10000
Dim OpSysSet, obj
Set OpSysSet = GetObject("winmgmts:{impersonationLevel=impersonate," & _
"(Shutdown)}//" & strComputer & "/root/cimv2").ExecQuery _
("SELECT * FROM Win32_OperatingSystem" &_
" WHERE Primary=true")
For Each obj In OpSysSet
' obj.Win32Shutdown(2)
Next
End Sub
Sub timeoutprocess
'----------------------------------------------------------------------- ждем когда процесс закончится
numcircle = 0
WScript.Sleep 5000
Do
Set colProcesses = objWMIService.ExecQuery ("Select * from Win32_Process Where Name = 'update.exe'")
If colProcesses.Count = 0 Then
Exit Sub
Else
End If
WScript.Sleep 1000
numcircle = numcircle + 1
Loop Until numcircle > 100
End Sub
Sub provpatch(strspisfile, strveros, strverlang)
'------------------------------------------------------------ начинаем проверку и установку патчей
strinfopatchfile = strpath & "\" & strspisfile
Set objinfopatchfile = objFSO.OpenTextFile(strinfopatchfile, ForReading)
bookrwez = "no"
Do Until objinfopatchfile.AtEndOfStream
strNextLine = objinfopatchfile.Readline
arrServiceList = Split(strNextLine , ",")
numpatch = arrServiceList(0)
If numpatch = "" or UBound(arrServiceList) <> 5 Then
Else
strCheckFileDirEnv = arrServiceList(1)
strCheckFile = arrServiceList(2)
strCheckFileNeedVersion = arrServiceList(3)
strkey = arrServiceList(4)
strStartFile = arrServiceList(5)
'------------------------------------------------ проверка необходимости установки по версии файла
strCheckFile = LCase(Shell.ExpandEnvironmentStrings("%" & strCheckFileDirEnv & "%") & strCheckFile)
If objFSO.FileExists(strCheckFile) Then
If objFSO.GetFileVersion(strCheckFile) < strCheckFileNeedVersion Then
'----------------------------------------------------------------------- запускаем установку патча
If boolinstall(numpatch, strkey, strStartFile) = "yes" Then
bookrwez = "yes"
Else
End If
Else
' Call writeline(Now & "-" & WSHNetwork.Computername & "-" & numpatch & "=ok")
End If
Else
Call writeline(Now & "-" & WSHNetwork.Computername & "- is dont exist file " & strCheckFile)
End If
End If
Loop
objinfopatchfile.Close
If bookrwez = "yes" Then
strmessa = "net send adminacomp " & WSHNetwork.Computername & ", start restart."
' Shell.Run strmessa
' Call restartcomp(strcomputer)
Else
Call writeline(Now & "-" & WSHNetwork.Computername & "-ok")
End If
End Sub
'---------------------------------------------------------------- end sub provpatch
Function boolinstall(numpatch, strkey, strStartFile)
boolinstall = "no"
strZapuskFile = strpath & "\" & numpatch & "\" & strStartFile
If objFSO.FileExists(strZapuskFile) Then
strzapusk = strpath & "\" & numpatch & "\" & strStartFile & " " & strkey
Shell.run strzapusk
strmessa = "net send adminacomp " & WSHNetwork.Computername & ", start patch " & numpatch
' Shell.Run strmessa
Call writeline(Now & "-" & WSHNetwork.Computername & "-" & strveros & "-" & stroslanguage & "-install-" & numpatch)
boolinstall = "yes"
WScript.Sleep 30000
Call timeoutprocess
Else
Call writeline(Now & "- is dont exist file " & strZapuskFile)
End If
End Function
'---------------------------------------------------------------- main
'On Error Resume Next
strCompdisk = "c:\"
strComputer = "."
Const ForAppending = 8
Const ForReading = 1
Dim WSHNetwork, Shell, objFSO, objWMIService, colOperatingSystems
Set WSHNetwork = WScript.CreateObject("WScript.Network")
Set Shell = WScript.CreateObject("WScript.Shell")
Set objFSO = CreateObject("Scripting.FileSystemObject")
Set objWMIService = GetObject("winmgmts:" & "{impersonationLevel=impersonate}!\\" & strComputer & "\root\cimv2")
strquery = "net send adminacomp " & WSHNetwork.Computername & "-" & WSHNetwork.Username & " - start patch.vbs "
' Shell.Run strquery
'strpath = ".\patch"
'strrezfile = ".\log\patch.txt"
strpath = "c:\patch"
strrezfile = "c:\patch.txt"
Set colOperatingSystems = objWMIService.ExecQuery("Select * from Win32_OperatingSystem")
For Each objOperatingSystem in colOperatingSystems
strveros = objOperatingSystem.Version
stroslanguage = objOperatingSystem.OSLanguage
strversp1 = objOperatingSystem.ServicePackMajorVersion
Next
Select Case strveros
Case "5.0.2195"
Select Case stroslanguage
'-------------------------------------------------------------------- english 2000
Case "1033"
Call provpatch("w2ken.txt", "2000", "ENU")
'-------------------------------------------------------------------- russian 2000
Case "1049"
Call provpatch("w2kru.txt", "2000", "RUS")
End Select
Case "5.1.2600"
Select Case stroslanguage
'-------------------------------------------------------------------- english XP
Case "1033"
Call provpatch("wxpen.txt", "XP", "ENU")
'-------------------------------------------------------------------- russian XP
Case "1049"
Call provpatch("wxpru.txt", "XP", "RUS")
End Select
End Select
Set Shell = Nothing
'Wscript.Echo "End work script"
Вот конец скрипта -----------------------------------------------------------------
|