<?xml version="1.0" encoding="utf-8"?>
<feed xmlns="http://www.w3.org/2005/Atom">
	<title type="html"><![CDATA[Серый форум &mdash; WSH: forever для Windows]]></title>
	<link rel="self" href="https://forum.script-coding.com/extern.php?action=feed&amp;tid=8593&amp;type=atom" />
	<updated>2013-08-25T07:35:33Z</updated>
	<generator>PunBB</generator>
	<id>https://forum.script-coding.com/viewtopic.php?id=8593</id>
		<entry>
			<title type="html"><![CDATA[Re: WSH: forever для Windows]]></title>
			<link rel="alternate" href="https://forum.script-coding.com/viewtopic.php?pid=74910#p74910" />
			<content type="html"><![CDATA[<p>К вопросу о &quot;бесшумности&quot;. <br />Карты на стол: открываю сакральную тайну постоянной подписки на события WMI, да простят меня посвященные <img src="//forum.script-coding.com/img/smilies/smile.png" width="15" height="15" />.<br />Если серьезно, убежден, что в приведенном ниже коде каждый разработчик, заинтересованный в применении постоянной подписки найдет для себя что-нибудь вкусное.</p><div class="codebox"><pre><code>
&#039; скрипт перманентного запуска процесса, 
&#039; использует постоянную подписку на события WMI
 
&#039; TODO:
&#039; - класс в пространстве имен root\default для хранения информации об именах классов, 
&#039; используемых для хранения информации о запущенных процессах, для того чтобы выводить список 
&#039; процессов, запущенных с помощью скрипта, обращаться к процессам по индексу, 
&#039; а не запоминать информацию о параметрах запуска скрипта
&#039; - вынести логику выполнения скрипта в отдельный класс
 
errString = &quot;Примеры: &quot; &amp; vbCrLf &amp; _
  &quot;- запуск notepad.exe:&quot; &amp; vbCrLf &amp; _
  &quot;  evermore.vbs notepad.exe&quot; &amp; vbCrLf &amp; _
  &quot;- запуск notepad.exe с выводом отладочных сообщений:&quot; &amp; vbCrLf &amp; _
  &quot;  evermore.vbs notepad.exe /v&quot; &amp; vbCrLf &amp; _  
  &quot;- запуск notepad.exe с определением имени фильтра, потребителя событий и класса:&quot; &amp; vbCrLf &amp; _
  &quot;  evermore.vbs notepad.exe /filter:filtername /consumer:consumername /class:classname&quot; &amp; vbCrLf &amp; _  
  &quot;- запуск notepad.exe на удаленном компьютере:&quot; &amp; vbCrLf &amp; _
  &quot;  evermore.vbs notepad.exe /computer:computername /user:username /pw:password&quot; &amp; vbCrLf &amp; _
  &quot;- завершние notepad.exe:&quot; &amp; vbCrLf &amp; _
  &quot;  evermore.vbs notepad.exe /q&quot; &amp; vbCrLf &amp; _
  &quot;- заверешние notepad.exe с выводом отладочных сообщений:&quot; &amp; vbCrLf &amp; _
  &quot;  evermore.vbs notepad.exe /q /v&quot; &amp; vbCrLf &amp; _
  &quot;- заверешние notepad.exe с определением имени фильтра, потребителя событий и класса:&quot; &amp; vbCrLf &amp; _
  &quot;  evermore.vbs notepad.exe /q /filter:filtername /consumer:consumername /class:classname&quot; &amp; vbCrLf &amp; _
  &quot;- получение журнала мониторинга, созданного с параметрами по умолчанию, в файл:&quot; &amp; vbCrLf &amp; _
  &quot;  evermore.vbs /r&quot; &amp; vbCrLf &amp; _
  &quot;- получение журнала мониторинга, созданного с параметрами по умолчанию, в окно консоли и в файл:&quot; &amp; vbCrLf &amp; _
  &quot;  evermore.vbs /r /v&quot; &amp; vbCrLf &amp; _
  &quot;- получение журнала мониторинга, созданного с параметрами по умолчанию, в окно консоли:&quot; &amp; vbCrLf &amp; _
  &quot;  evermore.vbs /r:0 /v&quot;
 
Set args = WScript.Arguments
 
&#039; что делать
todo = Wazzup(args)
 
If todo &lt; 0 Then
 If todo = -1 Then WScript.Echo &quot;Ошибка: недостаточно аргументов&quot; &amp; vbCrLf &amp; errString
 If todo = -2 Then WScript.Echo &quot;Ошибка: неверное количество аргументов&quot; &amp; vbCrLf &amp; errString
 WScript.Quit
End if
 
&#039; вывод отладочных сообщений
verbose = args.Named.Exists(&quot;v&quot;)
 
&#039;------------------------------------------------
&#039; подключаемся к WMI
Set objWMI = new WMI
If args.Named.Exists(&quot;computer&quot;) Then objWMI.Computer = args.Named.Item(&quot;computer&quot;)
If args.Named.Exists(&quot;user&quot;) Then objWMI.User = args.Named.Item(&quot;user&quot;)
If args.Named.Exists(&quot;pw&quot;) Then objWMI.PW = args.Named.Item(&quot;pw&quot;)
ret = objWMI.Connect()
If verbose Then WScript.Echo &quot;Подключение к WMI: &quot; &amp; Not IsArray(ret)
If IsArray(ret) Then 
 WScript.Echo &quot;Ошибка подключения к WMI&quot; &amp; vbCrLf &amp; _
   &quot;Код ошибки: &quot; &amp; ret(0) &amp; vbCrLf &amp; &quot;Пространство имен: &quot; &amp; ret(1)
 WScript.Quit
End If
 
&#039; проверяем регистрацию ActiveScriptEventConsumer
Set objSubscription = new Subscription
Set objSubscription.RootSubscription = objWMI.RootSubscription
Set objSubscription.RootCIMV2 = objWMI.RootCIMV2
ret = objSubscription.ScriptConsumerExists()
If verbose Then WScript.Echo &quot;ActiveScriptEventConsumer зарегистрирован: &quot; &amp; CBool(ret)
If Not ret Then &#039; пытаемся зарегистрировать
 ret = objSubscription.ScriptConsumerReg()
 If verbose Then WScript.Echo &quot;Регистрация ActiveScriptEventConsumer: &quot; &amp; CBool(ret)
 If Not ret Then
  WScript.Echo &quot;Ошибка: не удалось зарегистрировать ActiveScriptEventConsumer&quot;
  WScript.Quit
 End If
End If
&#039;------------------------------------------------
 
If todo = 0 Then &#039; запускаем процесс не интерактивно 
 Set objConfig = objWMI.RootCIMV2.Get(&quot;Win32_ProcessStartup&quot;).SpawnInstance_
 objConfig.ShowWindow = 0 &#039;0 - SW_HIDE, 1 - SW_NORMAL
 ret = objWMI.RootCIMV2.Get(&quot;Win32_Process&quot;).Create(args.Unnamed(0), , objConfig, pid)
 If verbose Then WScript.Echo &quot;Процесс &quot; &amp; args.Unnamed(0) &amp; &quot; запущен: &quot; &amp; CBool(Not ret)
 If ret Then
  WScript.Echo &quot;Ошибка: не удалось запустить процесс &#039;&quot; &amp; args.Unnamed(0) &amp; &quot;&#039;&quot;
  WScript.Quit
 End If
End If
 
&#039; создаем экземпляр объекта MyClass_
Set objMyClass = New MyClass_
Set objMyClass.RootDefault = objWMI.RootDefault
If args.Named.Exists(&quot;class&quot;) Then objMyClass.Name = args.Named.Item(&quot;class&quot;)
&#039; проверяем наличие класса
exists = objMyClass.Exists()
If verbose Then WScript.Echo &quot;Наличие класса &quot; &amp; objMyClass.Name &amp; &quot;: &quot; &amp; CBool(exists)
 
&#039; если запускаем процесс - создаем класс в пространстве имен root\default для хранения информации
If todo = 0 Then
 ret = objMyClass.Create(args.Unnamed(0), pid)
 If verbose Then WScript.Echo &quot;Создание класса &quot; &amp; objMyClass.Name &amp; &quot; в пространстве имен root\default: &quot; &amp; ret
 If Not ret Then
  WScript.Echo &quot;Ошибка: не удалось создать класс &quot; &amp; objMyClass.Name &amp; &quot; в пространстве имен root\default&quot;
  WScript.Quit
 End If
ElseIf todo = 1 Then &#039; завершаем процесс 
 If Not exists Then
  WScript.Echo &quot;Ошибка: класс &quot; &amp; objMyClass.Name &amp; &quot; не существует&quot; 
 Else
  qpid = objWMI.RootDefault.Get(objMyClass.Name).PID
  If verbose Then WScript.Echo &quot;Свойство PID класса &quot; &amp; objMyClass.Name &amp; &quot;: &quot; &amp; qpid
  Set colproc = objWMI.RootCIMV2.ExecQuery(&quot;SELECT * FROM Win32_Process WHERE ProcessID = &#039;&quot; &amp; qpid &amp; &quot;&#039;&quot;)
  gotpid = CBool(colproc.Count)
  If verbose Then WScript.Echo &quot;Процесс PID = &quot; &amp; qpid &amp; &quot; обнаружен: &quot; &amp; gotpid
  If gotpid Then  
   ret = 0
   For Each proc In colproc
    ret = ret + proc.Terminate()
   Next
   If verbose Then WScript.Echo &quot;Процесс PID = &quot; &amp; qpid &amp; &quot; завершен: &quot; &amp; Not CBool(ret)
   If ret Then WScript.Echo &quot;Ошибка: не удалось завершить процесс PID = &quot; &amp; qpid
  End If 
 End If
  
 ret = objMyClass.Delete()
 If verbose Then WScript.Echo &quot;Удаление класса &quot; &amp; objMyClass.Name &amp; &quot; в пространстве имен root\default: &quot; &amp; CBool(ret)
 If Not ret Then
  WScript.Echo &quot;Ошибка: не удалось удалить класс &quot; &amp; objMyClass.Name &amp; &quot; в пространстве имен root\default&quot;
  WScript.Quit
 End If
ElseIf todo = 2 And IsEmpty(args.Named.Item(&quot;r&quot;)) Then &#039; читаем журнал, пишем в файл
 If Not exists Then
  WScript.Echo &quot;Ошибка: класс &quot; &amp; objMyClass.Name &amp; &quot; не существует&quot; 
 Else
  logName = &quot;evermore.log&quot;
  Set fso = CreateObject(&quot;Scripting.FileSystemObject&quot;)
  With fso.CreateTextFile(logName, True)
   With GetObject(&quot;winmgmts:\\.\root\default:&quot; &amp; objMyClass.Name)
    s = &quot;Created: &quot; &amp; .Created &amp; vbCrLf &amp; &quot;Process: &quot; &amp; .Process &amp; vbCrLf &amp; _
      &quot;PID: &quot; &amp; .PID &amp; vbCrLf &amp; &quot;Log: &quot; &amp; .Log
   End With
   .WriteLine(s)
   .Close
  End With 
  Set fso = Nothing
 End If
End If
 
If verbose Then
 If exists And todo &lt;&gt; 1 Then &#039; если не завершаем процесс
  &#039; читаем свойства созданного класса
  With GetObject(&quot;winmgmts:\\.\root\default:&quot; &amp; objMyClass.Name)
  WScript.Echo &quot;Свойства класса &quot; &amp; objMyClass.Name &amp; &quot;:&quot; &amp; vbCrLf &amp; _
    &quot;- Created: &quot; &amp; .Created &amp; vbCrLf &amp; &quot;- Process: &quot; &amp; .Process &amp; vbCrLf &amp; _
    &quot;- PID: &quot; &amp; .PID &amp; vbCrLf &amp; &quot;- Log: &quot; &amp; .Log
  End With
 End If
End If
 
&#039; создаем подписку
If args.Named.Exists(&quot;filter&quot;) Then objSubscription.Filter = args.Named.Item(&quot;filter&quot;)
If args.Named.Exists(&quot;consumer&quot;) Then objSubscription.Consumer = args.Named.Item(&quot;consumer&quot;)
If todo = 0 Then &#039; если запускаем процесс
 ret = objSubscription.Create(objMyClass.Name)
 If verbose Then WScript.Echo &quot;Создание подписки: &quot; &amp; CBool(ret)
 If Not ret Then
  WScript.Echo &quot;Ошибка: не удалось создать подписку&quot;
  WScript.Quit
 End If
ElseIf todo = 1 Then &#039; если удаляем процесс
 ret = objSubscription.Delete()
 If verbose Then WScript.Echo &quot;Удаление подписки: &quot; &amp; CBool(ret)
 If Not ret Then
  WScript.Echo &quot;Ошибка: не удалось удалить подписку&quot;
  WScript.Quit
 End If
End If
 
Set objMyClass = Nothing
Set objSubscription = Nothing
Set objWMI = Nothing
 
 
WScript.Echo &quot;I gonna last evermore...&quot;
WScript.Quit 0
 
&#039; -1 - недостаточно аргументов, -2 - неверное количество аргументов, 
&#039; 0 - запуск, 1 - завершение, 2 - чтение
Function Wazzup(args)
 If args.Unnamed.Count = 0 And Not args.Named.Exists(&quot;r&quot;) Then
  Wazzup = -1
  Exit Function
 ElseIf args.Named.Exists(&quot;q&quot;) And args.Named.Exists(&quot;r&quot;) Then
  Wazzup = -2
  Exit Function
 ElseIf Not(args.Named.Exists(&quot;q&quot;) Or args.Named.Exists(&quot;r&quot;)) Then
  Wazzup = 0
  Exit Function
 ElseIf args.Named.Exists(&quot;q&quot;) Then
  Wazzup = 1
  Exit Function
 ElseIf args.Named.Exists(&quot;r&quot;) Then
  Wazzup = 2
  Exit Function
 End If
End Function
 
&#039; свойства: 
&#039; RootDefault, RootCIMV2, RootSubscription - пространства имен WMI
&#039; Computer, User, PW - данные для подключения к WMI удаленного компьютера
&#039; методы: 
&#039; Connect() - попытка подключения к WMI
&#039; в случае ошибки возвращает массив: код ошибки и пространство имен, 
&#039; при подключении к которому произошла ошибка
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 = &quot;root\default&quot;
  r2 = &quot;root\cimv2&quot;
  r3 = &quot;root\subscription&quot;
 End Sub
  
 &#039;подключение к пространствам имен 
  Function Connect()
  On Error Resume Next
    Set objLocator = CreateObject(&quot;WbemScripting.SWbemLocator&quot;)
    With objLocator.Security_
   .AuthenticationLevel = 6 &#039;уровень секретности пакетов
   .ImpersonationLevel = 3 &#039;объект-сервер может пользоваться всеми правами клиента
   .Privileges.Add(7) &#039;привилегия оператора безопасности
  End With
   
  Set m_Default = objLocator.ConnectServer(m_Computer, r1, m_User, m_PW, , , 128)
    If Err.Number &lt;&gt; 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 &lt;&gt; 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 &lt;&gt; 0 Then
      Connect = Array(Err.Number, r3)
      Exit Function
    End If
    Connect = 0  
 End Function
 
End Class
 
&#039; свойства:
&#039; Filter, Consumer - имена фильтра и потребителя событий, по умолчанию MyFilter и MyConsumer
&#039; RootSubscription, RootCIMV2 - объекты RootSubscription и RootCIMV2, необходимо присвоить значения
&#039; методы: 
&#039; ScriptConsumerExists() - проверка регистрации ActiveScriptEventConsumer, 
&#039; возвращает True если ActiveScriptEventConsumer зарегистрирован
&#039; ScriptConsumerReg() - попытка регистрации ActiveScriptEventConsumer, 
&#039; возвращает True в случае успешной регистрации ActiveScriptEventConsumer
&#039; Create(с_) - создание подписки на событие, получает имя класса, в случае успеха возвращает True
&#039; 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()
  &#039;значения по умолчанию
  m_Filter = &quot;MyFilter&quot;
  m_Consumer = &quot;MyConsumer&quot;
 End Sub
  
 &#039;проверка регистрации стандартного потребителя ActiveScriptEventConsumer
 Function ScriptConsumerExists()
  On Error Resume Next 
  If m_Subscription.ExecQuery( _
    &quot;SELECT * FROM __Provider WHERE Name=&#039;ActiveScriptEventConsumer&#039;&quot;).Count Then
   ScriptConsumerExists = True
  End If
 End Function
  
 &#039;регистрация стандартного потребителя
 Function ScriptConsumerReg()
  On Error Resume Next 
  &#039;конфигурируем создание процесса
  Set objConfig = m_CIMV2.Get(&quot;Win32_ProcessStartup&quot;).SpawnInstance_
  objConfig.ShowWindow = 0 &#039;SW_HIDE, 1 - SW_NORMAL
  &#039;регистрация стандартного потребителя
  ret = m_CIMV2.Get(&quot;Win32_Process&quot;).Create( _
    &quot;mofcomp -N:root\subscription %SystemRoot%\system32\Wbem\scrcons.mof&quot;, , objConfig, intProcessID)
  If ret &lt;&gt; 0 Then Exit Function
  &#039;отправляем идентификатор процесса в функцию ожидания завершения процесса
  ScriptConsumerReg = ProcessFinished(intProcessID)
 End Function
     
 &#039;ожидание завершения процесса &quot;до упора&quot;
 Function ProcessFinished(intProcessID)
  On Error Resume Next 
  Set colProcesses = m_CIMV2.ExecNotificationQuery( _
    &quot;SELECT * FROM __InstanceDeletionEvent WITHIN 2 WHERE TargetInstance ISA &#039;Win32_Process&#039;&quot; &amp; _
    &quot; AND TargetInstance.ProcessID = &#039;&quot; &amp; intProcessID &amp; &quot;&#039;&quot;)
  Do
   Set objProcess = colProcesses.NextEvent
   If Err.Number = 0 Then ProcessFinished = True
   Exit Function
  Loop
 End Function
  
 &#039;создание подписки на событие
 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) &#039; sid администратора
  &#039;создание фильтра события
    With m_Subscription.Get(&quot;__EventFilter&quot;).SpawnInstance_()
   .Name = m_Filter
      .QueryLanguage = &quot;WQL&quot;
      .EventNamespace = &quot;root\cimv2&quot;
      .Query = &quot;SELECT * FROM __InstanceDeletionEvent WITHIN 2 &quot; &amp; _
     &quot;WHERE TargetInstance ISA &#039;Win32_Process&#039; AND TargetInstance.ProcessId = &#039;&quot; &amp; pid &amp; &quot;&#039;&quot;
   .CreatorSID = sid
      Set objFilterPath = .Put_
    End With
     
  var = &quot;Const c_ = &quot;&quot;&quot; &amp; c_ &amp; &quot;&quot;&quot;, f_ = &quot;&quot;&quot; &amp; m_Filter &amp; &quot;&quot;&quot;&quot; &amp; vbCrLf &amp; &quot;With GetObject(&quot;&quot;winmgmts:\\.\root\default:&quot;&quot; &amp; c_)&quot; &amp; vbCrLf &amp; &quot; .Log = .Log &amp; vbCrLf &amp; Now() &amp; &quot;&quot; - Process &#039;&quot;&quot; &amp; .Process &amp; &quot;&quot;&#039; stopped, pid: &quot;&quot; &amp; .PID&quot; &amp; vbCrLf &amp; &quot; ret = GetObject(&quot;&quot;winmgmts:\\.\root\cimv2&quot;&quot;).Get(&quot;&quot;Win32_Process&quot;&quot;).Create(.Process, , , pid)&quot; &amp; vbCrLf &amp; &quot; created = Not CBool(ret)&quot; &amp; vbCrLf &amp; &quot; If created Then&quot; &amp; vbCrLf &amp; &quot;  .PID = pid&quot; &amp; vbCrLf &amp; &quot;  .Log = .Log &amp; vbCrLf &amp; Now() &amp; &quot;&quot; - Process &#039;&quot;&quot; &amp; .Process &amp; &quot;&quot;&#039; started, pid: &quot;&quot; &amp; pid&quot; &amp; vbCrLf &amp; &quot; Else&quot; &amp; vbCrLf &amp; &quot;  .PID = vbNullString&quot; &amp; vbCrLf
  var = var &amp; &quot;  .Log = .Log &amp; vbCrLf &amp; Now() &amp; &quot;&quot; - Fail starting process &#039;&quot;&quot; &amp; .Process &amp; &quot;&quot;&#039; started, pid: &quot;&quot; &amp; pid&quot; &amp; vbCrLf &amp; &quot; End If&quot; &amp; vbCrLf &amp; &quot; .Put_&quot; &amp; vbCrLf &amp; &quot;End With&quot; &amp; vbCrLf &amp; &quot;If created Then &quot; &amp; vbCrLf &amp; &quot; Set colFilters = GetObject(&quot;&quot;winmgmts:\\.\root\subscription&quot;&quot;).ExecQuery( _&quot; &amp; vbCrLf &amp; &quot;   &quot;&quot;SELECT * FROM __EventFilter WHERE Name=&#039;&quot;&quot; &amp; f_ &amp; &quot;&quot;&#039;&quot;&quot;)&quot; &amp; vbCrLf &amp; &quot; If colFilters.Count Then &quot; &amp; vbCrLf &amp; &quot;  For Each objFilter In colFilters&quot; &amp; vbCrLf &amp; &quot;   With objFilter&quot; &amp; vbCrLf &amp; &quot;    .Query = &quot;&quot;SELECT * FROM __InstanceDeletionEvent WITHIN 2 &quot;&quot; &amp; _&quot; &amp; vbCrLf
  var = var &amp; &quot;      &quot;&quot;WHERE TargetInstance ISA &#039;Win32_Process&#039; AND TargetInstance.ProcessId = &#039;&quot;&quot; &amp; pid &amp; &quot;&quot;&#039;&quot;&quot;&quot; &amp; vbCrLf &amp; &quot;    .CreatorSID = Array(1,2,0,0,0,0,0,5,32,0,0,0,32,2,0,0)    &quot; &amp; vbCrLf &amp; &quot;    .Put_    &quot; &amp; vbCrLf &amp; &quot;   End With   &quot; &amp; vbCrLf &amp; &quot;  Next&quot; &amp; vbCrLf &amp; &quot; End If &quot; &amp; vbCrLf &amp; &quot;End If&quot;
   
  &#039;создание потребителя события
    With m_Subscription.Get(&quot;ActiveScriptEventConsumer&quot;).SpawnInstance_()
   .Name = m_Consumer
      .ScriptingEngine = &quot;VBScript&quot;
      .KillTimeout = 10 &#039;завершить выполнение через 10 секунд
      .ScriptText = var
   .CreatorSID = sid
      Set objConsumerPath = .Put_
    End With
     
    &#039;связка фильтра и потребителя
    With m_Subscription.Get(&quot;__FilterToConsumerBinding&quot;).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
  
 &#039;удаление подписки на событие
 Function Delete()
  On Error Resume Next
  &#039;удаляем фильтр
    Set colFilters = m_Subscription.ExecQuery(&quot;SELECT * FROM __EventFilter WHERE Name=&#039;&quot; &amp; m_Filter &amp; &quot;&#039;&quot;)
    If colFilters.Count Then
   For Each objFilter In colFilters    
        objFilter.Delete_ &#039; удаляем сам фильтр
      Next
    End If
    Set colFilters = Nothing
         
    &#039;удаляем потребителя
    Set colConsumers = m_Subscription.ExecQuery(&quot;SELECT * FROM ActiveScriptEventConsumer WHERE Name=&#039;&quot; &amp; m_Consumer &amp; &quot;&#039;&quot;)
    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
 
&#039; свойства:
&#039; Name - имя класса, по умолчанию MyClass, 
&#039; RootDefault - объект RootDefault, необходимо присвоить значение
&#039; методы:
&#039; Exists() - проверка существования класса в пространстве имен root\default, 
&#039; возвращает True если класс существует
&#039; Create(proc, pid) - создание класса в пространстве имен root\default, 
&#039; получает команду запуска и ID процесса, возвращает True в случае успеха
&#039; Delete() - удаление класса из пространства имен root\default, 
&#039; возвращает 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 = &quot;MyClass&quot; &#039;по умолчанию
 End Sub
  
 &#039;наличие класса
 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
  
 &#039;создаем класс
 Function Create(proc, pid)
  On Error Resume Next
    With m_Default.Get()
   .Path_.Class = m_Name
   .Properties_.Add &quot;Log&quot;, 8 &#039;журнал
   .Properties_.Add &quot;Created&quot;, 8 &#039;дата создания
   .Properties_.Add &quot;PID&quot;, 8 &#039;ID процесса
   .Properties_.Add &quot;Process&quot;, 8 &#039;команда запуска процесса
   .Properties_(&quot;Log&quot;) = vbNullString &#039;по умолчанию
   .Properties_(&quot;Created&quot;) = Now()
   .Properties_(&quot;PID&quot;) = pid
   .Properties_(&quot;Process&quot;) = proc
      .Put_ &#039;пишем класс в репозиторий
  End With 
  If Err.Number = 0 Then Create = True
 End Function
  
 &#039;удаляем класс
 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
</code></pre></div><p>Как это работает.</p><p>Скрипт состоит из трех классов, отвечающих за подключение к WMI, создание постоянной подписки на события WMI и хранение информации в пространстве имен root\default, а также вступительной части, содержащей логику выполнения скрипта.</p><p>На самом деле большая часть кода (классы) мною написана уже давно, поэтому в данном случае мне оставалось написать в основном логику самого скрипта.</p><p>Скрипт подключается к WMI, создает постоянную подписку и класс в пространстве имен root\default для хранения информации, необходимой для работы скрипта.</p><p>Свойство ScriptText создаваемого потребителя событий ActiveScriptEventConsumer содержит следующий код:<br /></p><div class="codebox"><pre><code>
Const c_ = &quot;MyClass&quot;, f_ = &quot;MyFilter&quot;
With GetObject(&quot;winmgmts:\\.\root\default:&quot; &amp; c_)
 .Log = .Log &amp; vbCrLf &amp; Now() &amp; &quot; - Process &#039;&quot; &amp; .Process &amp; &quot;&#039; stopped, pid: &quot; &amp; .PID
 ret = GetObject(&quot;winmgmts:\\.\root\cimv2&quot;).Get(&quot;Win32_Process&quot;).Create(.Process, , , pid)
 created = Not CBool(ret)
 If created Then
  .PID = pid
  .Log = .Log &amp; vbCrLf &amp; Now() &amp; &quot; - Process &#039;&quot; &amp; .Process &amp; &quot;&#039; started, pid: &quot; &amp; pid
 Else
  .PID = vbNullString
  .Log = .Log &amp; vbCrLf &amp; Now() &amp; &quot; - Fail starting process &#039;&quot; &amp; .Process &amp; &quot;&#039; started, pid: &quot; &amp; pid
 End If
 .Put_
End With
If created Then
 Set colFilters = GetObject(&quot;winmgmts:\\.\root\subscription&quot;).ExecQuery( _
   &quot;SELECT * FROM __EventFilter WHERE Name=&#039;&quot; &amp; f_ &amp; &quot;&#039;&quot;)
 If colFilters.Count Then
  For Each objFilter In colFilters
   With objFilter
    .Query = &quot;SELECT * FROM __InstanceDeletionEvent WITHIN 2 &quot; &amp; _
      &quot;WHERE TargetInstance ISA &#039;Win32_Process&#039; AND TargetInstance.ProcessId = &#039;&quot; &amp; pid &amp; &quot;&#039;&quot;
    .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
</code></pre></div><p>Этот код сохраняем в файл (script.vbs), тестируем, после чего преобразуем в строку с помощью следующего скрипта (scr2var.vbs):<br /></p><div class="codebox"><pre><code>
&#039;*************************************
&#039;создание переменной из текста скрипта
&#039;*************************************
Set args = WScript.Arguments
If  args.Count = 0 Then
 WScript.Echo &quot;Ошибка: не достаточно аргументов&quot;
 WScript.Quit
End If
 
max = 9 &#039; максимальное количество строк файла в строке присваивания значения переменной, по умолчанию - 10
If args.Named.Exists(&quot;max&quot;) Then max = CInt(args.Named.Item(&quot;max&quot;)) + 1
 
Set fso = CreateObject(&quot;Scripting.FileSystemObject&quot;)
With fso
 If Not .FileExists(args(0)) Then
  WScript.Echo &quot;Ошибка: файл &quot; &amp; args(0) &amp; &quot; не найден&quot;
  WScript.Quit
 End If
 Set f1 = .OpenTextFile(args(0),1)
 f2Name = args(0) &amp; &quot;.txt&quot;
 Set f2 = .CreateTextFile(f2Name,True)
End With
 
Set args = Nothing
 
f2.Write &quot;var = &quot; &#039;первая строка
i = 0
Do Until f1.AtEndOfStream &#039;читаем
 If i &gt; max Then &#039;новая строка
  f2.Write &quot;var = var &amp; &quot; &amp; Chr(34) &amp; Replace(Trim(f1.ReadLine),Chr(34),Chr(34) &amp; Chr(34)) &amp; Chr(34) &amp; &quot; &amp; vbCrLf &amp; &quot;
  i = 0
 Else
  If i = max Then &#039;последняя строка
   f2.WriteLine Chr(34) &amp; Replace(Trim(f1.ReadLine),Chr(34),Chr(34) &amp; Chr(34)) &amp; Chr(34) &amp; &quot; &amp; vbCrLf&quot;  
  Else &#039;обычная строка
   f2.Write Chr(34) &amp; Replace(Trim(f1.ReadLine),Chr(34),Chr(34) &amp; Chr(34)) &amp; Chr(34)
   If Not f1.AtEndOfStream Then f2.Write &quot; &amp; vbCrLf &amp; &quot;
  End If
  i = i + 1
 End If
Loop
f2.Close
f1.Close
Set f1 = Nothing
Set f2 = Nothing
Set fso = Nothing
WScript.Echo &quot;Создание файла &quot; &amp; f2Name &amp; &quot; завершено&quot;
</code></pre></div><p>Скрипт не идеален, зато без массивов и регулярных выражений, кроме того полученную строку все равно приходится редактировать. В общем мне хватает. Кому не лень - пилите <img src="//forum.script-coding.com/img/smilies/smile.png" width="15" height="15" />.</p><p>Закидываем полученную строку в свойство ScriptText потребителя событий - метод Create(c_) класса Subscription - скрипт готов.</p><p>Запуск скрипта - от имени АДМИНИСТРАТОРА. Процесс запускается НЕ ИНТЕРАКТИВНО.<br />Подробности, примеры - в тексте скрипта.</p><p>Тестируем. У меня Windows 8 x64 со всеми параноидальными фичами безопасности.</p><p>Запускаем процесс.<br /><span class="postimg"><img src="http://3.bp.blogspot.com/-9EvFD0LgoAo/UhmvoCSrQ_I/AAAAAAAABwE/v8AA3mtcAv0/s1600/evermore1.jpg" alt="http://3.bp.blogspot.com/-9EvFD0LgoAo/UhmvoCSrQ_I/AAAAAAAABwE/v8AA3mtcAv0/s1600/evermore1.jpg" /></span></p><p>Несколько раз убиваем процесс. Читаем журнал, сохраняем.<br /><span class="postimg"><img src="http://1.bp.blogspot.com/-ykhvE-9mB6c/Uhmv0beujgI/AAAAAAAABwM/c8iAjiKzfRU/s1600/evermore2.jpg" alt="http://1.bp.blogspot.com/-ykhvE-9mB6c/Uhmv0beujgI/AAAAAAAABwM/c8iAjiKzfRU/s1600/evermore2.jpg" /></span></p><p>Останавливаем процесс.<br /><span class="postimg"><img src="http://2.bp.blogspot.com/-rBtL-kwDL1U/Uhmv9chLL-I/AAAAAAAABwU/02wxyREC6pQ/s1600/evermore3.jpg" alt="http://2.bp.blogspot.com/-rBtL-kwDL1U/Uhmv9chLL-I/AAAAAAAABwU/02wxyREC6pQ/s1600/evermore3.jpg" /></span></p><p>Have fun <img src="//forum.script-coding.com/img/smilies/smile.png" width="15" height="15" />.</p>]]></content>
			<author>
				<name><![CDATA[dab00]]></name>
				<uri>https://forum.script-coding.com/profile.php?id=27085</uri>
			</author>
			<updated>2013-08-25T07:35:33Z</updated>
			<id>https://forum.script-coding.com/viewtopic.php?pid=74910#p74910</id>
		</entry>
		<entry>
			<title type="html"><![CDATA[Re: WSH: forever для Windows]]></title>
			<link rel="alternate" href="https://forum.script-coding.com/viewtopic.php?pid=74716#p74716" />
			<content type="html"><![CDATA[<div class="quotebox"><cite>Rumata пишет:</cite><blockquote><p>Предполагаю, что все крутится вокруг двух WQL-запросов:</p></blockquote></div><p> Есть еще __InstanceOperationEvent ... , <a href="http://blog.daspot.ru/2012/01/wmi.html">здесь</a> подробно рассматривал тему временной подписки, просто на фоне forever вспомнил, что где-то я это уже видел.<br /></p><div class="quotebox"><cite>Rumata пишет:</cite><blockquote><p>&quot;бесшумно&quot; (то есть без всплывающих окошек)</p></blockquote></div><p> Это нужно через wscript запускать, или постоянную подписку делать - бесшумнее некуда - даже если захочешь окошки не вылезут (если без файла делать).<br /></p><div class="quotebox"><cite>Rumata пишет:</cite><blockquote><p>Вот бы еще добавить запрос, который выводил бы информацию по процессам и файлам при открытии файлов</p></blockquote></div><p>По-моему это уже совсем другая история...</p>]]></content>
			<author>
				<name><![CDATA[dab00]]></name>
				<uri>https://forum.script-coding.com/profile.php?id=27085</uri>
			</author>
			<updated>2013-08-20T03:48:49Z</updated>
			<id>https://forum.script-coding.com/viewtopic.php?pid=74716#p74716</id>
		</entry>
		<entry>
			<title type="html"><![CDATA[Re: WSH: forever для Windows]]></title>
			<link rel="alternate" href="https://forum.script-coding.com/viewtopic.php?pid=74705#p74705" />
			<content type="html"><![CDATA[<p>Идея хорошая. Одно время я задавался мыслью организовать скрипт, который бы и запускался выборочно: &quot;бесшумно&quot; (то есть без всплывающих окошек) с записью в лог-файл или из консоли управляемым выводом (в консоль или файл) и выполнял заданные (программируемые) действия по заданному событию. Но бросил. Потому что стало не так актуально. Предполагаю, что все крутится вокруг двух WQL-запросов:<br /></p><div class="codebox"><pre><code>
SELECT * FROM __InstanceCreationEvent WITHIN 1 WHERE TargetInstance ISA &quot;Win32_Process&quot;
SELECT * FROM __InstanceDeletionEvent WITHIN 1 WHERE TargetInstance ISA &quot;Win32_Process&quot;
</code></pre></div><p>Все остальные пляски и хотелки творятся вокруг результатов этих запросов. Вот бы еще добавить запрос, который выводил бы информацию по процессам и файлам при открытии файлов, как изъявлялось в теме <a href="http://forum.script-coding.com/viewtopic.php?id=8543">OFF: Мониторинг изменения c:\Windows\System32\drivers\etc\hosts</a>.</p>]]></content>
			<author>
				<name><![CDATA[Rumata]]></name>
				<uri>https://forum.script-coding.com/profile.php?id=24846</uri>
			</author>
			<updated>2013-08-19T19:34:33Z</updated>
			<id>https://forum.script-coding.com/viewtopic.php?pid=74705#p74705</id>
		</entry>
		<entry>
			<title type="html"><![CDATA[WSH: forever для Windows]]></title>
			<link rel="alternate" href="https://forum.script-coding.com/viewtopic.php?pid=74701#p74701" />
			<content type="html"><![CDATA[<p>Здравствуйте, уважаемые коллеги. <br />Хочу поделиться скриптом для мониторинга процессов. Ничего такого, может сгодится на что. <br />В последнее время часто работаю с <a href="http://nodejs.org/">Node.js</a>, сервисы запускаю через <a href="https://github.com/nodejitsu/forever">forever</a>, который суть - скрипт мониторинга процессов. В моем случае актуально. <br />Решил на досуге накидать что-то подобное для Windows. </p><p>Запускается примерно так: <br /><span class="postimg"><img src="http://4.bp.blogspot.com/-G7rptKyqK_Y/UhC5O8so4FI/AAAAAAAABvA/mESUHFDdhkQ/s1600/for9.jpg" alt="http://4.bp.blogspot.com/-G7rptKyqK_Y/UhC5O8so4FI/AAAAAAAABvA/mESUHFDdhkQ/s1600/for9.jpg" /></span></p><p>Скрипт ведет вот такой лог:<br /><span class="postimg"><img src="http://2.bp.blogspot.com/-j4PKyeLZTz0/UhC893ETVuI/AAAAAAAABvk/AFpqvx3Ofxw/s1600/for11.jpg" alt="http://2.bp.blogspot.com/-j4PKyeLZTz0/UhC893ETVuI/AAAAAAAABvk/AFpqvx3Ofxw/s1600/for11.jpg" /></span></p><p>Если кому интересно, можно реализовать запуск нескольких процессов, например - передавать несколько аргументов, <br />еще какие-нибудь свистелки прикрутить, ну это из разряда todo. В общем ваши замечания, предложения.</p><div class="codebox"><pre><code>
Set args = WScript.Arguments
&#039; проверяем наличие аргумента
If args.Count = 0 Then
 WScript.Echo &quot;Please enter process name&quot;
 WScript.Quit()
ElseIf args.Count &gt; 2 Then
 WScript.Echo &quot;Too much information&quot;
 WScript.Quit()
End If
 
If args.Count = 1 Then
 Set f = New Forever
 If f.Run(args(0)) = 0 Then &#039; запускаем процесс  
  WScript.Echo &quot;Process &#039;&quot; &amp; args(0) &amp; &quot;&#039; is started, pid: &quot; &amp; f.pid
  mon = &quot;wscript.exe &quot; &amp; WScript.ScriptFullName &amp; &quot; /pid:&quot; &amp; f.pid &amp; &quot; /proc:&quot; &amp; args(0)
  If f.Run(mon) = 0 Then &#039; запускаем процесс мониторинга
   WScript.Echo &quot;Monitor started...&quot;
  Else
   WScript.Echo &quot;Failed to start process &#039;&quot; &amp; mon &amp; &quot;&#039;&quot;
  End If
 Else
  WScript.Echo &quot;Failed to start process &#039;&quot; &amp; args(0) &amp; &quot;&#039;&quot;
 End If
 Set f = Nothing
Else &#039; запускаем мониторинг
 If IsEmpty(args.Named.Item(&quot;pid&quot;)) Or IsEmpty(args.Named.Item(&quot;proc&quot;)) Then
  WScript.Echo &quot;Named arguments are missing&quot;
  WScript.Quit
 End If
 Set f = New Forever
 f.Monitor args.Named.Item(&quot;pid&quot;), args.Named.Item(&quot;proc&quot;)
End If
 
Class Forever
 Private objWMI, m_pid, m_proc &#039; команда запуска процесса
 Public Property Get pid &#039; ProcessId запущенного процесса
  pid = m_pid
 End Property
 Private Sub Class_Initialize()
  Set objWMI = GetObject(&quot;winmgmts:\\.\Root\CIMV2&quot;)
 End Sub
 Private Sub Class_Terminate()
  Set objWMI = Nothing
 End Sub
 Public Function Run(proc)  
  ret = objWMI.Get(&quot;Win32_Process&quot;).Create(proc, , , m_pid)
  If ret = 0 Then  
   Log(&quot;Process &#039;&quot; &amp; proc &amp; &quot;&#039; started, pid: &quot; &amp; m_pid)
  Else
   Log(&quot;Failed to start process &#039;&quot; &amp; proc &amp; &quot;&#039;&quot;)
  End If
  Run = ret
 End Function
 Public Sub Monitor(pid, proc)
  m_pid = pid
  m_proc = proc
  Set colEvents = objWMI.ExecNotificationQuery( _
   &quot;SELECT * FROM __InstanceDeletionEvent WITHIN 2 &quot; &amp; _
   &quot;WHERE TargetInstance ISA &#039;Win32_Process&#039; AND TargetInstance.ProcessId = &#039;&quot; &amp; m_pid &amp; &quot;&#039;&quot;)  
  Do 
   Set objEvent = colEvents.NextEvent
   Log(&quot;Process &#039;&quot; &amp; m_proc &amp; &quot;&#039; stopped, pid: &quot; &amp; m_pid)
   Do   
    ret = Run(m_proc)
    WScript.Sleep 100
   Loop Until ret = 0 &#039; пытаемся запустить процесс до победного
   Exit Do
  Loop
  Monitor m_pid, m_proc
 End Sub
 &#039; логгер
 Private Sub Log(s)
  Const logName = &quot;forever.log&quot;
  Set fso = CreateObject(&quot;Scripting.FileSystemObject&quot;)
  With fso
   path = .BuildPath(.GetParentFolderName(.GetFile(WScript.ScriptFullName)), logName)
   If Not .FileExists(path) Then
    Set fl = .CreateTextFile(path)
    fl.Close()
    Set fl = Nothing
   End If
   Set fl = .OpenTextFile(path, 8)
   With fl
    .WriteLine Now() &amp; &quot;: &quot; &amp; s
    .Close()
   End With
   Set fl = Nothing
  End With
  Set fso = Nothing
 End Sub
End Class
</code></pre></div><p>p.s. Тут недавно была <a href="http://forum.script-coding.com/viewtopic.php?id=8555">тема на форуме</a> - вот она подписка на события WMI (рыба моей мечты <img src="//forum.script-coding.com/img/smilies/smile.png" width="15" height="15" />), правда временная, но тем не менее.</p>]]></content>
			<author>
				<name><![CDATA[dab00]]></name>
				<uri>https://forum.script-coding.com/profile.php?id=27085</uri>
			</author>
			<updated>2013-08-19T17:23:20Z</updated>
			<id>https://forum.script-coding.com/viewtopic.php?pid=74701#p74701</id>
		</entry>
</feed>
