PowerShell:Register-ObjectEvent 中 ScriptBlock 的限制

PowerShell:Register-ObjectEvent 中 ScriptBlock 的限制

我正在尝试构建一个 PowerShell 脚本,如果在一段时间后 Windows 文件夹 (C:\Test) 中没有生成新文件,则将其写入文本文件。作为基础,我使用显示的脚本这里。下面是我修改后的脚本。

如您所见,我添加了一个 IF-ELSE 语句,用于检查上次文件创建是否超过 10 秒。我还进行了修改,$action将当前时间戳分配给$lasttimefilecreated和 重置$logflag。但是,似乎 $action 并未执行这两件事。该行成功执行并创建了一个文件,但和Add-content "C:\FileCreated.txt"的值保持不变,并且未打印到控制台。还有其他方法可以实现此目的吗?我查看了 Microsoft 文章$lasttimefilecreated$logflag注册 ObjectEvent 对象,但无法弄清楚为什么我分配给 $action 的脚本块无法完全工作。感谢您的帮助!

### SET FOLDER TO WATCH + FILES TO WATCH + SUBFOLDERS YES/NO
$watcher = New-Object System.IO.FileSystemWatcher
$watcher.Path = "C:\Test"
$watcher.Filter = "*.*"
$watcher.IncludeSubdirectories = $true
$watcher.EnableRaisingEvents = $true  

### INITIALIZE VARIABLES
$lasttimefilecreated = $(Get-Date)
$logflag = 0
$action = { $lasttimefilecreated = $(Get-Date)
            "$lasttimefilecreated"
            $logflag = 0
            "$logflag"
            $path = $Event.SourceEventArgs.FullPath
            $changeType = $Event.SourceEventArgs.ChangeType
            $logline = "$(Get-Date), $changeType, $path"
            Add-content "C:\FileCreated.txt" -value $logline
          }

### DECIDE WHICH EVENTS SHOULD BE WATCHED + LOOP INDEFINITELY THROUGH IF-ELSE LOGIC  
$created = Register-ObjectEvent $watcher "Created" -Action $action
while ($true) {
        if ((New-TimeSpan -Start $lasttimefilecreated –End $(Get-Date)).Seconds -gt 10 -and $logflag -eq 0) {
        $logflag = 1
        Add-content "C:\Log.txt" -value "$(Get-Date)"
        "Log.txt file created/modified at $(Get-Date)"
        }
        else {sleep 5}}

答案1

您遇到了两个不同的 PowerShell 意外。

首先:作用域。当您从事件处理程序内部更改变量时,您只是设置了一个仅存在于该块内的新变量。作为一个简单的测试用例,在控制台中输入以下内容会产生1

$a = 1; {$a = 2}.Invoke(); $a

要指定要分配给全局范围,请global:在变量名称前面添加。这将打印2

$a = 1; {$global:a = 2}.Invoke(); $a

第二:事件输出重定向。当您从事件处理程序生成结果时,它实际上会保存在作业对象中。要打印到控制台,请使用Write-Host而不是(隐式)Write-Output。例如:

Write-Host $lasttimefilecreated

您可以考虑使用计时器而不是循环,如下所示:

$timer = New-Object System.Timers.Timer
$timer.Interval = 5000
$timer.Enabled = $true
Register-ObjectEvent $timer 'Elapsed' -Action {
    If ($global:logflag -eq 0) {
        $global:logflag = 1
        Add-content "C:\Log.txt" -value "$(Get-Date)"
        Write-Host "Log.txt file created/modified at $(Get-Date)"
    }
}
$timer.AutoReset = $true
$timer.Start()
while ($true) {Start-Sleep -Seconds 5}

最后一个循环只是阻止脚本退出。如果脚本停止,计时器将继续运行,但看起来有点奇怪。

答案2

如果您在第一次保存之前从 ISE 执行,它将运行您在脚本窗口中键入的代码,就好像您在命令行中键入它一样,并且您不能使用“$script:”范围,但在保存后它将执行.ps1 文件,并且“$script:”范围适用于脚本(它不会更改 ise 会话中的变量,但它会在脚本执行过程中更改它们,并且从脚本的角度来看,考虑到全局范围,即启动脚本的范围。如果使用“$global:”范围,它会影响脚本并且还会影响 ise 会话中的变量(从中调用脚本的全局范围)。我希望这可以消除差异,所以对于脚本来说,使用哪个范围并不重要,但对于调用脚本的控制台来说很重要。

相关内容