web-dev-qa-db-ja.com

PowerShell:Register-ObjectEventのScriptBlockの制限

一定期間後にWindowsフォルダー(C:\ Test)に新しいファイルが生成されなかった場合に、テキストファイルに書き込むPowerShellスクリプトを作成しようとしています。基礎として、私は示されているスクリプトを使用しています ここ 。以下は私の変更したスクリプトです。

ご覧のとおり、最後のファイル作成が10秒以上前かどうかをチェックするIF-ELSEステートメントを追加しました。また、$actionを変更して現在のタイムスタンプを$lasttimefilecreatedに割り当て、$logflagをリセットしました。ただし、$ actionはこれら2つのことのどちらも実行しないようです。 Add-content "C:\FileCreated.txt"行は正常に実行され、ファイルが作成されますが、$lasttimefilecreatedおよび$logflagの値は変更されず、コンソールに出力されません。これを達成する他の方法はありますか? Register-ObjectEvent object に関するMicrosoftの記事を確認しましたが、$ 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}}
3
skyfx

2つの異なるPowerShellサプライズに遭遇しています。

最初:スコーピング。イベントハンドラー内から変数を変更すると、そのブロック内にのみ存在する新しい変数のみが設定されます。簡単なテストケースとして、コンソールでこれを入力すると、1が生成されます。

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

グローバルスコープに割り当てることを指定するには、変数名の前にglobal:を追加します。これは2を出力します:

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

2番目:イベント出力のリダイレクト。イベントハンドラーから結果を生成すると、実際にはジョブオブジェクトに保存されます。コンソールに印刷するには、(暗黙の)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
Ben N

初めて保存する前にISEから実行すると、スクリプトウィンドウに入力したコードが実行されます。コマンドラインで入力した場合と同様に、「$ script:」スコープは使用できませんが、保存した後です。代わりに.ps1ファイルを実行し、「$ script:」スコープがスクリプト内に適用されます(iseセッションの変数は変更されませんが、スクリプトの実行中およびスクリプトから変数が変更されます)グローバルスコープ、スクリプトが開始されたスコープを考慮した観点。「$ global:」スコープを使用すると、スクリプトに影響し、iseセッションの変数(スクリプトの元となったグローバルスコープ)にも影響します。違いが明らかになることを願っています。したがって、スクリプトの場合、どのスコープを使用するかは問題ではありませんが、スクリプトが呼び出されるコンソールでは重要です。

0
nico