2

Using PowerShell I would like to invoke the print verb on multiple files. In Windows Explorer I can go into a folder, select a number of files, right-click and choose the print options. This opens up the Print Pictures dialog with all the selected files. I am able to do this for one file using:

$path = "C:\person.jpg";
Start-Process -FilePath $path -Verb Print | Out-Null;
Start-Sleep -s 150;

But was wondering how I could do it for a number of files.

Lance U. Matthews
  • 15,725
  • 6
  • 48
  • 68
daibatzu
  • 507
  • 4
  • 16

2 Answers2

3

You can use COM to invoke a verb on multiple files in one operation.

Assuming...

$folderPath = 'X:\Test'
$verbName = 'print'
$verbArguments = ''

...you can print all objects in a folder with...

$application = New-Object -ComObject 'Shell.Application'
$folder = $application.NameSpace($folderPath)
$folderItems = $folder.Items()
Write-Verbose "Folder ""$($folder.Self.Name)"" contains $($folderItems.Count) item(s)."
$folderItems.InvokeVerbEx($verbName, $verbArguments)

I say "objects" because $folderItems will contain both files and folders. The default appears to be enumerate subfolders and ignore hidden objects, while verbs are ignored on objects that don't support them.

If, for example, you wanted to only print files with a certain extension that are immediate children and include hidden files, you can do so using the Filter() method...

New-Variable -Name 'SHCONTF_NONFOLDERS'    -Option 'Constant' -Value 0x00040
New-Variable -Name 'SHCONTF_INCLUDEHIDDEN' -Option 'Constant' -Value 0x00080

$application = New-Object -ComObject 'Shell.Application'
$folder = $application.NameSpace($folderPath)
$folderItems = $folder.Items()
$folderItems.Filter($SHCONTF_NONFOLDERS -bor $SHCONTF_INCLUDEHIDDEN, '*.jpg')
Write-Verbose "Filtered folder ""$($folder.Self.Name)"" contains $($folderItems.Count) item(s)."
$folderItems.InvokeVerbEx($verbName, $verbArguments)

If you want to print some custom set of files that don't nicely align by extension, visibility, etc. then I'm not seeing a way to do that. That would seem to require modifying $folderItems or creating a new FolderItems3 instance, and neither appears to be possible. I see there is a ShellFolderView type that supports item selection, but that looks like it's for interacting with an Explorer(-like) window.

Documentation for types and constants used above:

Lance U. Matthews
  • 15,725
  • 6
  • 48
  • 68
  • Thanks a lot. This is pretty much the answer. there is just one small problem. I aready have the list of files in a folder as in $fileList = "C:\Projects\Javascript\photos\Silvercoins.jpg","C:\Projects\Javascript\photos\celeste.png";. I tried applying a filter to folderitems but it then shows the print preview one at a time. Without a filter it prints in one batch. Can you please also help with that? – daibatzu Jun 29 '19 at 22:46
  • What does your call to `Filter()` look like? You want `Silvercoins.jpg` and `celeste.png` to be printed in the same or separate print jobs? Are those the only files in `photos\\`` that support printing, or there are others that you want to exclude from being printed? – Lance U. Matthews Jun 29 '19 at 23:21
  • My filter is $folderItems = $folder.Items() | ? { $fileList -contains $_.Path }; These are not the only files that support printing, I am selecting some files in my program and then printing them. Thanks – daibatzu Jun 30 '19 at 00:12
  • 1
    To change the files operated on by `InvokeVerbEx()` you'd need to somehow modify the collection returned by `$folder.Items()`; `$folder.Items() | ? { $fileList -contains $_.Path }` yields a new collection entirely. If you need to operate on an arbitrary set of files the potential workarounds I can think of are 1) copy that set of files to a temporary directory and print from there, 2) same as #1 but using shortcuts/symlinks/hardlinks to the original files, or 3) if you're printing graphics files only maybe there's a module or library that makes it easy to create print jobs from those. – Lance U. Matthews Jun 30 '19 at 17:10
1

As far as I know, you can use foreach to iterate over all items in an array of items (files that you want to print), and execute the action print on each one of them as follows:

Get-ChildItem "C:\" -Include "*.jpg" | ForEach-Object {start-process $_.FullName –Verb Print}
Start-Sleep -s 150

This will:

  • get all the files (jpg files) found in C

  • apply the verb print on each file.

Note You can use -wait parameter for Start-Process instead of Start-Sleep -s 150; This waits for the specified process and its descendants to complete before accepting more input.

Shadowfax
  • 556
  • 2
  • 13