【问题标题】:How to Subscribe to Windows File Modification Events如何订阅 Windows 文件修改事件
【发布时间】:2016-06-10 14:05:59
【问题描述】:

我正在尝试使用WQL 使用以下查询订阅特定文件被修改的事件:

SELECT * FROM __InstanceModificationEvent WITHIN 1 WHERE TargetInstance ISA "CIM_DataFile" AND TargetInstance.Drive="C:" AND TargetInstace.Path="\\test\\filewatching\\"

我可以成功注册事件(见底部的输出),并且可以看到它与我注册的脚本(消费者)绑定。

但是,当我修改 C:\test\filewatching\ 中的文件时,脚本不会运行。


这是在同一文件夹中注册文件创建事件的代码,可以正常工作

#WQL

$query = @"
SELECT * FROM __InstanceCreationEvent WITHIN 1 WHERE TargetInstance ISA "Cim_DirectoryContainsFile" AND TargetInstance.GroupComponent="Win32_Directory.Name='C:\\test\\filewatching'"
"@
$instanceFilter = ([WMICLASS]"\\$Computername\root\subscription:__EventFilter").CreateInstance()
$instanceFilter.QueryLanguage = 'WQL'
$instanceFilter.Query = $query
$instanceFilter.Name = 'EventFilterNameHere'
$instanceFilter.EventNameSpace = 'root/CIMV2'
$result = $instanceFilter.Put()

# Consumer

$script = 
@"
Set objFSO = CreateObject("Scripting.FileSystemObject")
Set objFile = objFSO.OpenTextFile("c:\test\filewatching\Log.log", 8, True)
objFile.WriteLine "New File Created"
objFile.Close
"@
$instanceConsumer = ([wmiclass]"\\$Computername\root\subscription:ActiveScriptEventConsumer").CreateInstance()
$instanceConsumer.Name = 'ConsumerNameHere'
$instanceConsumer.ScriptingEngine = 'VBScript'
$instanceConsumer.ScriptFilename = '' 
$instanceConsumer.ScriptText = $script
$instanceConsumer.Put()

# Binding

[object]$Filter = (Get-WMIObject -Computername $Computername -Namespace root\Subscription -Class __EventFilter | Sort Name)
[object]$Consumer = (Get-WMIObject -Computername $Computername -Namespace root\Subscription -Class __EventConsumer | Sort Name)

$instanceBinding = ([wmiclass]"\\$Computername\root\subscription:__FilterToConsumerBinding").CreateInstance()
$instanceBinding.Filter = $Filter
$instanceBinding.Consumer = $Consumer
$instanceBinding.Put()

所以我知道我的 PowerShell 没有任何问题。这让我觉得我的查询一定是错误的。

我已尝试对上述InstanceModificationEvent 查询进行一些调整,但没有成功。 (这些调整包括将C: 更改为C 或从TargetInstace.Path 中删除\s)。


我需要此订阅是永久的,并且在 PC 开启或关闭时无法重置 - 这就是我使用 WQL 的原因。如果有人可以提出另一种实现相同目标的方法或我如何解决我的查询,我将永远感激不尽!


运行脚本后的输出:

Path          : \\WIN7-IT3\root\subscription:ActiveScriptEventConsumer.Name="Co
                nsumerNameHere"
RelativePath  : ActiveScriptEventConsumer.Name="ConsumerNameHere"
Server        : WIN7-IT3
NamespacePath : root\subscription
ClassName     : ActiveScriptEventConsumer
IsClass       : False
IsInstance    : True
IsSingleton   : False

Path          : \\WIN7-IT3\root\subscription:__FilterToConsumerBinding.Consumer
                ="\\\\WIN7-IT3\\ROOT\\Subscription:ActiveScriptEventConsumer.Na
                me=\"ConsumerNameHere\"",Filter="\\\\WIN7-IT3\\ROOT\\Subscripti
                on:__EventFilter.Name=\"EventFilterNameHere\""
RelativePath  : __FilterToConsumerBinding.Consumer="\\\\WIN7-IT3\\ROOT\\Subscri
                ption:ActiveScriptEventConsumer.Name=\"ConsumerNameHere\"",Filt
                er="\\\\WIN7-IT3\\ROOT\\Subscription:__EventFilter.Name=\"Event
                FilterNameHere\""
Server        : WIN7-IT3
NamespacePath : root\subscription
ClassName     : __FilterToConsumerBinding
IsClass       : False
IsInstance    : True
IsSingleton   : False

查询 WMI 订阅:

Get-WmiObject -Namespace root\Subscription -Class __Eventfilter
Get-WMIObject -Namespace root\Subscription -Class __EventConsumer
Get-WMIObject -Namespace root\Subscription -Class __FilterToConsumerBinding
Get-WMIObject -Namespace root\Subscription -Class ActiveScriptEventConsumer

查询后的输出:

__GENUS          : 2
__CLASS          : __EventFilter
__SUPERCLASS     : __IndicationRelated
__DYNASTY        : __SystemClass
__RELPATH        : __EventFilter.Name="EventFilterNameHere"
__PROPERTY_COUNT : 6
__DERIVATION     : {__IndicationRelated, __SystemClass}
__SERVER         : WIN7-IT3
__NAMESPACE      : ROOT\Subscription
__PATH           : \\WIN7-IT3\ROOT\Subscription:__EventFilter.Name="EventFilterNameHere"
CreatorSID       : {1, 5, 0, 0...}
EventAccess      : 
EventNamespace   : root/CIMV2
Name             : EventFilterNameHere
Query            : SELECT * FROM __InstanceModificationEvent WITHIN 5 WHERE TargetInstance ISA 
                   "CIM_DataFile" AND TargetInstance.Drive="C:" AND 
                   TargetInstace.Path="\\test\\filewatching\\"
QueryLanguage    : WQL
PSComputerName   : WIN7-IT3

__GENUS          : 2
__CLASS          : ActiveScriptEventConsumer
__SUPERCLASS     : __EventConsumer
__DYNASTY        : __SystemClass
__RELPATH        : ActiveScriptEventConsumer.Name="ConsumerNameHere"
__PROPERTY_COUNT : 8
__DERIVATION     : {__EventConsumer, __IndicationRelated, __SystemClass}
__SERVER         : WIN7-IT3
__NAMESPACE      : ROOT\Subscription
__PATH           : \\WIN7-IT3\ROOT\Subscription:ActiveScriptEventConsumer.Name="ConsumerNameHere"
CreatorSID       : {1, 5, 0, 0...}
KillTimeout      : 0
MachineName      : 
MaximumQueueSize : 
Name             : ConsumerNameHere
ScriptFilename   : 
ScriptingEngine  : VBScript
ScriptText       : Set objFSO = CreateObject("Scripting.FileSystemObject")
                   Set objFile = objFSO.OpenTextFile("c:\test\filewatching\Log.log", 8, True)
                   objFile.WriteLine "New File Created"
                   objFile.Close
PSComputerName   : WIN7-IT3

__GENUS                 : 2
__CLASS                 : __FilterToConsumerBinding
__SUPERCLASS            : __IndicationRelated
__DYNASTY               : __SystemClass
__RELPATH               : __FilterToConsumerBinding.Consumer="\\\\WIN7-IT3\\ROOT\\Subscription:ActiveS
                          criptEventConsumer.Name=\"ConsumerNameHere\"",Filter="\\\\WIN7-IT3\\ROOT\\Su
                          bscription:__EventFilter.Name=\"EventFilterNameHere\""
__PROPERTY_COUNT        : 7
__DERIVATION            : {__IndicationRelated, __SystemClass}
__SERVER                : WIN7-IT3
__NAMESPACE             : ROOT\Subscription
__PATH                  : \\WIN7-IT3\ROOT\Subscription:__FilterToConsumerBinding.Consumer="\\\\WIN7-IT
                          3\\ROOT\\Subscription:ActiveScriptEventConsumer.Name=\"ConsumerNameHere\"",F
                          ilter="\\\\WIN7-IT3\\ROOT\\Subscription:__EventFilter.Name=\"EventFilterName
                          Here\""
Consumer                : \\WIN7-IT3\ROOT\Subscription:ActiveScriptEventConsumer.Name="ConsumerNameHer
                          e"
CreatorSID              : {1, 5, 0, 0...}
DeliverSynchronously    : False
DeliveryQoS             : 
Filter                  : \\WIN7-IT3\ROOT\Subscription:__EventFilter.Name="EventFilterNameHere"
MaintainSecurityContext : False
SlowDownProviders       : False
PSComputerName          : WIN7-IT3

__GENUS          : 2
__CLASS          : ActiveScriptEventConsumer
__SUPERCLASS     : __EventConsumer
__DYNASTY        : __SystemClass
__RELPATH        : ActiveScriptEventConsumer.Name="ConsumerNameHere"
__PROPERTY_COUNT : 8
__DERIVATION     : {__EventConsumer, __IndicationRelated, __SystemClass}
__SERVER         : WIN7-IT3
__NAMESPACE      : ROOT\Subscription
__PATH           : \\WIN7-IT3\ROOT\Subscription:ActiveScriptEventConsumer.Name="ConsumerNameHere"
CreatorSID       : {1, 5, 0, 0...}
KillTimeout      : 0
MachineName      : 
MaximumQueueSize : 
Name             : ConsumerNameHere
ScriptFilename   : 
ScriptingEngine  : VBScript
ScriptText       : Set objFSO = CreateObject("Scripting.FileSystemObject")
                   Set objFile = objFSO.OpenTextFile("c:\test\filewatching\Log.log", 8, True)
                   objFile.WriteLine "New File Created"
                   objFile.Close
PSComputerName   : WIN7-IT3

【问题讨论】:

    标签: powershell events wmi wql


    【解决方案1】:

    发布此问题后不久偶然发现this page,从中我发现我需要的查询是:

    SELECT * FROM __InstanceModificationEvent WITHIN 1 WHERE TargetInstance ISA 'CIM_DataFile' AND TargetInstance.Name='c:\\test\\filewatching\\tester.txt'

    请注意,与网上的其他几篇帖子相反,对我有用的实际上是省略了TargetInstancePathDrive 部分,只包含我想要观看的文件的完整路径和名称。

    这对我有用,因为我只会观看 1 个特定文件。如果您需要使用此方法观看多个文件,则需要注册多个订阅。

    注册文件修改观察者的完整代码:

    #WQL
    
    $query = @"
    SELECT * FROM __InstanceModificationEvent WITHIN 1 WHERE TargetInstance ISA 'CIM_DataFile' AND TargetInstance.Name='c:\\test\\filewatching\\tester.txt'
    "@
    $instanceFilter = ([WMICLASS]"\\$Computername\root\subscription:__EventFilter").CreateInstance()
    $instanceFilter.QueryLanguage = 'WQL'
    $instanceFilter.Query = $query
    $instanceFilter.Name = 'EventFilterNameHere'
    $instanceFilter.EventNameSpace = 'root/CIMV2'
    $result = $instanceFilter.Put()
    
    # Consumer
    
    $script = 
    @"
    Set objFSO = CreateObject("Scripting.FileSystemObject")
    Set objFile = objFSO.OpenTextFile("c:\test\filewatching\Log.log", 8, True)
    objFile.WriteLine "New File Created"
    objFile.Close
    "@
    $instanceConsumer = ([wmiclass]"\\$Computername\root\subscription:ActiveScriptEventConsumer").CreateInstance()
    $instanceConsumer.Name = 'ConsumerNameHere'
    $instanceConsumer.ScriptingEngine = 'VBScript'
    $instanceConsumer.ScriptFilename = '' 
    $instanceConsumer.ScriptText = $script
    $instanceConsumer.Put()
    
    # Binding
    
    [object]$Filter = (Get-WMIObject -Computername $Computername -Namespace root\Subscription -Class __EventFilter | Sort Name)
    [object]$Consumer = (Get-WMIObject -Computername $Computername -Namespace root\Subscription -Class __EventConsumer | Sort Name)
    
    $instanceBinding = ([wmiclass]"\\$Computername\root\subscription:__FilterToConsumerBinding").CreateInstance()
    $instanceBinding.Filter = $Filter
    $instanceBinding.Consumer = $Consumer
    $instanceBinding.Put()
    

    【讨论】:

      【解决方案2】:

      您需要将消费者和过滤器的路径附加到活页夹 而不是系统中的每个过滤器\消费者

      $result = $instanceFilter.Put()
      $filterPath = $result.Path
      $result = $instanceConsumer.Put()
      $consumerPath = $result.Path
      
      $bind.Filter = $filterPath
      $bind.Consumer = $consumerPath
      

      【讨论】:

        猜你喜欢
        • 2016-02-04
        • 1970-01-01
        • 2013-11-03
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2016-07-19
        相关资源
        最近更新 更多