Register-ObjectEvent of System.IO.FileSystemWatcher not working as expected - powershell

I use a powershell script to watch a folder and get notification when a new file is created.
The script is the following
### SET FOLDER TO WATCH + FILES TO WATCH + SUBFOLDERS YES/NO
$watcher = New-Object System.IO.FileSystemWatcher
$watcher.Path = "C:\Users\Desktop\test\"
$watcher.Filter = "*.nrrd"
$watcher.IncludeSubdirectories = $true
$watcher.EnableRaisingEvents = $true
### DEFINE ACTIONS AFTER AN EVENT IS DETECTED
$action =
{
$path = $Event.SourceEventArgs.FullPath
$changeType = $Event.SourceEventArgs.ChangeType
Write-Host "The file '$path' was $changeType at '$(Get-Date)'" -fore green
}
### DECIDE WHICH EVENTS SHOULD BE WATCHED
Register-ObjectEvent $watcher "Created" -Action $action
while ($true) {sleep 5}
It works fine even if I create the file manually or with a .bat, PHP or even python.
The only way it does not work is when another user (or session?) is creating the file.
For example:
I created a folder on my computer, shared it with other computer over LAN.
When the file is created by me (or one of my script), the script is well working and the sentence is displayed.
If I use another computer on the LAN to add a file in the same folder, it does not work. Nothing is displayed.
(But if I copy/past the file created by the other user, the script is working, so is not a issue with the file itself).
I found this and this but the posts are outdated.
Do you have any workaround or idea to solve this?
UPDATE
The file created by hand (or copy/pasted) has owner DEBIAN\root but the original one have Unix User\www-data.
Maybe powershell (windows) is not able to "catch" this kind of user that's maybe why the event is not even created?

Try giving the shared folder's UNC path
$watcher.Path = "\\server\share"

Related

How launch stats program JMP when a file is saved in a folder?

I want to use a code in PowerShell to launch JMP analysis. To begin I just want to launch the same code any time a file is saved in the folder and after I will adapt this. So I use something I see on this forum to create this code:
### SET FOLDER TO WATCH
$watcher = New-Object System.IO.FileSystemWatcher
$watcher.Path = "C:\Users\GROUSD01\Desktop\test"
$watcher.Filter = "*.xlsx"
$watcher.EnableRaisingEvents = $true
### DEFINE ACTIONS AFTER AN EVENT IS DETECTED
$action = { Start-Process jmp.exe "C:\Users\GROUSD01\Desktop\Création code MPPT\ScriptMPPT.jsl"
}
### DECIDE WHICH EVENTS SHOULD BE WATCHED
Register-ObjectEvent $watcher "Created" -Action $action
When I run it in Powershell, it detects the new file and tries to run the command but doesn't find the file .jsl and JMP prints an error. But when I run this code in the command line:
jmp.exe "C:\Users\GROUSD01\Desktop\Création code MPPT\ScriptMPPT.jsl"`
It finds the good file and runs the good things.
Do you have any idea about why is there a problem?

How do you automatically clean up all event subscriptions made in a PowerShell script when that script exits?

I'm setting up a FileSystemWatcher to watch a file for changes. This works. I also want to keep the script that sets this up running until the user manually terminates the script. This also works. However, I'd also like the event subscription on the FileSystemWatcher to get automatically cleaned up when the script exits (either normally or abnormally). This doesn't work, because event subscriptions are part of the session, and the script doesn't have its own session.
I tried creating a new session object inside the script and using it for the watcher setup and event registration, which seemed to do a great job cleaning up the event subscription on script termination, but it also seemed to cause all my console activity to get swallowed up in that child session.
How can I make it so that whenever the script exits (normally or abnormally), the event subscription is cleaned up automatically? (And doing this while maintaining visibility of my console output.)
In case the context matters, this is a simple ZIP file build script. I'm trying to add a "watch mode" to it so that when the ZIP is updated by another app, the ZIP is decompressed back to the folder from which it was created. So this script is meant to be executed from a PowerShell command line that remains active and is possibly used for other things before and after this script runs. In other words, the mighty hammer of Get-EventSubscriber | Unregister-Event is potentially a little too mighty, in addition to being another command that the script user would have to invoke on their own.
This is a condensed version of my script:
$watcher = New-Object System.IO.FileSystemWatcher ".", $fileName -Property #{
NotifyFilter = [IO.NotifyFilters]::LastWrite
}
Register-ObjectEvent $watcher -EventName Changed -Action {
Write-Host "File change detected."
# other things, scripts, etc
}
$watcher.EnableRaisingEvents = $true
Write-Host "Press Ctrl+C to stop watching the file."
while ($true)
{
if ([Console]::KeyAvailable)
{
$keyInfo = [Console]::ReadKey($true)
if ($keyInfo.Modifiers -eq [ConsoleModifiers]::Control -and $keyInfo.Key -eq [ConsoleKey]::C)
{
Exit
}
}
else
{
Start-Sleep 0.5
}
}
Try the following:
$watcher = New-Object System.IO.FileSystemWatcher $pwd, $fileName -Property #{
NotifyFilter = [IO.NotifyFilters]::LastWrite
}
# Register with a self-chosen source identifier.
$evtJob = Register-ObjectEvent -SourceIdentifier fileWatcher $watcher -EventName Changed -Action {
Write-Host "File change detected."
# other things, scripts, etc
}
$watcher.EnableRaisingEvents = $true
Write-Host "Press Ctrl+C to stop watching the file."
try {
# This blocks execution indefinitely while allowing
# events to be processed in the -Action script block.
# Ctrl-C aborts the script by default, which will execute
# the `finally` block.
Wait-Event -SourceIdentifier fileWatcher
}
finally {
# Clean up the event job, and with it the event subscription.
# Note: If the -Action script block produces output, you
# can collect it with Receive-Job first.
$evtJob | Remove-Job -Force
}

Windows Task Scheduler Powershell Script complete and restart

I have created a script that uses a FileSystemWatcher and creates a job. When a file is added to a folder it
Renames the newly added file
Moves the file to a new destination
Begins a downstream workflow
Once it’s done it ends the Job.
What I want to do is use Windows Task Scheduler to check that when the job completes to immediately run again. This way if one person drops a folder, that another person and can do the same.
ALSO If there is another way to have this work I am happy to use it.
I have tried to schedule the task to run but the lowest increment is 1 minute
I expect to have the filesystemwatcher running all the time. And once the script has finished I want it to start again.
You don't have to start job when the event (file creation) occur, you can directly move the file and do whatever you want using action parameter.
Also, you don't have to restart the event, it is will keep running unless you manually unregister it, so you don't have to use task scheduler at all.
Here's the code
# set the folder you want to watch
$watcher = New-Object System.IO.FileSystemWatcher
$watcher.Path = "$home/Desktop/Folder"
$watcher.Filter = "*.*"
$watcher.IncludeSubdirectories = $true
$watcher.EnableRaisingEvents = $true
# start job when event is detected
$action = {
Start-Job -ScriptBlock {
# Step 1&2 (You can move the file and rename it with one step)
Move-Item $Event.SourceEventArgs.FullPath -Destination $newPath
} | Wait-Job
}
# Register and start the FileSystemWatcher
Register-ObjectEvent -InputObject $watcher -EventName Created -SourceIdentifier FileCreated -Action $action
Note
I used Start-Job in the code; However, you can omit it and put the code exactly in $action.
This code will register new FileSystemWatcher and will keep monitoring the folder for newly created file then move it to a new location.
To stop the watcher
Unregister-Event -SourceIdentifier FileCreated
Look here for more information about tracking changes to a folder using PowerShell

Power shell executing base on how many files is in the path how to solve this issue?

I have a code in PowerShell for file watcher fo my FTP folder and when the code see that there is new file in that folder it will open a batch file that will run a program for my database.
My problem is when i sent multiple files "2 files to be exact" the power shell also execute it twice or more i just need to run it once when the file is already uploaded in the specified folder.
here is my code thank you in advance!
$searchPath = "D:\Upload\ftp\"
$watcher = New-Object System.IO.FileSystemWatcher
$watcher.Path = $searchPath
$watcher.IncludeSubdirectories = $false
$watcher.EnableRaisingEvents = $true
$created = Register-ObjectEvent $watcher "Created" -Action {
Start-Process "C:\eGaps\Isabela\Automatic-Upload\automata.bat"
}
This is because the event watcher you have in place is designed to look for write to the folder as the occur and you are specifically telling it to take an action on that.
Either set this code as a scheduled task to say run every hour and grab all new files in the folder or change the coded to look for a certain number of new files before your trigger is called.
The scheduled task is the easiest route IMHO, the below article is an example of how to do the scheduled task approach.
Scan Folder for Changed/Added Files
Description: Script to check if files have been updated or added in
the past 10 minutes, with the expectation that the script will be run
as a scheduled task every 10 minutes.
If there is a hit the script will send an email with the changed/added
files in the body of the email.
https://community.spiceworks.com/scripts/show/1595-scan-folder-for-changed-added-files

Register-ObjectEvent Event Subscription Uptime

We have a data dump come from an external entity on a daily basis. Once we receive the file, a Object Event Listener triggers, moves the file into two separate locations (one live, one backup) and then calls a MS SQL stored procedure to import the file into the database.
The process and my script seem to function perfectly fine. The file moves, and the SQL is executed. However, every morning when I check to see if it triggered, nothing triggered. I check for event-subscribers by calling Get-EventSubscriber and there are no listeners registered. Once I register the listeners and move the file into the input location, everything runs fine.
I understand that the Event Subscriptions do not persist through reboots, but how long do they stay open? is it possible that something is closing them? or do they time out?
$watchFolder = "\\server\c$\path\to\inbound\"
$filter = "*.txt"
$fsw = New-Object IO.FileSystemWatcher $watchFolder, $filter -Property #{
IncludeSubdirectories = $false
NotifyFilter = [IO.NotifyFilters]'FileName, LastWrite'
}
$onCreated = Register-ObjectEvent $fsw Created -SourceIdentifier FileMonitor -Action {
$filePath = $Event.SourceEventArgs.FullPath
$fileName = $Event.SourceEventArgs.Name
Write-Host "Source File: $fileName"
$success = copyFile($fileName, $filePath) #custom function to copy file to multiple destinations
if ($success) {
Write-Host "Starting SQL_JOB_NAME Job"
Set-Location SQLSERVER:\SQL\server\DEFAULT\Databases\msdb\
$execute_import = "EXEC dbo.sp_start_job N'SQL_JOB_NAME';"
Invoke-Sqlcmd -SuppressProviderContextWarning -Query $execute_import
} else {
Write-Host "Something failed along the way: `r`n"
}
}
As silly as it seems, I learned here that calling Register-ObjectEvent if the PowerShell process is closed, the ObjectEvent is also unregistered.
Because the nature of the project required us to have an always-on file listener, we decided that Powershell was not the correct implementation for us.
Instead we implemented a Windows service using the .NET libraries, which are the same used here in PowerShell.
Thanks to PetSerAl for his prompt answer.