MSBuild: Unable to find the path - msbuild

I am using following script within my build file. I have installed MSBuildExtensionPack on the build server.
<?xml version="1.0" encoding="utf-8"?>
<Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003"
ToolsVersion="4.0"
DefaultTargets="StopIT">
<Import Project=".\thirdparty\tools\MsBuildExtensions"/>
<Target Name="StopIT">
<MSBuild.ExtensionPack.Computer.WindowsService TaskAction="Stop" ServiceName="AppServices" MachineName="MyMachineName"/>
</Target>
</Project>
After running the script, I am getting following error:
The imported project "C:\Program Files (x86)\MSBuild\ExtensionPack\4.0\MSBuild.ExtensionPack.tasks" was not found. Confirm that the path in the declaration is correct, and that the file exists on disk.
If i look into the machine, I can find this file under: "C:\Program Files\MSBuild\ExtensionPack\4.0\MSBuild.ExtensionPack.tasks" location.
How can I inform the build script to look into correct path.

To answer my own question, I installed the 32 bit version which by default get installed at C:\Program Files (x86)\MSBuild\ExtensionPack\4.0 location. I am not sure if there is an explicit way to specify another path.
Thank you

Related

How to ship the stylecop.json and custom.ruleset files with a NuGet package in VS2017

At the moment we are switching from VS2015 to VS2017. One of our upgrade steps is to switch from stylecop to the new Stylecop.Analyzer package. The new Stylecop is using 2 files. The stylecop.json and the Stylecop.ruleset.
The target: I want to provide the stylecop files as a custom nuget package. But I dont know how to create the needed .csproj entries.
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
...
<CodeAnalysisRuleSet>packages\My.StyleCop.1.0.0-pre15\RuleSet\My.StyleCop.ruleset</CodeAnalysisRuleSet>
</PropertyGroup>
...
<ItemGroup>
<AdditionalFiles Include="packages\My.StyleCop.1.0.0-pre15\Config\stylecop.json">
<Link>stylecop.json</Link>
</AdditionalFiles>
</ItemGroup>
</Project>
In the past, there was the possibility to use a install.ps1 script to do this stuff. But with NuGet 3. (or 4.) the install scripts are obsolete and will be ignored.
I already tried to use My.StyleCop.targets:
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<ItemGroup>
<AdditionalFiles Include="packages\My.StyleCop.1.0.0-pre17\Config\stylecop.json">
<Link>stylecop.json</Link>
</AdditionalFiles>
</ItemGroup>
</Project>
But here I have some issues, too. Since NuGet 3. (or 4.) there is no solution wide package folder and I dont know any variable or placeholder I can use here to get a absolute or relative path to my package.
You can add .props or .targets files to the build folder in your packages and they will be imported to the projects.
On the .props file, you can use the MSBuildThisFileDirectory MSBuild variable that represents the folder where that file is located.
Thanks to Paulo.
How I did it:
This is the structure of my NuGet package.
The solution is quiet easy. You need to create to files. A .props and a .targets file named like the NuGet package and place them in the build folder of your package.
In these MSBuild files you can use the $(MSBuildThisFileDirectory) variable to get the path of your NuGet package.
MSBuildThisFileDirectory = C:\Users\UserName\.nuget\packages\sig.stylecop\1.0.0-pre23\build\
My SIG.StyleCop.props file:
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<PropertyGroup>
<CodeAnalysisRuleSet>$(MSBuildThisFileDirectory)\..\RuleSet\SIG.combiLink.ruleset</CodeAnalysisRuleSet>
</PropertyGroup>
</Project>
My SIG.StyleCop.targets file:
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<ItemGroup>
<AdditionalFiles Include="$(MSBuildThisFileDirectory)\..\Config\stylecop.json">
<Link>stylecop.json</Link>
</AdditionalFiles>
</ItemGroup>
</Project>
Cause of the structure of my package i need to navigate (..) into the Config and into the RuleSet folder.
The variable $(MSBuildThisFileDirectory) already includes the backslash at the end. It is important to omit the backslash when you reference the ruleset and the stylecop.json file:
<CodeAnalysisRuleSet>$(MSBuildThisFileDirectory)..\RuleSet\SIG.combiLink.ruleset</CodeAnalysisRuleSet>
<AdditionalFiles Include="$(MSBuildThisFileDirectory)..\Config\stylecop.json">
With the double backslash I experienced two strange problems in Visual Studio 2017:
Unit tests rebuild the code each time I start them, even without any code change
The IDE shows many StyleCop errors in the Error List window and shows red marks in the scroll bar even for rules that are explicitly disabled in the rule set.

Use MSBuild Targets to copy files recursively from NuGet package

I have a .targets file in my NuGet package build folder which is then automatically included in the project that consumes the NuGet package.
I want this .targets file to copy some folders on post-build. The following script shows how that is done, but the output I get is wrong because %(RecursiveDir) starts at the first wild-card which I used for the version number of the package.
My question: How can I specify the version of MyPackage in the .targets file dynamically so that I can remove the first wildcard?
<?xml version="1.0" encoding="utf-8" ?>
<Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<Target Name="AfterBuild">
<ItemGroup>
<!-- MyPackage.* should be replaced by MyPackage.1.0.0.4534. But the version is set by NuGet.exe pack -Version -->
<FilesToCopy Include="$(SolutionDir)packages\MyPackage.*\myfolder\**\*.*"/>
</ItemGroup>
<Copy SourceFiles="#(FilesToCopy)" DestinationFolder="$(SolutionDir)bin\$(Configuration)\myfolder\%(RecursiveDir)"/>
</Target>
</Project>
To avoid having to the package version you could use the MSBuildThisFileDirectory property instead.
The MSBuildThisFileDirectory property gives you the directory where the .targets file is so you can change the <FilesToCopy> element to use a path relative to that directory and you do not have to use the version number.
<FilesToCopy Include="$(MSBuildThisFileDirectory)myfolder\**\*.*"/>

Using MSBuildExtensionPack from a specific location (DLL reference)

I am trying to use MSBuildExtensionPack and read that I have to import the project by using:
$(MSBuildProjectDirectory)..\MSBuild.ExtensionPack.tasks
$(MSBuildProjectDirectory)....\Common\MSBuild.ExtensionPack.tasks
It should not be necessary for you to include the above type of import in your usage of the tasks. If you have used the default installation path, simply use the following imports:
3.5 ---
4.0 ---
I have not installed the extension pack on the build server, rather I have copied the DLL into a specifc location and trying to access it by following code:
After trigerring the build using TeamCity, I get following error:
error MSB4019: The imported project "C:\Apps\Teamcity\buildAgent 1\work\vb82348r312dsd33\thirdparty\tools\MsBuildExtensions" was not found. Confirm that the path in the declaration is correct, and that the file exists on disk.
If I look into the build machine, I can find the folder and all the files in it. Not sure why I am getting this error.
<?xml version="1.0" encoding="utf-8"?>
<Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003"
ToolsVersion="4.0"
DefaultTargets="StopIT">
<Import Project=".\thirdparty\tools\MsBuildExtensions"/>
<Target Name="StopIT">
<MSBuild.ExtensionPack.Computer.WindowsService TaskAction="Stop" ServiceName="AppServices" MachineName="MyMachineName"/>
</Target>
</Project>
Please provide your suggestion
You need to change your import from
<Import Project=".\thirdparty\tools\MsBuildExtensions"/>
to
<Import Project=".\thirdparty\tools\MsBuildExtensions\MSBuild.ExtensionPack.tasks"/>
It is not enough to name the folder, you have to name every file (.proj, .target, .tasks) that should be imported, in your case the MSBuild.ExtensionPack.tasks
The tasks file contains some kind of mapping between task names and the assembly where to find them.

Change working directory of msbuild.exe

I am executing MSBuild from a batch file. The MSBuild script is in a different directory than the directory I want MSBuild to consider the working directory when running the script. When invoking MSBuild.exe, how do I change its working directory?
Edit: More details
Let's say I have an MSBuild script located on some other server. I want to run a command thusly:
msbuild.exe \\my_server\c$\My\Path\To\Scripts\TestScript.msbuild
I run that command with my command prompt at c:\temp. Let's say my TestScript.msbuild has a task to create a file. The file has no path just a filename. I would expect that the file gets created inside c:\temp. But it doesn't it gets created next to the msbuild file that is sitting on the server. This is the behavior I want to change.
Edit #2
Here is the script I'm using in my test:
<Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<ItemGroup>
<Files Include="HelloWorld.txt" />
</ItemGroup>
<Target Name="TouchFiles">
<Touch Files="#(Files)" AlwaysCreate="True" />
</Target>
</Project>
I am going into a command shell CDing into c:\temp and then executing the script. With or without the /p:OutDir switch that #Nick Nieslanik mentions, the HelloWorld.txt file appears in the folder where the *.msbuild file is and not c:\temp.
I ran across this while looking for a solution to my problem. Here's my solution (build script):
<?xml version="1.0" encoding="utf-8"?>
<Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<Target Name="Default">
<Exec Command="build.bat" WorkingDirectory="..\[your dir]\" />
</Target>
</Project>
I believe that's more what you were originally looking for?
My problem was that my batch file called another that it expected to be in the same directory, but since my ms build script was being run elsewhere, the batch file failed to find the second batch file.
#jkohlhepp - I see now. You are doing the opposite of what I described in my comment to some degree.
MSBuild common targets use the MSBuildProjectDirectory to determine the output folder unless you override that. So in your case, you could run
msbuild.exe \\my_server\c$\My\Pat\To\Scripts\TestScript.msbuild /p:OutDir=c:\temp
to force the output to be dropped in that location.
EDIT:
Given the project file above, you'd need to edit it to do something like the following for this to work:
<Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<PropertyGroup>
<OutDir Condition=" '$(OutDir)' == '' ">bin\debug\</OutDir>
</PropertyGroup>
<ItemGroup>
<!-- Without prefacing files with paths, they are assumed relative to the proj file -->
<FilesToCreate Include="$(OutDir)HelloWorld.txt" />
</ItemGroup>
<Target Name="TouchFiles">
<Touch Files="#(FilesToCreate)" AlwaysCreate="True" />
</Target>
</Project>
In current versions of MSBuild the well-known property MSBuildStartupDirectory can be used in the msbuild file to retrieve the absolute path of the folder where MSBuild is called.
https://learn.microsoft.com/en-us/visualstudio/msbuild/msbuild-reserved-and-well-known-properties?view=vs-2019
This option perhaps did not exist in msbuild around the time when the question was asked. I didn't want to spend too much time investigating it.

Working directory issue when importing msbuild file in another msbuild file

I am trying to specify some additional targets/tasks to an msbuild file by extending an existing msbuild file (a web applicartion .csproj file). The idea is to put configuration specific tasks in this "extended ms build file" and use this file in our build server (TeamCity). The way I tried to solve it at first was to add a folder "msbuildscripts" to my web project and put the extended ms build file there:
<?xml version="1.0" encoding="utf-8" ?>
<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003" DefaultTargets="Build">
<Import Project="../My.Web.csproj" />
...more stuff...
</Project>
and then build this file using something like:
c:\myweb\msbuild.exe msbuildscripts/extended.msbuild.file.xml
Now, this wont work because when importing the original ms build file, that csproj file will be "executed" in the "wrong" folder (msbuildscripts), and the csproj-build-file wont find any of its referenced folders/items.
Is there any way to tell msbuild.exe to use a specific working directory? I know it is possible to solve this problem using an execute task, but that doesnt seem like a good solution.
Use MSBuild task like this:
<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003" DefaultTargets="MyBuild">
<ItemGroup>
<ProjectToBuild Include="../My.Web.csproj" />
</ItemGroup>
<Target Name="MyBuild">
<MSBuild Targets="Build" Projects="#(ProjectToBuild)"></MSBuild>
</Target>
</Project>