I am trying to build a PowerShell script to write to a text file if no new file has been generated in a Windows folder (C:\Test) after a certain period of time. As a foundation, I am using the script shown here. Below is my modified script.
As you can see, I added an IF-ELSE statement that checks if the last file creation is more than 10 seconds ago. I also modified $action to assign the current timestamp to $lasttimefilecreated and reset $logflag. However, it appears that $action does not perform either of those two things. The Add-content "C:\FileCreated.txt" line executes successfully and a file is created, but the values of $lasttimefilecreated and $logflag remain unchanged and are not printed to the console. Is there any other way to accomplish this? I reviewed the Microsoft article on the Register-ObjectEvent object, but could not figure out why the script block I am assigning to $action does not fully work. Appreciate your help!
### 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}} 2 Answers
You're running into two different PowerShell surprises.
First: scoping. When you change a variable from inside your event handler, you're only setting a new variable that only exists inside that block. As a simple test case, typing this at the console produces 1:
$a = 1; {$a = 2}.Invoke(); $aTo specify that you're assigning to the global scope, prepend global: to the variable name. This prints 2:
$a = 1; {$global:a = 2}.Invoke(); $aSecond: event output redirection. When you produce results from an event handler, it actually gets saved in a job object. To print to the console, use Write-Host instead of (the implicit) Write-Output. For example:
Write-Host $lasttimefilecreatedYou might consider using a timer instead of a loop, like so:
$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}The final loop there just prevents the script from exiting. Timers would continue to run if it did stop, but it looks a little weird.
8if you execute from ISE before saving the first time it will run the code that you typed in the script window, as if you typed it on the command line and you can't use the "$script:" scope, but after you saved it will execute the .ps1 file instead, and the "$script:" scope applies within the script (it won't change the variables in your ise session, but it will change them within the execution of the script, and from the scripts point of view considering that the global scope, the scope in which the script was started. if you use the "$global:" scope it affects the script and also affects the variables in your ise session (the global scope from which the script was called). I hope that clears up the difference, so for a script it doesn't matter which of those scopes you use, but it matters for the console from which a script is called.
0