1

I trying to create a script that will convert Markdown files that are dropped on a processing script.

To accomplish this, I created a (process.bat) that would pass the names of the dropped files to a PowerShell script:

powershell.exe -NoProfile -File "./process.ps1" -Document %*
@pause

The PowerShell file (process.ps1) would process each file individually:

[parameter(Mandatory=$true)]
[String[]]$Document

Write-Host $args[1]

$Document | ForEach-Object {
  Write-Host "Document: $_"

  # convert Markdown to Html
  pandoc -o ($_ -Replace '.md', '.html') -f markdown -t html $_
}

When I drop two files on the batch file:

C:\Users\XXX\Documents\WindowsPowerShell\Scripts\Markdown>powershell.exe -NoProfile -File "./process.ps1" -Document "C:\Users\XXX\Documents\WindowsPowerShell\Scripts\Markdown\FOO.md"
"C:\Users\XXX\Documents\WindowsPowerShell\Scripts\Markdown\BAR.md"
C:\Users\XXX\Documents\WindowsPowerShell\Scripts\Markdown\BAR.md
Document: 
Press any key to continue . . .

The documents are not being processed.

What's the recommended approach to passing the batch file's file list %* to PowerShell?

mklement0
  • 382,024
  • 64
  • 607
  • 775
craig
  • 25,664
  • 27
  • 119
  • 205
  • 1
    I'm not sure why you're wasting time using a batch file to run a powershell script. The only reason would be that you wanted to run it with an alternative execution policy, but it is clear that you aren't. Why not drop your files onto a powershell script instead? – Compo Sep 23 '19 at 17:18
  • @Compo, I didn't realize (or consider) that a `PS1` file could handle this. – craig Sep 23 '19 at 17:44
  • @Compo: It's worth noting that cannot use a `*.ps1` file _directly_ as a drop target, but you can via a _shortcut file_ (`*.lnk`) that invokes the script explicitly; craig, please see the update to my answer. – mklement0 Sep 23 '19 at 18:47
  • 1
    Thanks for the note, @mklement0, I'd never tried it TBH. – Compo Sep 23 '19 at 19:29

1 Answers1

1

When powershell.exe, the PowerShell CLI, is called from the outside with the -File parameter, it doesn't support arrays - only individual arguments.[1]

(Additionally, you neglected to wrap your parameter definition in a param(...) block, which effectively caused it be ignored.)

The simplest solution is to define your parameter with the ValueFromRemainingArguments option so that it automatically collects all positional arguments in the parameter variable:

param(
  [Parameter(Mandatory, ValueFromRemainingArguments)]
  [String[]] $Document
)

Then invoke your script via the PowerShell CLI without -Document:

powershell.exe -NoProfile -File "./process.ps1" %*

As an alternative to using a helper batch file, you can:

  • define a shortcut file (*.lnk) that explicitly invokes your PowerShell script as powershell.exe -File \path\to\your\script.ps1 (without additional arguments)

  • and then use that as the drop target.

Note: The reason that you cannot use a PowerShell script (*.ps1) directly as a drop target is that PowerShell script files aren't directly executable - instead, opening (double-clicking) a *.ps1 file opens it for editing.

You'd then need to add pause (or something similar, such as Read-Host -Prompt 'Press Enter to exit.') to your PowerShell script, to prevent it from closing the window instantly on finishing.

Alternatively, leave the script as-is and use -NoExit (placed before -File) to keep the PowerShell session open.


[1] The same applies to the PowerShell Core CLI, pwsh.

mklement0
  • 382,024
  • 64
  • 607
  • 775