PowerShell - Start-Process和Cmdline开关

85

这段代码可以正常运行:

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

但是当我运行以下代码时,出现错误:

$msbuild = "C:\WINDOWS\Microsoft.NET\Framework\v3.5\MSBuild.exe /v:q /nologo" 
start-process $msbuild -wait
有没有一种方法可以使用 start-process 传递参数给 MSBuild?如果不使用 start-process,我也可以接受,我使用它的唯一原因是我需要将 "command" 作为变量。
当我有以下命令时:
C:\WINDOWS\Microsoft.NET\Framework\v3.5\MSBuild.exe /v:q /nologo
独立成一行,在 Powershell 中该如何处理?
是否应该使用类似于 eval() 的函数?

请参考 http://blogs.msdn.com/powershell/archive/2007/01/16/managing-processes-in-powershell.aspx 了解在 PowerShell 中启动进程的替代方法。 - i_am_jorf
感谢jeffamaphone,这是一些很好的参考信息。 - BuddyJoe
1
请注意,Start-Process是V2中的新功能。那篇文章中的信息非常好,但其中一些在V2中已经不再是必要的了。 - EBGreen
Start-Process本身是V2中新增的吗?您能详细说明一下吗?我没有安装V1的机器来测试。 - BuddyJoe
1
我只是指在V1中不存在Start-Process命令。在V1中,您必须使用Jef链接的博客文章中列出的方法之一。 - EBGreen
@i_am_jorf 这是一个新的替代 start-process 的链接: https://devblogs.microsoft.com/powershell/managing-processes-in-powershell/ - Kevin Driedger
6个回答

134

你需要将参数分开成单独的参数。

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

16
"$args" 作为变量名无法使用,因为它是保留字。请改用 "$arguments" 或其他名称。 - joshcomley
1
看起来建议队列已满,但我建议读者们要理解 -ArgumentList 正在寻找字符串,所以另一个答案中用逗号分隔的字符串示例(技术上是一个数组)可能会因为 PowerShell 可能展开它而起作用,但如果你想从一个数组中传递参数列表,最好事先将其“解包”成一个字符串。 - dragon788
4
“get-help start-process”显示,-ArgumentList项需要输入一个“String[]”类型。 - asynchronos

67

使用显式参数,它将是:

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

编辑:引用。


1
我认为没有它们也可以,但是有它们肯定更好,所以我会进行编辑。 - EBGreen
5
使用-ArgumentList ('/v:q','/nologo')似乎更加可靠。 - Peter Taylor
2
PowerShell非常冗长。git gui & - 这多简单啊(当然是*nix)!与start-Process git -ArgumentList gui相比,我知道我知道,没什么帮助。最近我一直在玩PowerShell,发现有很多好东西;但是冗长确实让人崩溃! - HankCa
1
好的,只有在你想要它冗长的情况下才是这样:start git -args gui 也可以。我意识到这仍然比 *nix 冗长。关键是如果你使用 Tab 自动补全和别名,那么实际击键数会大大减少。我还要补充一点,冗长意味着一个完全不懂 PowerShell 的人可以阅读 PS 命令,并更容易地理解它正在做什么。这只是哲学上的差异。 - EBGreen
@HankCa,sajb { git gui } - asynchronos
好的,谢谢更新。在查看文档和示例时我并没有看到这些用法。 - HankCa

9

警告

如果您在Powershell创建的cmd.exe窗口中运行PowerShell,则第二个实例不再等待作业完成。

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

现在从新的cmd窗口运行PowerShell,然后在其内部启动第二个cmd窗口:

cmd2> PowerShell

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

第二个PowerShell实例不再支持-Wait请求,所有后台进程/作业即使它们仍在运行也会返回“已完成”状态!当我的C#资源管理器程序用于打开cmd.exe窗口并从该窗口运行PS时,我发现了这一点,它也忽略了-Wait请求。似乎任何是cmd.exe的“win32 job”的PowerShell都无法遵守等待请求。我在Windows 7/x64上使用PowerShell版本3.0时遇到了这个问题。

5

我发现使用cmd作为替代方案很好,特别是当你需要将调用应用程序的输出作为管道传递时(尤其是当它不像msbuild一样具有内置日志记录功能时)。

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


2

除非OP正在使用提供Start-Process cmdlet以及一堆其他cmdlet的PowerShell社区扩展。如果是这种情况,那么Glennular的解决方案非常有效,因为它与pscx\start-process的位置参数匹配:-path(位置1)-arguments(位置2)。


2

如果你想让它等待,请在 start-process 语句中添加 -wait 标志。

# 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
    }
}

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接