2

I am trying to write a wrapper script in Powershell which is passed the name of an executable, does some preprocessing, then invokes that executable with arguments resulting from that preprocessing. I want the executable to be anything you can run/open on Windows so I want to use Start-Process to run it so Invoke a second script with arguments from a script (which references Invoke-Expression) isn't really relevant. What I'm finding is that when the executable is another Powershell script, the arguments aren't seen by the script.

My stupid little test is:

Write-Output "Arg0: '$($Args[0])', Arg1: '$($Args[1])'" >>test.log

And working at a PS prompt this is what I see:

PS C:\Source> .\test.ps1 a b
PS C:\Source> more .\test.log
Arg0: 'a', Arg1: 'b'

PS C:\Source> .\test.ps1 c d
PS C:\Source> more .\test.log
Arg0: 'a', Arg1: 'b'
Arg0: 'c', Arg1: 'd'

PS C:\Source> Start-Process .\test.ps1 -ArgumentList e,f
PS C:\Source> Start-Process .\test.ps1 -Args e,f
PS C:\Source> more .\test.log                                                                                   
Arg0: 'a', Arg1: 'b'
Arg0: 'c', Arg1: 'd'
Arg0: '', Arg1: ''
Arg0: '', Arg1: ''

PS C:\Source>   

Which is consistent with what I see when using Start-Process in a script. I've spend a couple of hours Googling without finding an answer. Any thoughts?

I'm working on Windows 10 for development but my target is Windows Server. I don't know that that should make a difference.

Chris Nelson
  • 3,519
  • 7
  • 40
  • 51
  • 2
    `Start-Process .\test.ps1` treats `.\test.ps1` like a _document_, it performs the same default action you would get if you double-clicked the file in explorer (which, by default, is to open the script _for editing_). Also `Start-Process` is _asynchronous_ by default, so you'd have to pass `-Wait`. If you simply want to run a script / console application _in the same console window, synchronously_, don't use `Start-Process` at all. – mklement0 Feb 06 '20 at 16:42

1 Answers1

3

You need to invoke the script through powershell.exe:

Start-Process powershell -ArgumentList "-File .\test.ps1 arg1 arg2 argX"

You can specify the argument list either as a string or an array of strings. See example 7 here for more information.

As stated by @mklement0 in the question comment, if you don't invoke it through powershell.exe, it will execute it in the default context as Windows thinks that .ps1 files should be executed, which does not pass additional arguments to the script in this case.


You may not need to use Start-Process though - If you don't require any of the special functionality provided by Start-Process you can also just call the script using the call & operator or by specifying the path to the script just like you would interactively:

# You can use a variable with the path to the script
# in place of .\test.ps1 here and provide the arguments
# as variables as well, which lets you build a dynamic
# command out without using `Start-Process` or `Invoke-Expression`.
& .\test.ps1 arg1 arg2 argX

or

# You can use variables for the arguments here, but the script name
# must be hardcoded. Good for cases where the entrypoint doesn't change.
.\test.ps1 arg1 arg2 argX

You may also want to look into using argument splatting for your arguments as well when building out dynamic commands. I wrote an answer here as well which goes over splatting in more detail.

codewario
  • 19,553
  • 20
  • 90
  • 159
  • 1
    Thanks. `& $executable @argsArray` then testing `$?` does what I wanted. – Chris Nelson Feb 06 '20 at 18:34
  • Note that `$?` checks whether the last *cmdlet* succeeded. *External commands* (`exe` files) don't indicate success through `$?`, you have to check the value of `$LASTEXITCODE`. – codewario Sep 11 '21 at 18:07