Очередная вариация на тему forever для Windows. Карты на стол: открываю сакральную тайну постоянной подписки на события WMI, да простят меня посвященные :). Если серьезно, убежден, что в приведенном ниже коде каждый разработчик, заинтересованный в применении постоянной подписки найдет для себя что-нибудь вкусное.
Как это работает.
Скрипт состоит из трех классов, отвечающих за подключение к WMI, создание постоянной подписки на события WMI и хранение информации в пространстве имен root\default, а также вступительной части, содержащей логику выполнения скрипта.
На самом деле большая часть кода (классы) мною написана уже давно, поэтому в данном случае мне оставалось написать в основном логику самого скрипта.
Скрипт подключается к WMI, создает постоянную подписку и класс в пространстве имен root\default для хранения информации, необходимой для работы скрипта.
Свойство ScriptText создаваемого потребителя событий ActiveScriptEventConsumer содержит следующий код:
Этот код сохраняем в файл (script.vbs), тестируем, после чего преобразуем в строку с помощью следующего скрипта (scr2var.vbs):
Скрипт не идеален, зато без массивов и регулярных выражений, кроме того полученную строку все равно приходится редактировать. В общем мне хватает. Кому не лень - пилите :).
Закидываем полученную строку в свойство ScriptText потребителя событий - метод Create(c_) класса Subscription - скрипт готов.
Запуск скрипта - от имени АДМИНИСТРАТОРА. Процесс запускается НЕ ИНТЕРАКТИВНО.
Подробности, примеры - в тексте скрипта.
Тестируем. У меня Windows 8 x64 со всеми параноидальными фичами безопасности.
Запускаем процесс.
Несколько раз убиваем процесс. Читаем журнал, сохраняем.
Останавливаем процесс.
Дисклеймер: за "допиливание" полученного кода с целью противозаконного использования автор ответственности не несет.
' скрипт перманентного запуска процесса,
' использует постоянную подписку на события WMI
' TODO:
' - класс в пространстве имен root\default для хранения информации об именах классов,
' используемых для хранения информации о запущенных процессах, для того чтобы выводить список
' процессов, запущенных с помощью скрипта, обращаться к процессам по индексу,
' а не запоминать информацию о параметрах запуска скрипта
' - вынести логику выполнения скрипта в отдельный класс
errString = "Примеры: " & vbCrLf & _
"- запуск notepad.exe:" & vbCrLf & _
" evermore.vbs notepad.exe" & vbCrLf & _
"- запуск notepad.exe с выводом отладочных сообщений:" & vbCrLf & _
" evermore.vbs notepad.exe /v" & vbCrLf & _
"- запуск notepad.exe с определением имени фильтра, потребителя событий и класса:" & vbCrLf & _
" evermore.vbs notepad.exe /filter:filtername /consumer:consumername /class:classname" & vbCrLf & _
"- запуск notepad.exe на удаленном компьютере:" & vbCrLf & _
" evermore.vbs notepad.exe /computer:computername /user:username /pw:password" & vbCrLf & _
"- завершние notepad.exe:" & vbCrLf & _
" evermore.vbs notepad.exe /q" & vbCrLf & _
"- заверешние notepad.exe с выводом отладочных сообщений:" & vbCrLf & _
" evermore.vbs notepad.exe /q /v" & vbCrLf & _
"- заверешние notepad.exe с определением имени фильтра, потребителя событий и класса:" & vbCrLf & _
" evermore.vbs notepad.exe /q /filter:filtername /consumer:consumername /class:classname" & vbCrLf & _
"- получение журнала мониторинга, созданного с параметрами по умолчанию, в файл:" & vbCrLf & _
" evermore.vbs /r" & vbCrLf & _
"- получение журнала мониторинга, созданного с параметрами по умолчанию, в окно консоли и в файл:" & vbCrLf & _
" evermore.vbs /r /v" & vbCrLf & _
"- получение журнала мониторинга, созданного с параметрами по умолчанию, в окно консоли:" & vbCrLf & _
" evermore.vbs /r:0 /v"
Set args = WScript.Arguments
' что делать
todo = Wazzup(args)
If todo < 0 Then
If todo = -1 Then WScript.Echo "Ошибка: недостаточно аргументов" & vbCrLf & errString
If todo = -2 Then WScript.Echo "Ошибка: неверное количество аргументов" & vbCrLf & errString
WScript.Quit
End if
' вывод отладочных сообщений
verbose = args.Named.Exists("v")
'------------------------------------------------
' подключаемся к WMI
Set objWMI = new WMI
If args.Named.Exists("computer") Then objWMI.Computer = args.Named.Item("computer")
If args.Named.Exists("user") Then objWMI.User = args.Named.Item("user")
If args.Named.Exists("pw") Then objWMI.PW = args.Named.Item("pw")
ret = objWMI.Connect()
If verbose Then WScript.Echo "Подключение к WMI: " & Not IsArray(ret)
If IsArray(ret) Then
WScript.Echo "Ошибка подключения к WMI" & vbCrLf & _
"Код ошибки: " & ret(0) & vbCrLf & "Пространство имен: " & ret(1)
WScript.Quit
End If
' проверяем регистрацию ActiveScriptEventConsumer
Set objSubscription = new Subscription
Set objSubscription.RootSubscription = objWMI.RootSubscription
Set objSubscription.RootCIMV2 = objWMI.RootCIMV2
ret = objSubscription.ScriptConsumerExists()
If verbose Then WScript.Echo "ActiveScriptEventConsumer зарегистрирован: " & CBool(ret)
If Not ret Then ' пытаемся зарегистрировать
ret = objSubscription.ScriptConsumerReg()
If verbose Then WScript.Echo "Регистрация ActiveScriptEventConsumer: " & CBool(ret)
If Not ret Then
WScript.Echo "Ошибка: не удалось зарегистрировать ActiveScriptEventConsumer"
WScript.Quit
End If
End If
'------------------------------------------------
If todo = 0 Then ' запускаем процесс не интерактивно
Set objConfig = objWMI.RootCIMV2.Get("Win32_ProcessStartup").SpawnInstance_
objConfig.ShowWindow = 0 '0 - SW_HIDE, 1 - SW_NORMAL
ret = objWMI.RootCIMV2.Get("Win32_Process").Create(args.Unnamed(0), , objConfig, pid)
If verbose Then WScript.Echo "Процесс " & args.Unnamed(0) & " запущен: " & CBool(Not ret)
If ret Then
WScript.Echo "Ошибка: не удалось запустить процесс '" & args.Unnamed(0) & "'"
WScript.Quit
End If
End If
' создаем экземпляр объекта MyClass_
Set objMyClass = New MyClass_
Set objMyClass.RootDefault = objWMI.RootDefault
If args.Named.Exists("class") Then objMyClass.Name = args.Named.Item("class")
' проверяем наличие класса
exists = objMyClass.Exists()
If verbose Then WScript.Echo "Наличие класса " & objMyClass.Name & ": " & CBool(exists)
' если запускаем процесс - создаем класс в пространстве имен root\default для хранения информации
If todo = 0 Then
ret = objMyClass.Create(args.Unnamed(0), pid)
If verbose Then WScript.Echo "Создание класса " & objMyClass.Name & " в пространстве имен root\default: " & ret
If Not ret Then
WScript.Echo "Ошибка: не удалось создать класс " & objMyClass.Name & " в пространстве имен root\default"
WScript.Quit
End If
ElseIf todo = 1 Then ' завершаем процесс
If Not exists Then
WScript.Echo "Ошибка: класс " & objMyClass.Name & " не существует"
Else
qpid = objWMI.RootDefault.Get(objMyClass.Name).PID
If verbose Then WScript.Echo "Свойство PID класса " & objMyClass.Name & ": " & qpid
Set colproc = objWMI.RootCIMV2.ExecQuery("SELECT * FROM Win32_Process WHERE ProcessID = '" & qpid & "'")
gotpid = CBool(colproc.Count)
If verbose Then WScript.Echo "Процесс PID = " & qpid & " обнаружен: " & gotpid
If gotpid Then
ret = 0
For Each proc In colproc
ret = ret + proc.Terminate()
Next
If verbose Then WScript.Echo "Процесс PID = " & qpid & " завершен: " & Not CBool(ret)
If ret Then WScript.Echo "Ошибка: не удалось завершить процесс PID = " & qpid
End If
End If
ret = objMyClass.Delete()
If verbose Then WScript.Echo "Удаление класса " & objMyClass.Name & " в пространстве имен root\default: " & CBool(ret)
If Not ret Then
WScript.Echo "Ошибка: не удалось удалить класс " & objMyClass.Name & " в пространстве имен root\default"
WScript.Quit
End If
ElseIf todo = 2 And IsEmpty(args.Named.Item("r")) Then ' читаем журнал, пишем в файл
If Not exists Then
WScript.Echo "Ошибка: класс " & objMyClass.Name & " не существует"
Else
logName = "evermore.log"
Set fso = CreateObject("Scripting.FileSystemObject")
With fso.CreateTextFile(logName, True)
With GetObject("winmgmts:\\.\root\default:" & objMyClass.Name)
s = "Created: " & .Created & vbCrLf & "Process: " & .Process & vbCrLf & _
"PID: " & .PID & vbCrLf & "Log: " & .Log
End With
.WriteLine(s)
.Close
End With
Set fso = Nothing
End If
End If
If verbose Then
If exists And todo <> 1 Then ' если не завершаем процесс
' читаем свойства созданного класса
With GetObject("winmgmts:\\.\root\default:" & objMyClass.Name)
WScript.Echo "Свойства класса " & objMyClass.Name & ":" & vbCrLf & _
"- Created: " & .Created & vbCrLf & "- Process: " & .Process & vbCrLf & _
"- PID: " & .PID & vbCrLf & "- Log: " & .Log
End With
End If
End If
' создаем подписку
If args.Named.Exists("filter") Then objSubscription.Filter = args.Named.Item("filter")
If args.Named.Exists("consumer") Then objSubscription.Consumer = args.Named.Item("consumer")
If todo = 0 Then ' если запускаем процесс
ret = objSubscription.Create(objMyClass.Name)
If verbose Then WScript.Echo "Создание подписки: " & CBool(ret)
If Not ret Then
WScript.Echo "Ошибка: не удалось создать подписку"
WScript.Quit
End If
ElseIf todo = 1 Then ' если удаляем процесс
ret = objSubscription.Delete()
If verbose Then WScript.Echo "Удаление подписки: " & CBool(ret)
If Not ret Then
WScript.Echo "Ошибка: не удалось удалить подписку"
WScript.Quit
End If
End If
Set objMyClass = Nothing
Set objSubscription = Nothing
Set objWMI = Nothing
WScript.Echo "I gonna last evermore..."
WScript.Quit 0
' -1 - недостаточно аргументов, -2 - неверное количество аргументов,
' 0 - запуск, 1 - завершение, 2 - чтение
Function Wazzup(args)
If args.Unnamed.Count = 0 And Not args.Named.Exists("r") Then
Wazzup = -1
Exit Function
ElseIf args.Named.Exists("q") And args.Named.Exists("r") Then
Wazzup = -2
Exit Function
ElseIf Not(args.Named.Exists("q") Or args.Named.Exists("r")) Then
Wazzup = 0
Exit Function
ElseIf args.Named.Exists("q") Then
Wazzup = 1
Exit Function
ElseIf args.Named.Exists("r") Then
Wazzup = 2
Exit Function
End If
End Function
' свойства:
' RootDefault, RootCIMV2, RootSubscription - пространства имен WMI
' Computer, User, PW - данные для подключения к WMI удаленного компьютера
' методы:
' Connect() - попытка подключения к WMI
' в случае ошибки возвращает массив: код ошибки и пространство имен,
' при подключении к которому произошла ошибка
Class WMI
Private m_Default, m_CIMV2, m_Subscription
Private m_Computer, m_User, m_PW
Private r1, r2, r3
Public Property Get RootDefault()
Set RootDefault = m_Default
End Property
Public Property Get RootCIMV2()
Set RootCIMV2 = m_CIMV2
End Property
Public Property Get RootSubscription()
Set RootSubscription = m_Subscription
End Property
Public Property Let Computer(i)
m_Computer = i
End Property
Public Property Let User(i)
m_User = i
End Property
Public Property Let PW(i)
m_PW = i
End Property
Private Sub Class_Initialize()
r1 = "root\default"
r2 = "root\cimv2"
r3 = "root\subscription"
End Sub
'подключение к пространствам имен
Function Connect()
On Error Resume Next
Set objLocator = CreateObject("WbemScripting.SWbemLocator")
With objLocator.Security_
.AuthenticationLevel = 6 'уровень секретности пакетов
.ImpersonationLevel = 3 'объект-сервер может пользоваться всеми правами клиента
.Privileges.Add(7) 'привилегия оператора безопасности
End With
Set m_Default = objLocator.ConnectServer(m_Computer, r1, m_User, m_PW, , , 128)
If Err.Number <> 0 Then
Connect = Array(Err.Number, r1)
Exit Function
End If
Set m_CIMV2 = objLocator.ConnectServer(m_Computer, r2, m_User, m_PW, , , 128)
If Err.Number <> 0 Then
Connect = Array(Err.Number, r2)
Exit Function
End If
Set m_Subscription = objLocator.ConnectServer(m_Computer, r3, m_User, m_PW, , , 128)
If Err.Number <> 0 Then
Connect = Array(Err.Number, r3)
Exit Function
End If
Connect = 0
End Function
End Class
' свойства:
' Filter, Consumer - имена фильтра и потребителя событий, по умолчанию MyFilter и MyConsumer
' RootSubscription, RootCIMV2 - объекты RootSubscription и RootCIMV2, необходимо присвоить значения
' методы:
' ScriptConsumerExists() - проверка регистрации ActiveScriptEventConsumer,
' возвращает True если ActiveScriptEventConsumer зарегистрирован
' ScriptConsumerReg() - попытка регистрации ActiveScriptEventConsumer,
' возвращает True в случае успешной регистрации ActiveScriptEventConsumer
' Create(с_) - создание подписки на событие, получает имя класса, в случае успеха возвращает True
' Delete() - удаление подписки на событие, в случае успеха возвращает True
Class Subscription
Private m_Filter, m_Consumer, m_Subscription, m_CIMV2
Public Property Let Filter(i)
m_Filter = i
End Property
Public Property Let Consumer(i)
m_Consumer = i
End Property
Public Property Get Filter
Filter = m_Filter
End Property
Public Property Get Consumer
Consumer = m_Consumer
End Property
Public Property Set RootSubscription(i)
Set m_Subscription = i
End Property
Public Property Set RootCIMV2(i)
Set m_CIMV2 = i
End Property
Private Sub Class_Initialize()
'значения по умолчанию
m_Filter = "MyFilter"
m_Consumer = "MyConsumer"
End Sub
'проверка регистрации стандартного потребителя ActiveScriptEventConsumer
Function ScriptConsumerExists()
On Error Resume Next
If m_Subscription.ExecQuery( _
"SELECT * FROM __Provider WHERE Name='ActiveScriptEventConsumer'").Count Then
ScriptConsumerExists = True
End If
End Function
'регистрация стандартного потребителя
Function ScriptConsumerReg()
On Error Resume Next
'конфигурируем создание процесса
Set objConfig = m_CIMV2.Get("Win32_ProcessStartup").SpawnInstance_
objConfig.ShowWindow = 0 'SW_HIDE, 1 - SW_NORMAL
'регистрация стандартного потребителя
ret = m_CIMV2.Get("Win32_Process").Create( _
"mofcomp -N:root\subscription %SystemRoot%\system32\Wbem\scrcons.mof", , objConfig, intProcessID)
If ret <> 0 Then Exit Function
'отправляем идентификатор процесса в функцию ожидания завершения процесса
ScriptConsumerReg = ProcessFinished(intProcessID)
End Function
'ожидание завершения процесса "до упора"
Function ProcessFinished(intProcessID)
On Error Resume Next
Set colProcesses = m_CIMV2.ExecNotificationQuery( _
"SELECT * FROM __InstanceDeletionEvent WITHIN 2 WHERE TargetInstance ISA 'Win32_Process'" & _
" AND TargetInstance.ProcessID = '" & intProcessID & "'")
Do
Set objProcess = colProcesses.NextEvent
If Err.Number = 0 Then ProcessFinished = True
Exit Function
Loop
End Function
'создание подписки на событие
Function Create(c_)
On Error Resume Next
sid = Array(1,2,0,0,0,0,0,5,32,0,0,0,32,2,0,0) ' sid администратора
'создание фильтра события
With m_Subscription.Get("__EventFilter").SpawnInstance_()
.Name = m_Filter
.QueryLanguage = "WQL"
.EventNamespace = "root\cimv2"
.Query = "SELECT * FROM __InstanceDeletionEvent WITHIN 2 " & _
"WHERE TargetInstance ISA 'Win32_Process' AND TargetInstance.ProcessId = '" & pid & "'"
.CreatorSID = sid
Set objFilterPath = .Put_
End With
var = "Const c_ = """ & c_ & """, f_ = """ & m_Filter & """" & vbCrLf & "With GetObject(""winmgmts:\\.\root\default:"" & c_)" & vbCrLf & " .Log = .Log & vbCrLf & Now() & "" - Process '"" & .Process & ""' stopped, pid: "" & .PID" & vbCrLf & " ret = GetObject(""winmgmts:\\.\root\cimv2"").Get(""Win32_Process"").Create(.Process, , , pid)" & vbCrLf & " created = Not CBool(ret)" & vbCrLf & " If created Then" & vbCrLf & " .PID = pid" & vbCrLf & " .Log = .Log & vbCrLf & Now() & "" - Process '"" & .Process & ""' started, pid: "" & pid" & vbCrLf & " Else" & vbCrLf & " .PID = vbNullString" & vbCrLf
var = var & " .Log = .Log & vbCrLf & Now() & "" - Fail starting process '"" & .Process & ""' started, pid: "" & pid" & vbCrLf & " End If" & vbCrLf & " .Put_" & vbCrLf & "End With" & vbCrLf & "If created Then " & vbCrLf & " Set colFilters = GetObject(""winmgmts:\\.\root\subscription"").ExecQuery( _" & vbCrLf & " ""SELECT * FROM __EventFilter WHERE Name='"" & f_ & ""'"")" & vbCrLf & " If colFilters.Count Then " & vbCrLf & " For Each objFilter In colFilters" & vbCrLf & " With objFilter" & vbCrLf & " .Query = ""SELECT * FROM __InstanceDeletionEvent WITHIN 2 "" & _" & vbCrLf
var = var & " ""WHERE TargetInstance ISA 'Win32_Process' AND TargetInstance.ProcessId = '"" & pid & ""'""" & vbCrLf & " .CreatorSID = Array(1,2,0,0,0,0,0,5,32,0,0,0,32,2,0,0) " & vbCrLf & " .Put_ " & vbCrLf & " End With " & vbCrLf & " Next" & vbCrLf & " End If " & vbCrLf & "End If"
'создание потребителя события
With m_Subscription.Get("ActiveScriptEventConsumer").SpawnInstance_()
.Name = m_Consumer
.ScriptingEngine = "VBScript"
.KillTimeout = 10 'завершить выполнение через 10 секунд
.ScriptText = var
.CreatorSID = sid
Set objConsumerPath = .Put_
End With
'связка фильтра и потребителя
With m_Subscription.Get("__FilterToConsumerBinding").SpawnInstance_()
.Filter = objFilterPath
.Consumer = objConsumerPath
.CreatorSID = sid
.Put_
End With
Set objFilterPath = Nothing
Set objConsumerPath = Nothing
If Err.Number = 0 Then Create = True
End Function
'удаление подписки на событие
Function Delete()
On Error Resume Next
'удаляем фильтр
Set colFilters = m_Subscription.ExecQuery("SELECT * FROM __EventFilter WHERE Name='" & m_Filter & "'")
If colFilters.Count Then
For Each objFilter In colFilters
objFilter.Delete_ ' удаляем сам фильтр
Next
End If
Set colFilters = Nothing
'удаляем потребителя
Set colConsumers = m_Subscription.ExecQuery("SELECT * FROM ActiveScriptEventConsumer WHERE Name='" & m_Consumer & "'")
If colConsumers.Count Then
For Each objConsumer In colConsumers
objConsumer.Delete_
Next
End If
Set colConsumers = Nothing
If Err.Number = 0 Then Delete = True
End Function
End Class
' свойства:
' Name - имя класса, по умолчанию MyClass,
' RootDefault - объект RootDefault, необходимо присвоить значение
' методы:
' Exists() - проверка существования класса в пространстве имен root\default,
' возвращает True если класс существует
' Create(proc, pid) - создание класса в пространстве имен root\default,
' получает команду запуска и ID процесса, возвращает True в случае успеха
' Delete() - удаление класса из пространства имен root\default,
' возвращает True в случае успеха
Class MyClass_
Private m_Name, m_Default
Public Property Let Name(i)
m_Name = i
End Property
Public Property Get Name
Name = m_Name
End Property
Public Property Set RootDefault(i)
Set m_Default = i
End Property
Private Sub Class_Initialize()
m_Name = "MyClass" 'по умолчанию
End Sub
'наличие класса
Function Exists()
On Error Resume Next
For Each objClass In m_Default.SubclassesOf()
If InStr(objClass.Path_.Path, m_Name) Then
Exists = True
Exit Function
End If
Next
End Function
'создаем класс
Function Create(proc, pid)
On Error Resume Next
With m_Default.Get()
.Path_.Class = m_Name
.Properties_.Add "Log", 8 'журнал
.Properties_.Add "Created", 8 'дата создания
.Properties_.Add "PID", 8 'ID процесса
.Properties_.Add "Process", 8 'команда запуска процесса
.Properties_("Log") = vbNullString 'по умолчанию
.Properties_("Created") = Now()
.Properties_("PID") = pid
.Properties_("Process") = proc
.Put_ 'пишем класс в репозиторий
End With
If Err.Number = 0 Then Create = True
End Function
'удаляем класс
Function Delete()
On Error Resume Next
With m_Default.Get()
.Path_.Class = m_Name
.Put_
End With
m_Default.Delete m_Name
If Err.Number = 0 Then Delete = True
End Function
End Class
Как это работает.
Скрипт состоит из трех классов, отвечающих за подключение к WMI, создание постоянной подписки на события WMI и хранение информации в пространстве имен root\default, а также вступительной части, содержащей логику выполнения скрипта.
На самом деле большая часть кода (классы) мною написана уже давно, поэтому в данном случае мне оставалось написать в основном логику самого скрипта.
Скрипт подключается к WMI, создает постоянную подписку и класс в пространстве имен root\default для хранения информации, необходимой для работы скрипта.
Свойство ScriptText создаваемого потребителя событий ActiveScriptEventConsumer содержит следующий код:
Const c_ = "MyClass", f_ = "MyFilter"
With GetObject("winmgmts:\\.\root\default:" & c_)
.Log = .Log & vbCrLf & Now() & " - Process '" & .Process & "' stopped, pid: " & .PID
ret = GetObject("winmgmts:\\.\root\cimv2").Get("Win32_Process").Create(.Process, , , pid)
created = Not CBool(ret)
If created Then
.PID = pid
.Log = .Log & vbCrLf & Now() & " - Process '" & .Process & "' started, pid: " & pid
Else
.PID = vbNullString
.Log = .Log & vbCrLf & Now() & " - Fail starting process '" & .Process & "' started, pid: " & pid
End If
.Put_
End With
If created Then
Set colFilters = GetObject("winmgmts:\\.\root\subscription").ExecQuery( _
"SELECT * FROM __EventFilter WHERE Name='" & f_ & "'")
If colFilters.Count Then
For Each objFilter In colFilters
With objFilter
.Query = "SELECT * FROM __InstanceDeletionEvent WITHIN 2 " & _
"WHERE TargetInstance ISA 'Win32_Process' AND TargetInstance.ProcessId = '" & pid & "'"
.CreatorSID = Array(1,2,0,0,0,0,0,5,32,0,0,0,32,2,0,0)
.Put_
End With
Next
End If
End If
Этот код сохраняем в файл (script.vbs), тестируем, после чего преобразуем в строку с помощью следующего скрипта (scr2var.vbs):
'*************************************
'создание переменной из текста скрипта
'*************************************
Set args = WScript.Arguments
If args.Count = 0 Then
WScript.Echo "Ошибка: не достаточно аргументов"
WScript.Quit
End If
max = 9 ' максимальное количество строк файла в строке присваивания значения переменной, по умолчанию - 10
If args.Named.Exists("max") Then max = CInt(args.Named.Item("max")) + 1
Set fso = CreateObject("Scripting.FileSystemObject")
With fso
If Not .FileExists(args(0)) Then
WScript.Echo "Ошибка: файл " & args(0) & " не найден"
WScript.Quit
End If
Set f1 = .OpenTextFile(args(0),1)
f2Name = args(0) & ".txt"
Set f2 = .CreateTextFile(f2Name,True)
End With
Set args = Nothing
f2.Write "var = " 'первая строка
i = 0
Do Until f1.AtEndOfStream 'читаем
If i > max Then 'новая строка
f2.Write "var = var & " & Chr(34) & Replace(Trim(f1.ReadLine),Chr(34),Chr(34) & Chr(34)) & Chr(34) & " & vbCrLf & "
i = 0
Else
If i = max Then 'последняя строка
f2.WriteLine Chr(34) & Replace(Trim(f1.ReadLine),Chr(34),Chr(34) & Chr(34)) & Chr(34) & " & vbCrLf"
Else 'обычная строка
f2.Write Chr(34) & Replace(Trim(f1.ReadLine),Chr(34),Chr(34) & Chr(34)) & Chr(34)
If Not f1.AtEndOfStream Then f2.Write " & vbCrLf & "
End If
i = i + 1
End If
Loop
f2.Close
f1.Close
Set f1 = Nothing
Set f2 = Nothing
Set fso = Nothing
WScript.Echo "Создание файла " & f2Name & " завершено"
Скрипт не идеален, зато без массивов и регулярных выражений, кроме того полученную строку все равно приходится редактировать. В общем мне хватает. Кому не лень - пилите :).
Закидываем полученную строку в свойство ScriptText потребителя событий - метод Create(c_) класса Subscription - скрипт готов.
Запуск скрипта - от имени АДМИНИСТРАТОРА. Процесс запускается НЕ ИНТЕРАКТИВНО.
Подробности, примеры - в тексте скрипта.
Тестируем. У меня Windows 8 x64 со всеми параноидальными фичами безопасности.
Запускаем процесс.
Несколько раз убиваем процесс. Читаем журнал, сохраняем.
Останавливаем процесс.
Дисклеймер: за "допиливание" полученного кода с целью противозаконного использования автор ответственности не несет.




Комментариев нет:
Отправить комментарий
Комментарий будет опубликован после модерации