Home HowTo Parameters Passing Arguments To Native Console Applications
 

Passing Arguments To Native Console Applications

Have you ever wondered why this command runs in a console window but fails in PowerShell?

  

explorer.exe /SELECT,C:\windows\system32\WindowsPowerShell\v1.0\powershell.exe

  Opens explorer and selects powershell.exe

Or put generally, why submitting arguments to console applications in PowerShell often fails?

The line above runs well in a cmd.exe: it opens the explorer and selects powershell.exe (provided your Windows-folder is c:\windows). In Powershell, explorer opens, too, but it is displaying the wrong folder and not selecting anything.

Understand How PowerShell Submits Arguments

The secret is just to understand how PowerShell carries over arguments to commands. The parser first parses the text, then the result is submitted to the command.

A comma always creates an array, so in reality, the call above has submitted two (!) arguments, wrapped in an array. Since explorer.exe expects only one argument, it takes "/SELECT" and omits the rest. That's why explorer starts and opens the default folder.

Turning Off The Parser

To turn off the parser, just remember that console applications expect plain text arguments, not objects. So simply enclose arguments in quotes, and you are set:

  

explorer.exe '/SELECT,C:\windows\system32\WindowsPowerShell\v1.0\powershell.exe'

  Enclose arguments in quotes to keep the parser away

Beginning in PowerShell 3.0, you can also use –%. Anything following this special sequence will taken as-is:

  

explorer.exe –% /SELECT,C:\windows\system32\WindowsPowerShell\v1.0\powershell.exe

  Turning off the parser using "–%"

However, –% has limitations because now, PowerShell is not touching the code anymore that follows –% and will no longer expand variables, either. Also, –% will not work in PowerShell 2.0.

So quoting is a better way. This works:

  

explorer.exe "/SELECT,$PSHome\powershell.exe"

  Use double-quotes to expand variables

And this fails:

  

explorer.exe —% /SELECT,$PSHome\powershell.exe

  –% will disable variable expansion

Dealing With Multiple Arguments

Watch out for console applications that really take multiple arguments. If a console application expects multiple arguments, you must submit them as an array.

Either use a variable that contains an array of strings that you want to pass on to the command, or use cmdlet syntax: submit strings separated by spaces, just like you would submit positional parameters to a cmdlet.

This example will use robocopy.exe to copy all sound files from the windows folder to another folder:

  

$SourcePath = $env:windir
$DestinationPath = 'c:\sounds'
$Filter = '*.wav'
$Recurse = '/S'
$Exclude = '*winsxs*'

robocopy.exe $SourcePath $DestinationPath $Filter /R:0  $Recurse /XD $Exclude

explorer.exe $DestinationPath

  Submitting multiple arguments to robocopy

As you can see, each argument is a separate parameter. If you quoted all of this, robocopy would fail:

  

robocopy.exe "$SourcePath $DestinationPath $Filter /R:0  $Recurse /XD $Exclude"
PS> robocopy.exe "$SourcePath $DestinationPath $Filter /R:0  $Recurse /XD $Exclude"

–––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––
   ROBOCOPY     ::     Robust File Copy for Windows                             
–––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––

  Started : Freitag, 14. Februar 2014 09:53:51
   Source –
     Dest –

    Files :
  Options : /DCOPY:DA /COPY:DAT /R:1000000 /W:30

––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––

ERROR : Invalid Parameter #1 : "C:\WINDOWS c:\sounds *.wav /R:0  /S /XD *winsxs*"

       Simple Usage :: ROBOCOPY source destination /MIR

             source :: Source Directory (drive:\path or \\server\share\path).
        destination :: Destination Dir  (drive:\path or \\server\share\path).
               /MIR :: Mirror a complete directory tree.

    For more usage information run ROBOCOPY /?

                                                         
****  /MIR can DELETE files as well as copy them !

PS> 

The error message clearly states that now, the entire array of arguments have been passed to robocopy's first parameter:

ERROR : Invalid Parameter #1 : "C:\WINDOWS c:\sounds *.wav /R:0  /S /XD *winsxs*"

So always remember to submit each argument as a separate string. If you feel like it and because of this, you can submit the arguments as string array in just one variable:

  

$SourcePath = $env:windir
$DestinationPath = 'c:\sounds'
$Filter = '*.wav'
$Recurse = '/S'
$Exclude = '*winsxs*'

$arguments = $SourcePath, $DestinationPath, $Filter, '/R:0', $Recurse, '/XD', $Exclude

robocopy.exe $arguments

explorer.exe $DestinationPath

  Submitting a string array to a console application

As you can see, in this example robocopy takes its argument information from $arguments.

With these simple tricks, and by understanding how PowerShell sends arguments and how console applications receive them, you can now easily integrate console applications into your PowerShell code.

And always remember: if the console application returns a numeric ErrorLevel information, then this will be available in $LASTEXITCODE after the application executed. And if the console application returns text, you can assign it to a variable to receive it, keep it, and further process it:

  

$info = whoami.exe /GROUPS /FO CSV
$info | ConvertFrom-CSV | Out-GridView

  Displaying a list of group memberships

May the PowerShell be with you!

Tobias