0

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.

5
  • function Run-VsWhere { "..." $args } should throw an error when trying to define the function. Did you omit the call operator? Commented Apr 29, 2019 at 12:19
  • @AnsgarWiechers You are correct, I've fixed the code. Commented Apr 29, 2019 at 12:34
  • Try echoing "${env:ProgramFiles(x86)}/..." $args instead of invoking the program. Does it show the commandline you expect? Do you get a result when running that commandine manually? Commented Apr 29, 2019 at 12:42
  • 1
    Try @args instead of $args. That should unroll the array. Commented Apr 29, 2019 at 18:05
  • Bloody beautiful @AnsgarWiechers! Please post that as an answer so I can give you the richly-deserved credit! Commented Apr 30, 2019 at 7:46

2 Answers 2

1

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
}
Sign up to request clarification or add additional context in comments.

Comments

0

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"

1 Comment

Sorry for wasting your time, I made a typo in the question, please see the update.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.