对于某些打印问题(由citrix和远程服务器引起),我们有一个复杂的解决方案。基本上是从主服务器上,我们强制将pdf文件推送到远程计算机,然后有一个Powershell脚本,该脚本不断在远程计算机上运行以“捕获”文件并将其推送到本地打印机
这可以“很好”
但是,我们会随机退出。 powershell脚本似乎没有崩溃,因为它仍在Windows中运行,但实际操作似乎并未在处理新文件
我今天已经做了大量的阅读,并且提到必须在完成后命名和注销事件,否则会导致缓冲区溢出问题并使powershell停止处理该动作。但是我不确定它应该在代码中的实际位置。想法是该脚本将永久运行,那么我们是否要在动作本身或其他地方取消注册或删除事件?
我以前在动作中进行了大量虚拟登录,以尝试查找失败的地方,但是它似乎在没有任何正当理由的情况下停在了不同的位置(即,在查找文件或其他命令时失败)命令移动等的时间
### 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
while ($true) {sleep 5}
答案 0 :(得分:1)
如果您希望脚本在后台运行,请查看PowerShell后台作业。
如果您希望脚本永久运行,那么您希望使其成为服务...
请参阅以下内容:
How to Create a User-Defined Service
How to run a PowerShell script as a Windows service
...或将其附加到计划的任务,将在重新启动后重新启动。
有两种方法可以实现FileSystemWatcher。
从本质上讲,同步FileSystemWatcher会在检测到更改时将控制权返回给脚本,以便它可以处理更改。如果在您的脚本不再等待事件时发生另一个文件更改,则它将丢失。因此会导致意外的结果。
异步使用FileSystemWatcher,它将继续记录新的文件系统更改,并在PowerShell完成对先前更改的处理后对其进行处理。
*一个示例-示例异步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.'
}
答案 1 :(得分:0)
我还没有遇到可以在Windows上永久运行的脚本。 因此,考虑到这一点,我们认为理所当然会发生一些您无法控制的问题,例如network或电源或系统关闭。 考虑到这一点,我们为该脚本提供了一个生命周期,最后应适当清理所有内容。在这种情况下,我们有while循环,理论上应该永远不会结束,但是如果抛出异常,它将结束。在while循环中,如果任何事件都已注销,我们可以重新注册它们。如果观察者已被处置,我们可以重新创建它和事件。如果这确实是关键任务代码,那么我将把.net看作是hangfire和nlog作为Windows服务的替代方案。
### WRAP Everything in a try finally so we dispose of events
try {
### SET FOLDER TO WATCH + FILES TO WATCH + SUBFOLDERS YES/NO
$watcherArgs = @{
Path = "l:\files\cut"
Filter = "*.pdf"
IncludeSubdirectories = $false
EnableRaisingEvents = $true
}
$watcher = New-Object System.IO.FileSystemWatcher
$watcher.Path = $watcherArgs.Path
$watcher.Filter = $watcherArgs.Filter
$watcher.IncludeSubdirectories = $watcherArgs.IncludeSubdirectories
$watcher.EnableRaisingEvents = $watcherArgs.EnableRaisingEvents
### 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=$_
if($LASTEXITCODE -ne 0) {
# Do something
# Reset so we know when sumatra fails
$LASTEXITCODE = 0
}
& $sumatra -silent $scandir\$pdftoprint -print-to $printername
if($LASTEXITCODE -ne 0) {
# Do something to handle sumatra
}
sleep 3
# Split up copy and delete so we never loose files
[system.io.file]::Copy("$scandir\$pdftoprint", "$scanbackdir", $true)
[system.io.file]::Delete("$scandir\$pdftoprint")
}
}
### 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
$ErrorEvent = Register-ObjectEvent $watcher "Error" -Action $erroraction
$CreatedEvent = Register-ObjectEvent $watcher "Created" -Action $action
$ListOfEvents = @(
$ErrorEvent
$CreatedEvent
)
while ($true) {
$eventMissing = $false
$ListOfEvents | % {
$e = $_
if (!(Get-Event -SourceIdentifier $e.Name -ErrorAction SilentlyContinue)) {
# Event does not exist
$eventMissing = $true
}
}
if(!$watcher || $eventMissing -eq $true) {
# deregister events
$ListOfEvents | % {
$e = $_
try {
Unregister-Event -SourceIdentifier $e.Name
} catch {
# Do Nothing
}
}
if($watcher) {
$watcher.Dispose()
$watcher = $null
} else {
# Create watcher
$watcher = New-Object System.IO.FileSystemWatcher
$watcher.Path = $watcherArgs.Path
$watcher.Filter = $watcherArgs.Filter
$watcher.IncludeSubdirectories = $watcherArgs.IncludeSubdirectories
$watcher.EnableRaisingEvents = $watcherArgs.EnableRaisingEvents
$ErrorEvent = Register-ObjectEvent $watcher "Error" -Action $erroraction
$CreatedEvent = Register-ObjectEvent $watcher "Created" -Action $action
$ListOfEvents = @(
$ErrorEvent
$CreatedEvent
)
}
}
if ($watcher.EnableRaisingEvents -eq $false) {
$watcher.EnableRaisingEvents = $watcherArgs.EnableRaisingEvents
}
sleep 5
}
} finally {
$ListOfEvents | % {
$e = $_
try {
Unregister-Event -SourceIdentifier $e.Name
} catch {
# Do Nothing
}
}
if($watcher) {
$watcher.Dispose();
}
}