如何从PowerShell将字符串和数组的混合形式传递给可执行文件?

时间:2019-04-29 11:15:24

标签: powershell

出于CI目的,我正在尝试将vswhere.exe调用到find various Visual Studio executables。为了简化此过程,我创建了一个包装函数:

function Run-VsWhere { &("${env:ProgramFiles(x86)}/Microsoft Visual Studio/Installer/vswhere.exe") $args }

function Find-VSWherePath([string[]] $workloads, [string] $pathGlob) {
    Run-VsWhere -products * -prerelease -latest -requires $workloads -requiresAny -find $pathGlob
}

这非常适合单个工作负载,例如对于MSBuild:

Find-VSWherePath "Microsoft.Component.MSBuild" "MSBuild/**/Bin/MSBuild.exe"
> C:\Program Files (x86)\Microsoft Visual Studio\2019\Preview\MSBuild\Current\Bin\MSBuild.exe

...但是对于像VSTest这样的多个项目却分崩离析:

Find-VSWherePath "Microsoft.VisualStudio.Workload.ManagedDesktop","Microsoft.VisualStudio.Workload.Web" "**/TestPlatform/vstest.console.exe"
> (nothing)

如果我将对vswhere的调用替换为a call to echoargs,它将确切地说明出了什么问题。 MSBuild:

> Arg 0 is <-products>
> Arg 1 is <*>
> Arg 2 is <-prerelease>
> Arg 3 is <-latest>
> Arg 4 is <-requires>
> Arg 5 is <Microsoft.Component.MSBuild>
> Arg 6 is <-requiresAny>
> Arg 7 is <-find>
> Arg 8 is <MSBuild/**/Bin/MSBuild.exe>

vs VSTest:

> Arg 0 is <-products>
> Arg 1 is <*>
> Arg 2 is <-prerelease>
> Arg 3 is <-latest>
> Arg 4 is <-requires>
> Arg 5 is <Microsoft.VisualStudio.Workload.ManagedDesktop Microsoft.VisualStudio.Workload.Web>
> Arg 6 is <-requiresAny>
> Arg 7 is <-find>
> Arg 8 is <**/TestPlatform/vstest.console.exe>

问题是$workloads参数作为由空格连接的单个参数传递给Run-VsWhere,而不是每个元素中的一个参数数组-如何强制其通过?我已经尝试了splatting,split,join,单引号,双引号的所有组合...但是似乎没有任何效果。

2 个答案:

答案 0 :(得分:1)

使用自动变量$args传递所提供的参数,这意味着嵌套在$args中的数组参数按原样传递(即仍为数组)。使用splatting@args)展平/展开嵌套数组。

function Run-VsWhere {
    & "${env:ProgramFiles(x86)}/Microsoft Visual Studio/Installer/vswhere.exe" @args
}

答案 1 :(得分:0)

由于指定的工作负载不可用,第二次致电Find-VSWherePath可能没有结果吗?我尝试了下面的代码,它确实起作用。

function Find-VSWherePath([string[]] $workloads, [string] $pathGlob) {
    . "${env:ProgramFiles(x86)}/Microsoft Visual Studio/Installer/vswhere.exe" -products * -prerelease -latest -requires $workloads -requiresAny -find $pathGlob
}

clear

"This works"
Find-VSWherePath "Microsoft.Component.MSBuild" "MSBuild/**/Bin/MSBuild.exe"

"No result"
Find-VSWherePath "Microsoft.VisualStudio.Workload.Web" "MSBuild/**/Bin/MSBuild.exe"

"Try two workloads, the first is not available, but the second is. This also works."
Find-VSWherePath "Microsoft.VisualStudio.Workload.Web","Microsoft.VisualStudio.Component.NuGet" "MSBuild/**/Bin/MSBuild.exe"