Monday, November 24, 2014

Automatically Print and Delete PDFs Dumped in a Folder

Problem:


Last week I spent an inordinate amount of time setting up a new network scanner. One of the features this scanner lacks is the ability to scan directly to a printer emulating a copier. The scanner operates under the assumption that you have network printers with FTP print capabilities than can natively print PDFs. Unfortunately, the printers we have do not support native PDF printer, though they do support FTP printing of driver generated .prn files.

"No biggy!" I thought. "Surely others out there have run into this and there are some ready made PowerShell or VBS scripts to do this." I was wrong. What I didn't consider is that PDFs need to be processed by a PDF reader application to then be sent to a printer driver and subsequently printed. I did find scripts that would do this with Adobe Reader, but it would only work to the default printer. This wouldn't work for us as we need to differentiate between the color printer and black and white printer.

In summary: windows cannot natively print PDFs via script and a third party PDF viewer will be needed.

After some digging I found Sumatra PDF. It is a free, open source PDF viewer that has some command line print options that do not launch the GUI. The key difference between this PDF viewer and others I researched was the ability to specify a printer from the command line. So long as the printer has been added to the machine Sumatra PDF is launched on, that printer can be used to print PDFs from the command line without launching the GUI along with error suppression. This makes it the ideal candidate for scriptable PDF printing.

After selecting the PDF viewer to be used, I just needed to create the surrounding script to scan a folder for PDFs, execute Sumatra PDF to print the PDF, and then delete the PDF file. Then I added a new scan to network option to the scanner and have it save the scan to the shared folder. I created multiple "dump" folders, shared them, created multiple scan to network options to accommodate multiple printers, and concurrently ran multiple instances of the PowerShell script. I then had a functioning copier emulation.

There are a few caveats. The first of which is that this only works for single-sided printing and not duplex printing. If you scan a double sided-document, it will only print single-sided. To correct this, I could modify the script to accept more Sumatra PDF command line arguments to enable double sided printer, create another dump folder, create another scan to network settings, and set the script to monitor that folder, and then print using the double-sided option. I decided that wasn't completely necessary for our environment, but it's not to hard to implement.

The next caveat is that this has to run as a task that starts on machine startup. PowerShell windows tasks are a pain. I will give an example task after the script code to use as reference. This also means the task needs to run as a user that has read/write to the "dump" folders, execute permissions on Sumatra PDF, and print permissions. I gave up trying to make this all work nicely and have the task running with elevated privileges. You could by pass all this and just run the scripts in a perpetually open PowerShell window, but that's not a very "survivable" option.

The final caveat is the delay. This is more of a user experience issue than anything else. A copier would scan and start printing right away. This setup needs to scan, upload, get processed, send to printer, print. This is good enough for government work, but probably best to get something that does direct copying if your users are impatient. The script does include an adjustable sleep cycle setting allowing you to scan the folder more or less frequently. But the lower the sleep seconds, the more file system reads you will inflict on whatever system houses the "dump" folders.

Now, I will shut up and give you what you googled for.

Code:



######## Configuration ###########################
# Parameters:
#    DUMPFLDR: location of the dump folder where pdf's will be deposited
#    PRINTER: Printer share location
#    SUMATRA: Location of the sumatrapdf.exe (A free PDF viewer used to print the PDFs)
#        http://blog.kowalczyk.info/software/sumatrapdf/download-free-pdf-viewer.html
#    SLEEPFOR: How long to sleep, if necesary, between program loops in seconds
#
# Example:
#    pdfdump.ps1 -DUMPFLDR "C:\scripts\pdfdump" -PRINTER "\\printserver\PRINTER1" -SUMATRA "C:\scripts\SumatraPDF.exe -SLEEPFOR 15 -LOGFILE "c:\script\pdfdump.log"
#
# The defaults can be set below for when no command line parameter is given
param(
    [string]$DUMPFLDR="D:\PDFDUMP\PRINTER1",
    [string]$PRINTER="\\printserver\PRINTER1",
    [string]$SUMATRA="C:\scripts\SumatraPDF.exe",
    [int]$SLEEPFOR=15,
    [string]$LOGFILE="c:\scripts\pdfdump.log"
)
####### End configuration ########################
$scriptpath = $MyInvocation.MyCommand.Path
$hostname=hostname

$ErrorActionPreference="SilentlyContinue"

echo "$(get-date) - Starting pdfdump from $scriptpath on $hostname with parameters DUMPFLDR:$DUMPFLDR PRINTER:$PRINTER SUMATRA:$SUMATRA SLEEPFOR:$SLEEPFOR LOGFILE:$LOGFILE" | Out-File -Append $LOGFILE

while ( $true )
{
    $starttime = $(get-date)
 get-childitem -recurse -path $DUMPFLDR -filter "*.pdf" | % {
  $curfile = $_
  echo "$(get-date) - Printing $DUMPFLDR\$curfile on $PRINTER..." | Out-File -Append $LOGFILE
  & $SUMATRA -silent -print-to $PRINTER $DUMPFLDR\$curfile | Out-Null  | Out-File -Append $LOGFILE
        echo "$(get-date) - Deleting $DUMPFLDR\$curfile..."  | Out-File -Append $LOGFILE
        Remove-Item $DUMPFLDR\$curfile  | Out-File -Append $LOGFILE
 }
    $elapsedtime = $(get-date) - $starttime  
    $sleeptime = $SLEEPFOR - $elapsedtime.seconds
    start-sleep $sleeptime  | Out-File -Append $LOGFILE
}

Scheduled Task Configuration Example:

This assumes the following:

  • Script location: c:\scripts\pdfdump.ps1
  • Network printer: \\printserver\PRINTER1
  • Dump folder: d:\PDFDUMP\PRINTER1\
  • Log File: C:\scripts\pdfdump.log
Configuration details:
  •   General Tab
    • Name: PRINTER1 PDF Dump
    • Security Options
      • Run whether user is logged on or not
      • Run with highest privileges
  • Triggers Tab
    • At Startup
  • Action
    • Action: Start a program
    • Program/script: PowerShell
    • Add arguments: -NonInteractive -WindowStyle Hidden -command "& C:\scripts\pdfdump.ps1 -DUMPFLDR 'D:\PDFDUMP\PRINTER1' -PRINTER '\\printserver\PRINTER1' -LOGFILE 'C:\scripts\pdfdump.log'"
    • Start in: c:\scripts\
  • Conditions Tab
    • Uncheck everything to ensure it always runs
  • Settings Tab
    • Check and set:
      • Allow task to be run on demand
      • Run task as soon as possible after a scheduled start is missed
      • If the task fails, restart every: 1 minute
        • Attempt to restart up to: 30 times
      • If the running task does not end when
    • Uncheck
      • Stop the task if it runs longer than
      • If the task is not scheduled to run again, delete it after