![PowerShell:Register-ObjectEvent 中 ScriptBlock 的限制](https://linux22.com/image/1504005/PowerShell%EF%BC%9ARegister-ObjectEvent%20%E4%B8%AD%20ScriptBlock%20%E7%9A%84%E9%99%90%E5%88%B6.png)
我正在尝试构建一个 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 会话中的变量(从中调用脚本的全局范围)。我希望这可以消除差异,所以对于脚本来说,使用哪个范围并不重要,但对于调用脚本的控制台来说很重要。