Split strings from registered event output in PowerShell - powershell

I have just started working with IO.FIleSystemWatcher. My current code works and alerts me of created files in the desired location, however I want to pipe some of the variables out and split the strings. I cannot get the split portion to work.
Functional Code:
$folder = 'D:\Output'
$filter = '*.jpg'
$fsw = New-Object IO.FileSystemWatcher $folder, $filter -Property #{IncludeSubdirectories = $false;NotifyFilter = [IO.NotifyFilters]'FileName, LastWrite'}
Register-ObjectEvent $fsw Created -SourceIdentifier FileCreated -Action {
$name = $Event.SourceEventArgs.Name
$changeType = $Event.SourceEventArgs.ChangeType
$timeStamp = $Event.TimeGenerated
Write-Host "The file '$name' was $changeType at $timeStamp" -fore green
Out-File D:\Output\scans\$name.txt
}
$name will always be formatted like so 'file.name.fn_xxx.jpg' and I want to use split to pull 'file' from $name, for example:
$name.split('.')[0]
However, this does nothing as far as I can tell. For instance I can output a file with $name as the filename, but if I try to split it first nothing outputs.
Non-Functional Code:
Register-ObjectEvent $fsw Created -SourceIdentifier FileCreated -Action {
$name = $Event.SourceEventArgs.Name
$changeType = $Event.SourceEventArgs.ChangeType
$timeStamp = $Event.TimeGenerated
Write-Host "The file '$name' was $changeType at $timeStamp" -fore green
$name = $name.split('.')[0]
Out-File D:\Output\scans\$name.txt
}
This is a bit over my head so any advice or suggestion is appreciated.
Thanks

I ended up working it out by simply using another variable.
$folder = 'D:\Output'
$filter = '*.jpg'
$fsw = New-Object IO.FileSystemWatcher $folder, $filter -Property #{IncludeSubdirectories = $false;NotifyFilter = [IO.NotifyFilters]'FileName, LastWrite'}
Register-ObjectEvent $fsw Created -SourceIdentifier FileCreated -Action {
$name = $Event.SourceEventArgs.Name
$changeType = $Event.SourceEventArgs.ChangeType
$timeStamp = $Event.TimeGenerated
Write-Host "The file '$name' was $changeType at $timeStamp" -fore green
Write-Host "$name"
$x = $name.split(".")[0]
Out-File D:\Output\scans\$x.txt
I am not sure why this works, but it does. If anyone knows why please comment!

Related

PowerShell IO.FileSystemWatcher doesn't work after restart fileserver

I need a FileSystemWatcher on a network directory (fileserver)
The script works well but fails after a reboot from the fileserver.
How can I detect if the FSW is failing and restart the watcher if the fileserver is up and running again?
Code:
$destinations = #{"\\location1" = "c:\destination1"
"\\location2" = "c:\destination2"
}
foreach ($location in $destinations.Keys) {
$Watcher = New-Object IO.FileSystemWatcher -Property #{
Path = $location
Filter = "*.*"
IncludeSubdirectories = $false
NotifyFilter = [IO.NotifyFilters]'FileName, LastWrite'
}
Register-ObjectEvent $Watcher -EventName Created -SourceIdentifier $location -Action {
$path = $Event.SourceEventArgs.FullPath
$name = $Event.SourceEventArgs.Name
$changeType = $Event.SourceEventArgs.ChangeType
$timeStamp = $Event.TimeGenerated
$SI = $Event.SourceIdentifier
Write-Host "The file '$name' was $changeType at $timeStamp"
Write-Host $path
Move-Item $path -Destination $destinations[$SI] -Force -Verbose
}
}
RTFM!
There is Error event from FileSystemWatcher, and there is your case exactly described.
For example, if the object is monitoring changes in a remote directory and the connection to that directory is lost, the Error event is raised.
Solution found:
$destinations = #{"\\location1" = "c:\destination1"
"\\location2" = "c:\destination2"
}
foreach ($location in $destinations.Keys) {
$Watcher = New-Object IO.FileSystemWatcher -Property #{
Path = $location
Filter = "*.*"
IncludeSubdirectories = $false
NotifyFilter = [IO.NotifyFilters]'FileName, LastWrite'
}
$action = {
$path = $Event.SourceEventArgs.FullPath
$name = $Event.SourceEventArgs.Name
$changeType = $Event.SourceEventArgs.ChangeType
$timeStamp = $Event.TimeGenerated
$SI = $Event.SourceIdentifier
Write-Host "The file '$name' was $changeType at $timeStamp"
Write-Host $path
Move-Item $path -Destination $destinations[$SI] -Force -Verbose
}
$actionError = {
$Sender.EnableRaisingEvents = $false
$ip = $location -split "\\" | Where { $_ -ne "" } | Select -first 1
do {
Write-Host "Waiting for boot " + $ip
Start-Sleep -Seconds 5
} until (Test-Connection $ip -Quiet -Count 1)
$Sender.EnableRaisingEvents = $true
}
Register-ObjectEvent $Watcher -EventName Created -SourceIdentifier $location -Action $action
Register-ObjectEvent $Watcher -EventName Error -SourceIdentifier $location+'ERROR' -Action $actionError
}

How to make a io.systemfileswatcher run indefinitely

I have a script that calls two io.systemfile watchers which I would like to run 24x7 so that it can detect data that needs to be processed and automatically hand it off to a script that processes it (and uploads the result to the network):
Function Report1Watcher{
param ($folder)
$filter = "*vac*.csv"
$watcher = New-Object IO.FileSystemWatcher $folder, $filter -Property #{
IncludeSubdirectories = $true
EnableRaisingEvents = $true
InternalBufferSize = 65536
}
Write-Host "Watching $folder for creation of $filter files..."
$changeAction = {
$path = $Event.SourceEventArgs.FullPath
$name = $Event.SourceEventArgs.Name
$changeType = $Event.SourceEventArgs.ChangeType
$timeStamp = $Event.TimeGenerated
$Actionpath = Split-Path $Path
write-host $Actionpath " Ready for Report1"
Report1 $Actionpath
write-host $Actionpath " Report1 Generated"
}
Register-ObjectEvent $Watcher -EventName "Created" -Action $changeAction
}
Function Report2Watcher{
param ($folder)
$filter = "*4.4*"
$watcher = New-Object IO.FileSystemWatcher $folder, $filter -Property #{
IncludeSubdirectories = $true
EnableRaisingEvents = $true
InternalBufferSize = 65536
}
Write-Host "Watching $folder for creation of $filter files..."
$changeAction = {
$path = $Event.SourceEventArgs.FullPath
$name = $Event.SourceEventArgs.Name
$changeType = $Event.SourceEventArgs.ChangeType
$timeStamp = $Event.TimeGenerated
$Actionpath = Split-Path $Path
$Actionpath = Split-Path $Actionpath
write-host $Actionpath " Ready for Report2"
Report2 $Actionpath
write-host "Report2 Generated"
}
Register-ObjectEvent $Watcher -EventName "Created" -Action $changeAction
}
Function Watchmaster{
Report1Watcher $Testdir
Report2Watcher $Testdir
}
Watchmaster
I am thinking of turning it into a windows service, but would it be able to run 24x7 as is? I'm not sure where I could add an infinite loop without creating infinite io.systemfilewatchers. I know as a PS script that powershell would need to constantly be running. But if I created a batch file that runs this and set it up as a service with nssm would this accomplish what I need?

FileSystemWatcher not firing events till PowerShell closes

I have a script (below) that watches a folder that the .ps1 script sits in.
When a file is created it fires a .bat file to do a job.
Initially it would run and close immediately.
So I added '''Start-Sleep -s 50'''
It works but it only triggers the .bat launch when the PowerShell window closes.
(As I don't know how long it will be till a file turns up in the folder, this is kind of useless).
Ideally I could do with the .bat file launching as soon as the new file is created, which in turn then closes the PowerShell window
$configFilePath = $PSScriptRoot
$filter = '*.*'
$fsw = New-Object IO.FileSystemWatcher $configFilePath, $filter -Property #{IncludeSubdirectories = $true;NotifyFilter = [IO.NotifyFilters]'FileName, LastWrite'}
Register-ObjectEvent $fsw Created -SourceIdentifier FileCreated -Action {
$name = $Event.SourceEventArgs.Name
$changeType = $Event.SourceEventArgs.ChangeType
$timeStamp = $Event.TimeGenerated
Write-Host "The file '$name' was $changeType at $timeStamp" -fore green
Out-File -FilePath c:\temp\log\Filelog.txt -Append -InputObject "The file '$name' was $changeType at $timeStamp"
Set-Location "$PSScriptRoot"
Start-Process "$PSScriptRoot\PS_Run.bat"
}
Start-Sleep -s 50
You can replace Start-Sleep with:
Wait-Event -SourceIdentifier FileCreated
Then you need to add an exit command to your watcher like this:
Start-Process "$PSScriptRoot\PS_Run.bat"
exit
}
Since you cannot exit the console from the filewatcher, you can do this instead:
$configFilePath = $PSScriptRoot
$filter = '*.*'
$fsw = New-Object IO.FileSystemWatcher $configFilePath, $filter -Property #{IncludeSubdirectories = $true;NotifyFilter = [IO.NotifyFilters]'FileName, LastWrite'}
Register-ObjectEvent $fsw Created -SourceIdentifier FileCreated -Action {
$name = $Event.SourceEventArgs.Name
$changeType = $Event.SourceEventArgs.ChangeType
$timeStamp = $Event.TimeGenerated
Write-Host "The file '$name' was $changeType at $timeStamp" -fore green
Out-File -FilePath c:\temp\log\Filelog.txt -Append -InputObject "The file '$name' was $changeType at $timeStamp"
Set-Location "$PSScriptRoot"
Start-Process "$PSScriptRoot\PS_Run.bat"
}
Wait-Event -SourceIdentifier FileCreated -Timeout 50 # or no of seconds before file shows up.
When run as a scheduled task, this will execute the bat file as soon as a new file is created and close the console when the timeout is reached.

Check if file exist in folder?

I'm not sure how to do this. I need to execute an script.
The script needs to watch a folder for files created. If the files are created it will trigger a series of functions.
But prior to that, the script must ALWAYS check if a certain file exist. Because otherwise the script will not execute. The existing file needs to be moved before doing anything else.
I tried using the filechanged event but it will overwrite the existing file...
Is there a way to do this?
Here is the beginning of the script:
$fsw = New-Object IO.FileSystemWatcher $folder, $filter -Property #{
IncludeSubdirectories = $true # <-- set this according to your requirements
NotifyFilter = [IO.NotifyFilters]'FileName, LastWrite'
}
$onCreated = Register-ObjectEvent $fsw Created -SourceIdentifier FileCreated -Action {
$path = $Event.SourceEventArgs.FullPath
$name = $Event.SourceEventArgs.Name
$changeType = $Event.SourceEventArgs.ChangeType
$timeStamp = $Event.TimeGenerated
Write-Host "The file '$name' at '$path'was $changeType at $timeStamp" -Fore white
$lineas = (Get-Content $root\UNB\TMP\FACT_TEMPORAL.TXT | Measure-Object -Line).Lines
Write-Host "El archivo contiene $lineas lineas" -Fore white
if ($lineas -gt 3) {
Write-Host "El archivo contiene informaciĆ³n" -Fore white
limpia
leeyedita
printpdf
borrar
renombra
} else {
Write-Host "El archivo NO contiene informaciĆ³n" -Fore white
borrar
}
}

FileWatcher Task

Goal: create a file watcher to execute some tasks when a file stops being written to (i.e. file size stops changing or last write hasn't occurred in X time)
I know you can use powershell to create tasks when files are created/deleted/changed/renamed. Is there a way to utilize this to say do something if the file hasn't changed for X time (utilizing powershell or another language)?
$folder = '<path>' # Enter the root path you want to monitor.
$filter = '*.*' # You can enter a wildcard filter here.
# In the following line, you can change 'IncludeSubdirectories to $true if required.
$fsw = New-Object IO.FileSystemWatcher $folder, $filter -Property #{IncludeSubdirectories = $false;NotifyFilter = [IO.NotifyFilters]'FileName, LastWrite'}
# Here, all three events are registerd. You need only subscribe to events that you need:
Register-ObjectEvent $fsw Created -SourceIdentifier FileCreated -Action {
$name = $Event.SourceEventArgs.Name
$changeType = $Event.SourceEventArgs.ChangeType
$timeStamp = $Event.TimeGenerated
Write-Host "The file '$name' was $changeType at $timeStamp" -fore green
Out-File -FilePath c:\scripts\filechange\outlog.txt -Append -InputObject "The file '$name' was $changeType at $timeStamp"}
Register-ObjectEvent $fsw Deleted -SourceIdentifier FileDeleted -Action {
$name = $Event.SourceEventArgs.Name
$changeType = $Event.SourceEventArgs.ChangeType
$timeStamp = $Event.TimeGenerated
Write-Host "The file '$name' was $changeType at $timeStamp" -fore red
Out-File -FilePath c:\scripts\filechange\outlog.txt -Append -InputObject "The file '$name' was $changeType at $timeStamp"}
Register-ObjectEvent $fsw Changed -SourceIdentifier FileChanged -Action {
$name = $Event.SourceEventArgs.Name
$changeType = $Event.SourceEventArgs.ChangeType
$timeStamp = $Event.TimeGenerated
Write-Host "The file '$name' was $changeType at $timeStamp" -fore white
Out-File -FilePath c:\scripts\filechange\outlog.txt -Append -InputObject "The file '$name' was $changeType at $timeStamp"}
# To stop the monitoring, run the following commands:
# Unregister-Event FileDeleted
# Unregister-Event FileCreated
# Unregister-Event FileChanged
I don't know of an event type you can use to trigger that, but you can start a process like this on change or creation:
while ($true)
{
try{
[IO.file]::openwrite(<filepath>).close()
break
}
catch { start-sleep -Seconds 5 }
}
do-stuff
As long as the file is being written to you won't be able to get a write lock, and the openwrite will throw an error. As soon as it's closed, the openwrite will succeed, break the loop and fall through to the rest of the script.
Waiting for events won't help you when you're checking for the absence of events for a defined period of time. You can check the LastWriteTime property to see if the file has been changed in a given timespan:
$threshold = 5 # minutes
$f = Get-Item 'C:\path\to\your.file'
if (((Get-Date) - $f.LastWriteTime).TotalMinutes -lt $threshold) {
'File has been changed.'
}