Powershell+WMI事件订阅

 

业务场景:添加WMI事件实现对Winrm service的监控,当Winrm 异常停止时,重新启动.

BG: 在Powershell 出生之前, WMI是无可替代的远程(本地)系统管理工具。当下Powershell 已经慢慢取代了ActiveScript+WMI, 然而不可否认WMI依旧是WINDOWS系统管理的利器。

大家知道DCOM是最初WMI通讯协议,RPC也是饱受黑客眷顾的服务。而随着Winrm的普及已经对SSL/TLS的支持,管理人员更加青睐于基于Winrm通讯协议的远程管理方式。当WINRM成为了最主要的管理方式,甚至取代了RDP。为了防止因为IIS的宕机,相关服务crash而导致WINRM 服务不可用带来的管理工作的不便.  便有了此业务场景

 

查找Win32_service的元事件

考虑目标事件应该属于系统事件,并且是由确定实例发出的,可以先用下面的命令查询相应的CimClass

Get-CimClass -ClassName "__*Event" -PropertyName 'TargetInstance'


   NameSpace: ROOT/cimv2

CimClassName                        CimClassMethods      CimClassProperties                                                      
------------                        ---------------      ------------------                                                      
__InstanceOperationEvent            {}                   {SECURITY_DESCRIPTOR, TIME_CREATED, TargetInstance}                     
__InstanceModificationEvent         {}                   {SECURITY_DESCRIPTOR, TIME_CREATED, TargetInstance, PreviousInstance}   
__InstanceCreationEvent             {}                   {SECURITY_DESCRIPTOR, TIME_CREATED, TargetInstance}                     
__MethodInvocationEvent             {}                   {SECURITY_DESCRIPTOR, TIME_CREATED, TargetInstance, Method...}          
__InstanceDeletionEvent             {}                   {SECURITY_DESCRIPTOR, TIME_CREATED, TargetInstance} 

然后从微软官方文档中可以找出所有系统的wmi class, 查看__InstanceModificationEvent

https://docs.microsoft.com/en-us/windows/desktop/wmisdk/wmi-system-classes

通过查看官方文档,确定__InstanceModificationEvent就是我要找的元事件

创建EventProvider

$query = "SELECT * FROM __InstanceModificationEvent WITHIN 5 
    WHERE TargetInstance ISA 'Win32_Service' 
        and TargetInstance.Name = 'Winrm' 
        and TargetInstance.State = 'Stopped'"
$filter = Set-WmiInstance -Class __EventFilter `
 -ComputerName  "localhost" -Namespace "root\subscription" -Arguments `
  @{
    name='WinrmFilter'; 
    EventNameSpace="root\cimv2"; 
    QueryLanguage="WQL";
    Query=$query
   }

 创建EventConsumer

Consumer 选择 CommandLineEventConsumer,简单易用。 喜欢ActiveScript的同学可以选择ActiveScriptConsumer.

$Consumer = Set-WmiInstance -Class CommandLineEventConsumer `
 -ComputerName "localhost" -Namespace "root\subscription" `
 -Arguments @{name="WinrmDeamon";
  CommandLineTemplate = { powershell '
        $logPath="C:\setup\WinrmEvent.txt"
        Winrm quickconfig /q >> logPath
        get-date >> logPath
        ' 
   } ;
   ExecutablePath= 'C:\Windows\SysWOW64\WindowsPowerShell\v1.0\powershell.exe'
 }

这里的CommandLineTemplate. 在某些环境如(winserver 2008 R2, 2012, 2016)中需和ExecutablePath配合使用,如果不指定有效的ExecutablePath, Command不会执行,别问我为什么,不太清楚,我也是试出来的。

最后将privider 和 consumer绑定。大功告成.

绑定

$Binding = Set-WmiInstance -Class __FilterToConsumerBinding -ComputerName 'localhost' `
  -Namespace "root\subscription" -arguments @{Filter=$filter; Consumer=$Consumer} 

 

测试

查看WinEvent

Get-WinEvent -ProviderName 'Microsoft-Windows-WMI-Activity' -MaxEvents 5 | fl
TimeCreated  : 8/2/2018 2:01:32 AM
ProviderName : Microsoft-Windows-WMI-Activity
Id           : 5861
Message      : Namespace = //./root/subscription; Eventfilter = WinrmFilter (refer to its activate eventid:5859); Consumer = 
               CommandLineEventConsumer="WinrmDeamon"; PossibleCause = Binding EventFilter: 
               instance of __EventFilter
               {
               	CreatorSID = {1, 5, 0, 0, 0, 0, 0, 5, 21, 0, 0, 0, 152, 160, 177, 5, 52, 101, 181, 4, 217, 68, 206, 143, 244, 1, 
               0, 0};
               	EventNamespace = "root\\cimv2";
               	Name = "WinrmFilter";
               	Query = "SELECT * FROM __InstanceModificationEvent WITHIN 5 \n    WHERE TargetInstance ISA 'Win32_Service' \n    
                   and TargetInstance.Name = 'Winrm' \n        and TargetInstance.State = 'Stopped'";
               	QueryLanguage = "WQL";
               };
               Perm. Consumer: 
               instance of CommandLineEventConsumer
               {
               	CommandLineTemplate = " powershell '\n        $logPath=\"C:\\setup\\WinrmEvent.txt\"\n        Winrm quickconfig 
               /q >> logPath\n        get-date >> logPath\n        ' \n   ";
               	CreatorSID = {1, 5, 0, 0, 0, 0, 0, 5, 21, 0, 0, 0, 152, 160, 177, 5, 52, 101, 181, 4, 217, 68, 206, 143, 244, 1, 
               0, 0};
               	ExecutablePath = "C:\\Windows\\SysWOW64\\WindowsPowerShell\\v1.0\\powershell.exe";
               	Name = "WinrmDeamon";
               };
               

如果找到上面的log,说明Wmi持久化Event订阅成功.

通过命令 stop-service winrm 手动停止winrm 服务, 等待5秒发现Winrm 又恢复启动状态log文件也被创建了。

OK, 小试牛刀到此结束。

问题: 当使用域账号创建本地或远程wmi永久事件监听时, 上面的脚本会出错。这是由于Wmi永久事件订阅的执行权限为"LocalSystem". 而域账号在一般情况下会受到限制。

下一篇主要介绍一种绕过域账号安全限制的一种方式。

©️2020 CSDN 皮肤主题: 大白 设计师:CSDN官方博客 返回首页