Reputation: 29878
I'm trying to call vswhere.exe
to find various Visual Studio executables for CI purposes. In order to simplify this, I've created a wrapper function:
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
}
This works perfectly for single workloads, e.g. for MSBuild:
Find-VSWherePath "Microsoft.Component.MSBuild" "MSBuild/**/Bin/MSBuild.exe"
> C:\Program Files (x86)\Microsoft Visual Studio\2019\Preview\MSBuild\Current\Bin\MSBuild.exe
... but falls apart for multiple ones like VSTest:
Find-VSWherePath "Microsoft.VisualStudio.Workload.ManagedDesktop","Microsoft.VisualStudio.Workload.Web" "**/TestPlatform/vstest.console.exe"
> (nothing)
If I replace the call to vswhere
with a call to echoargs
, it demonstrates exactly what's going wrong. 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>
The issue is that the $workloads
parameter is being passed to Run-VsWhere
as a single parameter joined by a space, instead of one parameter per element in the array - how can I force it to pass as I need? I've tried every combination of splatting, splitting, joining, single-quoting, double-quoting... but nothing seems to work.
Upvotes: 0
Views: 262
Reputation: 200313
Using the automatic variable $args
passes the arguments as they're provided, meaning that an array argument nested in $args
is passed as-is (i.e. remains an array). Use splatting (@args
) to flatten/unroll nested arrays.
function Run-VsWhere {
& "${env:ProgramFiles(x86)}/Microsoft Visual Studio/Installer/vswhere.exe" @args
}
Upvotes: 1
Reputation: 4225
Is it possible your second call to Find-VSWherePath
does not result in anything because the specified workloads are not available? I tried the code below and it does work.
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"
Upvotes: 0