MSBuild inline task reference is escaping parenthesis, sometimes - msbuild

I am writing an inline task for MSBuild. It requires a reference to System.ServiceProcess.dll.
The task works great if I hard-code the path to the System.ServiceProcess.dll file, like this:
<UsingTask
TaskName="MyTask"
TaskFactory="CodeTaskFactory"
AssemblyFile="$(MSBuildToolsPath)\Microsoft.Build.Tasks.v4.0.dll">
<Task>
<Reference Include="C:\Program Files (x86)\Reference Assemblies\Microsoft\Framework\.NETFramework\v4.5\System.ServiceProcess.dll" />
<Code Type="Fragment" Language="cs">...working fine...</Code>
</Task>
</UsingTask>
However, I would rather not hard-code that path.
If I just use <Reference Include="System.ServiceProcess.dll" />, I get an error: MSB3755: Could not find reference "System.ServiceProcess.dll", so I think I have to use the full path here.
The $(FrameworkPathOverride) property contains the correct path already, so I tried to use that:
<Reference Include="$(FrameworkPathOverride)\System.ServiceProcess.dll" />
But that gives me an error:
C:\path\to\project.csproj(93,3): error MSB3754: The reference assembly "C:\Program Files %28x86%29\Reference Assemblies\Microsoft\Framework\.NETFramework\v4.5\System.ServiceProcess.dll" is invalid. "The given assembly name or codebase was invalid. (Exception from HRESULT: 0x80131047)"[C:\path\to\project.csproj]
Notice how it escaped (x86) into %28x86%29.
Notably, it seems to do this only for $(FrameworkPathOverride). If I define my own property and use it instead, it works just fine, unless that property also references $(FrameworkPathOverride). In other words, this works (but still has me hard-coding the path):
<PropertyGroup>
<MyPath>C:\Program Files (x86)\Reference Assemblies\Microsoft\Framework\.NETFramework\v4.5</MyPath>
</PropertyGroup>
// (later, inside <Task />)
<References Include="$(MyPath)\System.ServiceProcess.dll" />
However, this fails with the same error that reports searching a path for %28x86%29:
<PropertyGroup>
<MyPath>$(FrameworkPathOverride)</MyPath>
</PropertyGroup>
Just for kicks, I also tried this variation, which also fails with the same error:
<PropertyGroup>
<MyPath>$([System.Convert]::ToString("$(FrameworkPathOverride)"))</MyPath>
</PropertyGroup>
Also, in all cases, the output of <Message Text="$(FrameworkPathOverride)" /> and <Message Test="$(MyPath)" /> are identical. The <Message /> task is not escaping the parenthesis inside $(FrameworkPathOverride), but the <Reference Include="..." /> is. Hmm.
Why does (x86) become %28x86%29 inside <Reference /> but not inside <Message />?
Why does it happen for $(FrameworkPathOverride) and not for $(MyPath)?
Why does it start happening to $(MyPath) if it references $(FrameworkPathOverride)?
How can I avoid hard-coding this path?

Similar to your last attempt, have you tried the following using the "Unescape" MSBuild Property Function?
<PropertyGroup>
<MyPath>$([MSBuild]::Unescape("$(FrameworkPathOverride)"))</MyPath>
</PropertyGroup>
It seems to be a known issue titled "MSBuild 4.0 UsingTask cannot have a path with parentheses": http://connect.microsoft.com/VisualStudio/feedback/details/532677/msbuild-4-0-usingtask-cannot-have-a-path-with-parentheses
Unfortunately, I have not had the opportunity to test this.

Related

How to include a local DLL reference in to a nuget package when calling msbuild pack?

We have several projects that need to include a few static DLL. Therefore the project files include code like this:
<ItemGroup>
<Reference Include="..\_Solutions\dependencies\abc123.dll" />
<Reference Include="..\_Solutions\dependencies\def456.dll" />
<Reference Include="System.Web" />
</ItemGroup>
Expected:
We expected that the two dlls; abc123.dll and def456.dll would befound in the nupkg file.
Actual:
However, the nupkg doesn't include the abc123.dll nor the def456.dll files.
One can always include custom content in the nuget-package. Like this:
<ItemGroup>
<Content Include="$(OutputPath)\ReferencedLib.dll">
<Pack>true</Pack>
<PackagePath>lib\$(TargetFramework)</PackagePath>
</Content>
</ItemGroup>
If you target multiple frameworks:
<PropertyGroup>
<TargetFrameworks>netstandard2.0;netstandard1.6</TargetFrameworks>
<TargetsForTfmSpecificContentInPackage>$(TargetsForTfmSpecificContentInPackage);IncludeReferencedProjectInPackage</TargetsForTfmSpecificContentInPackage>
</PropertyGroup>
<Target Name="IncludeReferencedProjectInPackage" Condition="'$(IncludeBuildOutput)' != 'false'">
<ItemGroup>
<TfmSpecificPackageFile Include="$(OutputPath)\ReferencedLib.dll" PackagePath="lib/$(TargetFramework)" />
</ItemGroup>
</Target>
How to include a local DLL reference in to a nuget package when calling msbuild pack?
According the issue on the GitHub, this is currently not directly supported by NuGet.
The workaround I suggest is using the .nuspec file:
NuGet allows you to disable the automatic generation of the resulting
.nuspec file and automatic collection of files by setting the
property in your project, along with a
property that allows you to pass replacement tokens for parsing the
.nuspec file.
See Martin`s answer for details.

AjaxMin task has been declared or used incorrectly, or failed during construction

I'm trying to add Microsoft's AjaxMin to VS2012 project and I'm not really sure what I'm doing. I think I'm missing something obvious.
I copied the code from the tutorial here (http://ajaxmin.codeplex.com/wikipage?title=AjaxMinTask)
And I've tried adding the reference to my project so my code looks like this:
<UsingTask TaskName="AjaxMin" AssemblyFile="$(MSBuildProjectDirectory)\Build\AjaxMinTask.dll" />
<Target Name="AfterBuild" >
<ItemGroup>
<JS Include="**\*.js" Exclude="**\*.min.js;Scripts\*.js" />
</ItemGroup>
<ItemGroup>
<CSS Include="**\*.css" Exclude="**\*.min.css" />
</ItemGroup>
<AjaxMin JsSourceFiles="#(JS)" JsSourceExtensionPattern="\.js$" JsTargetExtension=".min.js" CssSourceFiles="#(CSS)" CssSourceExtensionPattern="\.css$" CssTargetExtension=".min.css" />
</Target>
This is at the bottom of my .csproj file where there was already a commented out AfterBuild section. I get errors saying JS, CSS, AjaxMin are invalid child elements. When I try to build the project I get an error, I'm not sure what I am missing. I created a folder in the project called Build and added the AjaxMinTask.dll. I don't know if there's any additional thing i need to do to make sure it is referenced properly.
I've also tried using the Import node instead of the UsingTask
<Import Project="$(MSBuildExtensionsPath)\Microsoft\MicrosoftAjax\AjaxMin.tasks" />
And I think AjaxMin is installed correctly because I can run it from command line.
In your .csproj, the end of the document (I've included the last closing element ) should look something like this:
<Import Project="$(MSBuildExtensionsPath32)\Microsoft\MicrosoftAjax\AjaxMin.tasks" />
<Target Name="AfterBuild" AfterTargets="CopyAllFilesToSingleFolderForPackage" Condition="'$(Configuration)'=='Release'">
<ItemGroup>
<JS Include="scripts\*.js" Exclude="scripts\*.min.js;" />
</ItemGroup>
<ItemGroup>
<CSS Include="css\main.css" />
</ItemGroup>
<AjaxMin Switches="-global:jQuery,$" JsSourceFiles="#(JS)" JsCombinedFileName="scripts\combined.min.js" CssSourceFiles="#(CSS)" CssSourceExtensionPattern="\.css$" CssTargetExtension=".min.css" />
</Target>
</Project>
As I am using Windows 7 64-bit, you will see the path of Import... includes (MSBuildExtensionsPath32). If you are using Windows 32-bit, then you do not need the 32 at the end. Other then that, your code should work.
Disregard the JS, CSS, AjaxMin childelements error. But you should not get a built error. If you could post your built error, it would be useful.
Also, the code above combines multiple JS files, just added for fun.

msbuild exec task call msbuild

I need to call exec and build a wix setup project.
Currently I have the following in my TFSbuild.proj
<PropertyGroup>
<WebRoot>$(DropLocation)\Latest\x86\Release\_PublishedWebsites\Web</WebRoot>
<DBRoot>$(DropLocation)\Latest\x86\Release\Database</DBRoot>
</PropertyGroup>
<PropertyGroup>
<Msbuildexe>"msbuild"</Msbuildexe>
<Configuration>"/p:Configuration:"Release""</Configuration>
<DefineConstants>" /p:DefineConstants:"WebRoot=$(WebRoot);DBRoot=$(DBRoot)""</DefineConstants>
<WixSolution>"$(MSBuildProjectDirectory)\Setup\Setup.sln"</WixSolution>
</PropertyGroup>
<Message Text="Bulding setup solution" />
<Message Text="$(Msbuildexe) $(Configuration) $(DefineConstants) $(WixSolution)" />
<Exec Command="$(Msbuildexe) $(Configuration) $(DefineConstants) $(WixSolution)" />
I've tried to simply as much as possible so I don't get confused where the " are meant to be. When I run this the debug message (2nd last command) outputs
"msbuild"
"/p:Configuration:"Release"" "
/p:DefineConstants:"WebRoot=\server\drops\app\Installer Build\Latest\x86\Release_PublishedWebsites\Web;DBRoot=\server\drops\app\Installer Build\Latest\x86\Release\Database""
"f:\builds\app\Installer Build\BuildType\Setup\Setup.sln"
And I get the following error in the log
'"msbuild"' is not recognized as an
internal or external command,
operable program or batch file.
f:\builds\app\Installer
Build\BuildType\TFSBuild.proj(538,5):
error MSB3073: The command ""msbuild"
"/p:Configuration:"Release"" "
/p:DefineConstants:"WebRoot=\server\drops\app\Installer Build\Latest\x86\Release_PublishedWebsites\Web;DBRoot=\server\drops\app\Installer Build\Latest\x86\Release\Database""
"f:\builds\app\Installer
Build\BuildType\Setup\Setup.sln""
exited with code 9009.
I'm not sure if this is being caused by not being able to call the msbuild command from the command line or a " issue. If it is because I can't call msbuild from the command line like this how would I go about referencing it, is there a property that points to it?
To start with, you don't need most of the quotes, especially if the paths you are using don't contain spaces, but I'd trim it down to this, allowing for spaces in the paths for $(WebRoot), $(DbRoot) and $(MSBuildProjectDirectory):
<PropertyGroup>
<WebRoot>$(DropLocation)\Latest\x86\Release\_PublishedWebsites\Web</WebRoot>
<DBRoot>$(DropLocation)\Latest\x86\Release\Database</DBRoot>
</PropertyGroup>
<PropertyGroup>
<MsbuildExe>{still-needs-a-path-to}\msbuild</MsbuildExe>
<Configuration>/p:Configuration:Release</Configuration>
<DefineConstants>/p:DefineConstants:"WebRoot=$(WebRoot);DBRoot=$(DBRoot)"</DefineConstants>
<WixSolution>"$(MSBuildProjectDirectory)\Setup\Setup.sln"</WixSolution>
</PropertyGroup>
<Message
Text="Bulding setup solution"
/>
<Message
Text="$(MsbuildExe) $(Configuration) $(DefineConstants) $(WixSolution)"
/>
<Exec
Command="$(MsbuildExe) $(Configuration) $(DefineConstants) $(WixSolution)"
/>
However, you still won't be able to execute MSBuild with this, since the path to MSBuild isn't specified. It is typically found in the $(WINDIR)\Framework\Microsoft.Net\v4.0.30319 folder. There are a few ways to get this, either encode it directly, rely on an environment variable (that has to be set up somehow), use the predefined $(MSBuildBinPath), or extract it from the registry using the MSBuild registry syntax, which would look like this:
$(Registry:HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\MSBuild\ToolsVersions\4.0\MSBuildToolsPath)
However, it isn't clear why you are running MSBuild using Exec rather than just using the MSBuild task. Change the line with Exec to this:
<MSBuild
Project="$(WixSolution)"
Properties="$(DefineConstants)"
/>
removing your declaration for <Configuration> and changing <DefineConstants> to this:
<DefineConstants>Configuration=$(Configuration);WebRoot=$(WebRoot);DBRoot=$(DBRoot)</DefineConstants>
Following up on my comment I'd suggest you try using the MSBuild Task instead of Exec:
<?xml version="1.0" encoding="utf-8"?>
<Project DefaultTargets="BuildWiXSolution">
<!-- Include the custom build targets installed with WiX -->
<Import Project="$(MSBuildExtensionsPath)\Wix\Wix.targets"/>
<PropertyGroup>
<WebRoot>$(DropLocation)\Latest\x86\Release\_PublishedWebsites\Web</WebRoot>
<DBRoot>$(DropLocation)\Latest\x86\Release\Database</DBRoot>
</PropertyGroup>
<ItemGroup>
<WiXSolution Include="$(MSBuildProjectDirectory)\Setup\Setup.sln">
<Properties>Configuration=Release</Properties>
<AdditionalProperties>WebRoot=$(WebRoot);DBRoot=$(DBRoot)</AdditionalProperties>
</WiXSolution>
</ItemGroup>
<Target Name="BuildWiXSolution">
<MSBuild Projects="#(WiXSolution)" />
</Target>
</Project>
It allows you to keep configuration properties and additional properties together with your Wix solution.

MSBuild transform not evaluating wildcards

I am having some trouble with a MSBuild file that I am trying to compile some custom libraries.
<PropertyGroup>
<FullVersion>10.8.0.0</FullVersion>
</PropertyGroup>
<ItemGroup>
<LibsToBuild Include=".\Lib1">
<Bin>bin\*.*</Bin>
<Project>Library 1</Project>
<Build>ReleaseNoProtect</Build>
<Version>CurrentVersion</Version>
</LibsToBuild>
<LibsToBuild Include=".\Lib2">
<Bin>bin\*.*</Bin>
<Project>Library 2</Project>
<Build>ReleaseLibrary</Build>
<Version>CurrentVersion</Version>
</LibsToBuild>
</ItemGroup>
<ItemGroup>
<LibsToCopy Include="#(LibsToBuild->'%(FullPath)\%(Version)\%(Bin)')" />
</ItemGroup>
<Target Name="BuildLibs">
<MSBuild
Projects="#(LibsToBuild->'%(FullPath)\%(Version)\Build\Build.proj')"
Targets="%(LibsToBuild.Build)"
Properties="Configuration=Release;APP_VERSION=$(FullVersion);PROJECT_NAME=%(LibsToBuild.Project)"
/>
<Copy
SourceFiles="#(LibsToCopy)"
DestinationFiles="#(LibsToCopy->'.\Libraries\CurrentVersion\%(RecursiveDir)%(Filename)%(Extension)')"
/>
<!--
<Exec Command='xcopy /y #(LibsToCopy) .\Libraries\CurrentVersion' />
-->
</Target>
When I run this through MSBuild, all of the compiles work, but the copy files does not. MSBuild complains with the following errors:
Copying file from "X:\Projects\Lib1\Master\bin\*.*" to ".\Libraries\CurrentVersion\*.*".
X:\Projects\Test Release.build(35,3): error MSB3021: Unable to copy file "X:\Projects\Lib1\Master\bin\*.*" to ".\Libraries\CurrentVersion\*.*". Illegal characters in path.
Copying file from "X:\Projects\Lib2\Master\bin\*.*" to ".\Libraries\CurrentVersion\*.*".
X:\Projects\Test Release.build(35,3): error MSB3021: Unable to copy file "X:\Projects\Lib1\Master\bin\*.*" to ".\Libraries\CurrentVersion\*.*". Illegal characters in path.
I am unable to figure out why the transform in the "LibsToCopy" ItemGroup isn't expanding the filename wildcards.
I have also attempted to use xcopy, but it doesn't like the wildcards either.
Thanks!
Dave
I had a similar problem. Try this, just before the <Copy> task
<CreateItem Include="#(LibsToBuild->'%(FullPath)\%(Version)\%(Bin)')">
<Output TaskParameter="Include" ItemName="LibsToCopy" />
</CreateItem>
Unfortunately the documentation says CreateItem task is deprecated, so I don't know how to solve tis problem in the future.

CSC task in Msbuild aborts with namespace errors

I have attempted the following:
<!-- Specify the inputs by type and file name -->
<ItemGroup>
<CSFile Include = "$(MSBuildProjectDirectory)\..\Mine.cs"/>
</ItemGroup>
<Target Name = "Compile">
<!-- Run the Visual C# compilation using input files of type CSFile -->
<Csc Sources="#(CSFile)" />
<!-- Log the file name of the output file -->
<Message Text="The output file is done"/>
</Target>
This does not work as all the namespaces used in the project throw errors. Does anyone know how I can explicitly get the assemblies to pick up from the solution file, as the paths are ok and if loaded in Visual Studio all is fine. I need to script this and the above is not working. Is there an obvious mishap?
Appreciate the inpuT :-)
I have realised that this is not going to work as the file I have has several external dependancies. Hence I would need to use the devenv.exe. Problem is that I get the follwing:
What I get is that the command exits with Code 1? I want to get the project to build all the dependant dlls that it requires without having to open visual studio.
Any ideas?
Thnxes :-)
try this (add you own dlls references)
<ItemGroup>
<CSFile Include = "$(MSBuildProjectDirectory)\..\Mine.cs"/>
<Reference Include="System.dll"/>
<Reference Include="System.Data.dll"/>
<Reference Include="System.Drawing.dll"/>
<Reference Include="System.Windows.Forms.dll"/>
<Reference Include="System.XML.dll"/>
</ItemGroup>
<Target Name = "Compile">
<!-- Run the Visual C# compilation using input files of type CSFile -->
<Csc Sources="#(CSFile)"
References="#(Reference)"
OutputAssembly="$(builtdir)\$(MSBuildProjectName).exe"
TargetType="exe" />
/>
<!-- Log the file name of the output file -->
<Message Text="The output file is done"/>
</Target>