Hi all
Please forgive me for possibly asking a stupid or repeated question, I’m only really a notice scripter and an absolute newbie when it comes to PowerShell
We have a convoluted solution to some printing issues (caused by citrix and remote servers). Basically from the main server, we force push a pdf file to the remote pc and then have a powershell script which constantly runs on the remote pc to “catch” the file and push it to the local printer
This works “fine”
However we get random dropouts. The powershell script doesn’t seem to have crashed because it’s still running in windows but the actual action doesn’t seem to be processing new files
I have done A LOT of reading today and there’s mention of having to name and unregister events when you’re done otherwise it can cause a buffer overflow issues and make powershell stop processing the action. But I’m unsure where it should actually go within the code. The idea is that this script will run permanently, so do we unregister or remove the event within the action itself or somewhere else?
I previous had A LOT of dummy logging going on within the action to try to find where it failed, but it seems to stop at different points without any justifiable reason (ie, it would fail at the command to find files, other times at the command to move etc etc)
### SET FOLDER TO WATCH + FILES TO WATCH + SUBFOLDERS YES/NO
$watcher = New-Object System.IO.FileSystemWatcher
$watcher.Path = "l:\files\cut"
$watcher.Filter = "*.pdf"
$watcher.IncludeSubdirectories = $false
$watcher.EnableRaisingEvents = $true
### DEFINE ACTIONS AFTER AN EVENT IS DETECTED
$action = { $path = $Event.SourceEventArgs.FullPath
$changeType = $Event.SourceEventArgs.ChangeType
$scandir="l:\files\cut"
$scanbackdir="l:\files\cut\back"
$scanlogdir="l:\files\cut\log"
$sumatra="l:\SumatraPDF.exe"
$pdftoprint=""
$printername= "MainLBL"
### Get the List of files in the Directory, print file, wait and then move file
Get-ChildItem -Path $scandir -filter "*.pdf" -Name | % {
$pdftoprint=$_
& $sumatra -silent $scandir\$pdftoprint -print-to $printername
sleep 3
Move-Item -force $scandir\$pdftoprint $scanbackdir
}
}
### Define what happens when script fails
$erroraction = {echo $(get-date) the process crashed | Out-File -Append l:\files\cut\log\errorlog.txt}
### DECIDE WHICH EVENTS SHOULD BE WATCHED
Register-ObjectEvent $watcher "Error" -Action $erroraction
Register-ObjectEvent $watcher "Created" -Action $action
Are there a lot of documents being processed? Have you already tried increasing the buffer size? InternalBufferSize
cross posted. Here was my response to you from the other site.
If you want a script to run in the background, then look to PowerShell background jobs.
If you want a script to run permanently, then you want to make it a service …
See these:
How to Create a User-Defined Service
How to run a PowerShell script as a Windows service
… or attach that to a scheduled task, that would restart it on reboots.
There are two ways to implement a FileSystemWatcher.
A synchronous FileSystemWatcher, by it nature, when a change is detected, control is returned to your script so it can process the change. If another file change occurs while your script is no longer waiting for events, it gets lost. Hence leading to unexpected outcomes.
Using the FileSystemWatcher Asynchronously, it would continue to log new filesystem changes and process them once PowerShell is done processing previous changes.
*** An Sample - Example Asynchronous FileSystemWatcher***
### New-FileSystemWatcherAsynchronous
# Set the folder target
$PathToMonitor = Read-Host -Prompt 'Enter a folder path'
$FileSystemWatcher = New-Object System.IO.FileSystemWatcher
$FileSystemWatcher.Path = $PathToMonitor
$FileSystemWatcher.IncludeSubdirectories = $true
# Set emits events
$FileSystemWatcher.EnableRaisingEvents = $true
# Define change actions
$Action = {
$details = $event.SourceEventArgs
$Name = $details.Name
$FullPath = $details.FullPath
$OldFullPath = $details.OldFullPath
$OldName = $details.OldName
$ChangeType = $details.ChangeType
$Timestamp = $event.TimeGenerated
$text = "{0} was {1} at {2}" -f $FullPath, $ChangeType, $Timestamp
Write-Host $text -ForegroundColor Green
# Define change types
switch ($ChangeType)
{
'Changed' { "CHANGE" }
'Created' { "CREATED"}
'Deleted' { "DELETED"
# Set time intensive handler
Write-Host "Deletion Started" -ForegroundColor Gray
Start-Sleep -Seconds 3
Write-Warning -Message 'Deletion complete'
}
'Renamed' {
$text = "File {0} was renamed to {1}" -f $OldName, $Name
Write-Host $text -ForegroundColor Yellow
}
default { Write-Host $_ -ForegroundColor Red -BackgroundColor White }
}
}
# Set event handlers
$handlers = . {
Register-ObjectEvent -InputObject $FileSystemWatcher -EventName Changed -Action $Action -SourceIdentifier FSChange
Register-ObjectEvent -InputObject $FileSystemWatcher -EventName Created -Action $Action -SourceIdentifier FSCreate
Register-ObjectEvent -InputObject $FileSystemWatcher -EventName Deleted -Action $Action -SourceIdentifier FSDelete
Register-ObjectEvent -InputObject $FileSystemWatcher -EventName Renamed -Action $Action -SourceIdentifier FSRename
}
Write-Host "Watching for changes to $PathToMonitor" -ForegroundColor Cyan
try
{
do
{
Wait-Event -Timeout 1
Write-Host '.' -NoNewline
} while ($true)
}
finally
{
# End script actions + CTRL+C executes the remove event handlers
Unregister-Event -SourceIdentifier FSChange
Unregister-Event -SourceIdentifier FSCreate
Unregister-Event -SourceIdentifier FSDelete
Unregister-Event -SourceIdentifier FSRename
# Remaining cleanup
$handlers |
Remove-Job
$FileSystemWatcher.EnableRaisingEvents = $false
$FileSystemWatcher.Dispose()
Write-Warning -Message 'Event Handler completed and disabled.'
}