85

I can run this fine:

$msbuild = "C:\WINDOWS\Microsoft.NET\Framework\v3.5\MSBuild.exe" 
start-process $msbuild -wait

But when I run this code (below) I get an error:

$msbuild = "C:\WINDOWS\Microsoft.NET\Framework\v3.5\MSBuild.exe /v:q /nologo" 
start-process $msbuild -wait

Is there a way I can pass parameters to MSBuild using start-process? I'm open to not using start-process, the only reason I used it was I needed to have the "command" as a variable.

When I have
C:\WINDOWS\Microsoft.NET\Framework\v3.5\MSBuild.exe /v:q /nologo
on a line by itself, how does that get handled in Powershell?

Should I be using some kind of eval() kind of function instead?

BuddyJoe
  • 69,735
  • 114
  • 291
  • 466
  • See http://blogs.msdn.com/powershell/archive/2007/01/16/managing-processes-in-powershell.aspx for alternatives to start-process. – i_am_jorf Mar 16 '09 at 17:01
  • Thanks jeffamaphone, this was some good reference info also. – BuddyJoe Mar 16 '09 at 17:11
  • 1
    Keep in mind that Start-Process is a new feature in V2. The information in that post is very good but some of it is not really necessary anymore in V2. – EBGreen Mar 16 '09 at 17:19
  • Start-Process itself is new to V2? Can you elaborate a little? I don't have any machine with V1 installed to test. – BuddyJoe Mar 16 '09 at 18:18
  • 1
    I just mean that the Start-Process commandlet did not exist in V1. In V1 you had to use one of the methods listed in the blog post that Jef linked. – EBGreen Mar 16 '09 at 18:44
  • @i_am_jorf Here's the new link to alternatives to start-process: https://devblogs.microsoft.com/powershell/managing-processes-in-powershell/ – Kevin Driedger Jun 22 '20 at 18:30

6 Answers6

133

you are going to want to separate your arguments into separate parameter

$msbuild = "C:\WINDOWS\Microsoft.NET\Framework\v3.5\MSBuild.exe"
$arguments = "/v:q /nologo"
start-process $msbuild $arguments 
Glennular
  • 17,827
  • 9
  • 58
  • 77
  • 16
    `$args` as a variable name doesn't work, it's reserved. Use `$arguments` or anything else instead – joshcomley Dec 05 '12 at 11:56
  • 1
    Looks like the suggestion queue is full, but I would advise readers to understand that `-ArgumentList` is looking for string, so the example on another answer with comma separated strings (technically an array) may work because of how PowerShell potentially unrolls it, but if you are looking to pass in an argument list from an array it's probably best to "unpack" it into a string beforehand. – dragon788 Apr 03 '17 at 21:34
  • 4
    @dragon788, `get-help start-process` indicates that -ArgumentList expects `String[]` – asynchronos Jan 12 '19 at 01:12
67

Using explicit parameters, it would be:

$msbuild = 'C:\WINDOWS\Microsoft.NET\Framework\v3.5\MSBuild.exe'
start-Process -FilePath $msbuild -ArgumentList '/v:q','/nologo'

EDIT: quotes.

Lucas Pottersky
  • 1,844
  • 6
  • 22
  • 38
EBGreen
  • 36,735
  • 12
  • 65
  • 85
  • 1
    I think it would be ok without them, but it would definitely be ok with them so I will edit it – EBGreen Jul 05 '11 at 12:35
  • 5
    It seems to be more reliable to use `-ArgumentList ('/v:q','/nologo')` – Peter Taylor Oct 19 '15 at 11:58
  • 2
    Powershell is SO verbose. `git gui &` -- how simple is that (*nix of course)! Compared to `start-Process git -ArgumentList gui`. I know I know, not helpful. I've been playing with Powershell a bit lately and lots of nice things; but the verbosity is a killer! – HankCa Nov 06 '17 at 01:58
  • 1
    Well, it is only that verbose if you want it to be: ***start git -args gui*** works too. I realize that this is still more verbose than *nix. The point is that if you use tab completion and aliases, then the number of actual keystrokes goes down considerably. I will also add that the verbosity means that a person that does not know powershell well at all could read the PS command and more easily understand exactly what it is doing. Just a difference in philosophy. – EBGreen Nov 07 '17 at 15:43
  • @HankCa, `sajb { git gui }` – asynchronos Jan 12 '19 at 01:21
  • Ok thanks for the updates. I didn't see these usages at all when looking at doco and examples. – HankCa Jan 15 '19 at 01:24
9

Warning

If you run PowerShell from a cmd.exe window created by Powershell, the 2nd instance no longer waits for jobs to complete.

cmd>  PowerShell
PS> Start-Process cmd.exe -Wait 

Now from the new cmd window, run PowerShell again and within it start a 2nd cmd window: cmd2> PowerShell

PS> Start-Process cmd.exe -Wait
PS>   

The 2nd instance of PowerShell no longer honors the -Wait request and ALL background process/jobs return 'Completed' status even thou they are still running !

I discovered this when my C# Explorer program is used to open a cmd.exe window and PS is run from that window, it also ignores the -Wait request. It appears that any PowerShell which is a 'win32 job' of cmd.exe fails to honor the wait request.

I ran into this with PowerShell version 3.0 on windows 7/x64

LanDenLabs
  • 1,566
  • 16
  • 10
5

I've found using cmd works well as an alternative, especially when you need to pipe the output from the called application (espeically when it doesn't have built in logging, unlike msbuild)

cmd /C "$msbuild $args" >> $outputfile

ΩmegaMan
  • 29,542
  • 12
  • 100
  • 122
midspace
  • 922
  • 9
  • 18
2

Unless the OP is using PowerShell Community Extensions which does provide a Start-Process cmdlet along with a bunch of others. If this the case then Glennular's solution works a treat since it matches the positional parameters of pscx\start-process : -path (position 1) -arguments (positon 2).

Keith Hill
  • 2,329
  • 1
  • 19
  • 7
2

If you want it to wait add -wait flag to start-processs statements.

# Start EXE as a detected process
function StartExe {
    [CmdletBinding()]
    param(
        [Parameter(Mandatory=$true, Position=0)]
        [string]$ProcessName,

        [Parameter(Mandatory=$false, Position=1, ValueFromRemainingArguments=$true)]
        [string[]]$Arguments
    )

    # Command line as Multiple Arguments:
    #    PS> StartExe tclsh myscript.tcl arg1 arg2 arg3
    if ($Arguments) {
        $argumentString = $Arguments -join ' '
        Start-Process -FilePath $ProcessName -ArgumentList $argumentString -NoNewWindow
    }
    
    # Command line as a Single Argument:
    #    PS> StartExe "tclsh myscript.tcl arg1 arg2 arg3"
    else {
        Start-Process -FilePath 'cmd.exe' -ArgumentList "/c $ProcessName" -NoNewWindow
    }
}
Bimo
  • 5,987
  • 2
  • 39
  • 61