5

I'm trying to execute msbuild on Azure Devops. Because of that I cannot use the MSBuild task provided.

When I use a Command Line task the command is not recognised. On my local machine I load vcvarsall.bat before I use msbuild. But I've not been unable to work out how to obtain that path in Azure Devops. Doesn't appear to be a Develop Command Prompt task for Azue Devops either.

Any ideas on how I can use msbuild from a Command Line task or Batch Script task? Using their Hosted VS agent.

jessehouwing
  • 106,458
  • 22
  • 256
  • 341
thomthom
  • 2,854
  • 1
  • 23
  • 53

4 Answers4

4

The best way to do this in a supported way is to use vswhere. The following bit of script will install vswhere (using chocolatey) and then query the installer registry where msbuild can be found. Replace -latest with a more specific version if you need that:

choco install vswhere
for /f "tokens=*" %%i in ('vswhere -latest -requires Microsoft.Component.MSBuild -find MSBuild\**\Bin\MSBuild.exe -nologo') do set msbuildpath="%%i"

echo "##vso[task.setvariable variable=msbuildpath]%msbuildpath%"

This will save the path to msbuild to the environment variable %msbuildpath% as well as the pipeline variable (for this stage) $(msbuildpath).

You can then either use a second run commandline task and pass in $(msbuildpath) or you can simply call MsBuild from the same piece of script mentioned above by calling:

%msbuildpath%

This will make sure your script will remain working, even if Microsoft upgrades their images and moves some things around (which does happen).

You can also get vswhere using wget or invoke-webrequest -outfile from the following location:

https://github.com/Microsoft/vswhere/releases/latest/download/vswhere.exe

Other samples for vswhere syntax can be found on the project wiki, including the syntax for PowerShell.

jessehouwing
  • 106,458
  • 22
  • 256
  • 341
3

If you use Hosted Agent 2017 you can run the msbuild.exe from the Command Line task in this way:

Command Line version 1: enter image description here

Command Line version 2:

enter image description here

Results:

enter image description here

Shayki Abramczyk
  • 36,824
  • 16
  • 89
  • 114
  • It has to be Version 1 of the Command Line task? I'm using v2 because I need to apply some conditional logic before I invoke msbuild. Also is that path documented? Or is that an implementation detail that might change? – thomthom Mar 04 '19 at 17:51
  • @Matt - that's interesting. I was looking for variables, but I'd not found any. I might try that. I also found some clues when inspecting a Build with the system.debug flag on. There's a utility the MSBuild task uses to find and determine the MSBuild version to use. – thomthom Mar 08 '19 at 10:41
1

If you are interested in seeing how the built-in Microsoft task resolves the path, all the Azure Devops tasks are provided open-source. These are the path functions you probably care to review.

Matt
  • 3,658
  • 3
  • 14
  • 27
-1

Here is the solution I came up with using only built-in pipeline tasks which makes the MSBuild bin directory available on the path environment variable.

Create a PowerShell task to generate an MSBuild project to capture and output to a file the variables you are interested in (ex. MSBuildBinPath)

PowerShell script

"<Project DefaultTargets=`"DetectMsBuild`">
    <ItemGroup>        
        <OutFile Include=`"`$(MsBuildDetectionFile)`" />
        <OutFile Condition=`"'`$(OutFile)' == ''`" Include=`"msbuildInfo.json`" />
    </ItemGroup>

    <Target Name=`"DetectMsBuild`">
        <PropertyGroup>
            <MsBuildPaths>
[{
    `"Name`": `"BinPath`",
    `"Value`": `"`$(MSBuildBinPath.Replace('\', '\\'))`"
}]
            </MsBuildPaths>
        </PropertyGroup>

        <WriteLinesToFile
            File=`"@(Outfile)`"
            Lines=`"`$(MsBuildPaths)`"
            Overwrite=`"true`"
            Encoding=`"UTF-8`" />
    </Target>
</Project>" | Out-File -FilePath "msbuilddetect.proj" -Encoding utf8

Set the working directory and any variables accordingly.

PowerShell task settings screenshot:

PowerShell task settings screenshot

Create an MSBuild task to run the project file generated by the previous task. Ensure the MSBuild version is set to the version you want to use.

MSBuild task settings screenshot:

MSBuild task settings screenshot

Last, create another PowerShell task that will parse the outputted JSON file of the extracted variables and sets environment variables accordingly.

PowerShell script

Write-Host "Current path: $($env.Path)`n`n"

$msBuildVariables = Get-Content -Path msbuildInfo.json | ConvertFrom-Json

$Path = "$($msBuildVariables[0].Value);$($env:Path)"
Write-Host "##vso[task.setvariable variable=Path;]$Path"

PowerShell task settings screenshot:

PowerShell task settings screenshot

Here is a screenshot of the task order in the build pipeline.

Pipeline task order screenshot

Hasta Dhana
  • 4,699
  • 7
  • 17
  • 26