Execute csproj file with argument - msbuild

I need to execute 1 csproj from my solution use MsBuild with command line argument.
I created the file with MsBuild run command:
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="14.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2002">
<PropertyGroup>
<Version>1.2.0</Version>
</PropertyGroup>
<Target Name="Build" >
<MSBuild Projects="$(ProjectFolder)\Proj1.csproj" Properties="Configuration=Release" />
</Target>
</Project>
And I added into proj1.csproj file the following attribute:
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="14.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2002">
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
<PlatformTarget>AnyCPU</PlatformTarget>
<OutputPath>bin\Release\</OutputPath>
<StartArguments>TestArg1</StartArguments>
</PropertyGroup>
</Project>
And exeute the build. But in my app I can't see the argument
class Program
{
static void Main(string[] args)
{
Console.WriteLine($#"Test - {args[0]} - end");
}
}
In Console I see the:
"Test - - end"
What I do wrong?

Related

Setting OutputName from wxi MSBUILD -Customizing Target Order

I'm trying to set the <OutputName> of my .msi when using Wix in VisualStudio.
I have seen the other questions related to this, but I am approaching it a bit differently. Hoping you can all clear up some things for me.
This is my .wixproj
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="4.0" DefaultTargets="Build" InitialTargets="EnsureWixToolsetInstalled" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<PropertyGroup>
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
<Platform Condition=" '$(Platform)' == '' ">x86</Platform>
<ProjectGuid>fa14</ProjectGuid>
<SchemaVersion>2.0</SchemaVersion>
<OutputName>Installer_x64_v$(Version)</OutputName>
<OutputType>Package</OutputType>
<!--<ProjectGuid>{fa1414f5-97eb-4d39-8ff6-190cd92ca99f}</ProjectGuid>-->
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|x86' ">
<OutputPath>bin\$(Configuration)\</OutputPath>
<IntermediateOutputPath>obj\$(Configuration)\</IntermediateOutputPath>
<DefineConstants>Debug</DefineConstants>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|x86' ">
<OutputPath>bin\$(Configuration)\</OutputPath>
<IntermediateOutputPath>obj\$(Configuration)\</IntermediateOutputPath>
<WixVariables>
</WixVariables>
</PropertyGroup>
<ItemGroup>
<Compile Include="Product.wxs" />
<Compile Include="Files.wxs" />
<Compile Include="UI.wxs" />
</ItemGroup>
<ItemGroup>
<WixExtension Include="WixUIExtension">
<HintPath>$(WixExtDir)\WixUIExtension.dll</HintPath>
<Name>WixUIExtension</Name>
</WixExtension>
</ItemGroup>
<Import Project="$(WixTargetsPath)" Condition=" '$(WixTargetsPath)' != '' " />
<Import Project="$(MSBuildExtensionsPath32)\Microsoft\WiX\v3.x\Wix.targets" Condition=" '$(WixTargetsPath)' == '' AND Exists('$(MSBuildExtensionsPath32)\Microsoft\WiX\v3.x\Wix.targets') " />
<Target Name="EnsureWixToolsetInstalled" Condition=" '$(WixTargetsImported)' != 'true' ">
<Error Text="The WiX Toolset v3.11 (or newer) build tools must be installed to build this project. To download the WiX Toolset, see http://wixtoolset.org/releases/" />
</Target>
<!--
To modify your build process, add your task inside one of the targets below and uncomment it.
Other similar extension points exist, see Wix.targets.
<Target Name="BeforeBuild">
</Target>
<Target Name="AfterBuild">
</Target>
-->
<PropertyGroup>
</PropertyGroup>
<Target Name="BeforeBuild">
<ReadLinesFromFile File="Configuration.wxi" >
<Output TaskParameter="Lines" PropertyName="FileContents"/>
</ReadLinesFromFile>
<PropertyGroup>
<!-- Find occurence of string ProductVersion, return everything after 'Productversion', trimming spaces and " -->
<TrimmedWXI>$(FileContents.Substring($(FileContents.IndexOf(ProductVersion))).Replace(" ","").Replace('"',""))</TrimmedWXI>
<!-- Find the equals sign, add 1-->
<VersionStart>$([MSBuild]::Add($(TrimmedWXI.IndexOf(=)),1))</VersionStart>
<!-- Find the ?-->
<VersionEnd>$(TrimmedWXI.IndexOf(?))</VersionEnd>
<!-- Find the length of the version-->
<VersionLength>$([MSBuild]::Subtract($(VersionEnd),$(VersionStart)))</VersionLength>
<!-- Find the version-->
<Version>$(TrimmedWXI.Substring($(VersionStart),$(VersionLength)))</Version>
</PropertyGroup>
<Message Importance="High" Text=" Attempting build for $(Version)" />
</Target>
<Target Name="AfterBuild">
<Message Importance="High" Text="BuildDone" />
</Target>
</Project>
And the configuration.wxi
<?xml version="1.0" encoding="utf-8"?>
<Include>
<!-- Setup Configuration -->
<?define ProductName = "Acme" ?>
<?define ProductManufacturer = "AcmeInc." ?>
<?define ProductVersion = "9.99" ?>
<?define ProductUpgradeCode = "FAKEGUID" ?>
</Include>
Now, I am setting the <Version> property appropriately, it parses the file string properly and spits it out in the message, but when it comes to the building of the .msi, it is still blank. Looks like Version gets set after the OutputName is set, and I cant overwrite or make Version set before the OutputName.
I've done some reading and messed around with the Target and build order, but I can't quite get anything to work.
It seems like the OutputName is required to be set before everything else?
Why doesn't this get overridden in the BeforeBuild target?
Is it possible to have this ReadLinesFromFile task happen before the OutputName is set?
Thanks!

MSBuild overwrite properties value with Import

I have a msbuild script which contains only PropertyGroup: DefaultVariables.msbuild
<Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<!-- default values if nothing is set in Main.proj -->
<PropertyGroup>
<ProjectName Condition="'$(PublishService)'==''">DefaultService</ProjectName>
</PropertyGroup>
</Project>
The PublishService can be changed depend on environment.
I also have a Variables.msbuild with is same with above script, except the service name:
<Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<!-- default values if nothing is set in Main.proj -->
<PropertyGroup>
<ProjectName Condition="'$(PublishService)'==''">ErpService</ProjectName>
</PropertyGroup>
</Project
My main build script: BuildMsi.msbuild import the DefaultVariables.msbuild and has a target CreateEnvironmentSpecificInstaller which calls to Msi.msbuild
<Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003" DefaultTargets="CreateInstaller">
<PropertyGroup>
<BaseDir Condition="$(BaseDir)==''">$(MSBuildProjectDirectory)</BaseDir>
</PropertyGroup>
<Import Project="DefaultVariables.msbuild" />
<!-- Something else -->
<Target Name="CreateEnvironmentSpecificInstaller" DependsOnTargets="$(SpecificBuildSteps)">
<MSBuild Projects="$(RedistDir)\Framework\Msi.msbuild" Targets="CreateBatchScripts" StopOnFirstFailure="true" Properties="Configuration=$(Configuration)" RebaseOutputs="true" />
</Target>
<Target Name="CreateInstaller" DependsOnTargets="PrintVersion;$(GenericBuildSteps)">
<MSBuild Condition=" '$(EnvironmentName)' == '**AllEnvironments**' " Projects="$(BaseDir)\$(BtsDeploymentFrameworkDir)\BuildMsi.msbuild" Targets="CreateEnvironmentSpecificInstaller" StopOnFirstFailure="true"
Properties="Configuration=$(Configuration);" RebaseOutputs="true" />
<CallTarget Targets="RemoveGeneratedEnvironmentSettings" />
</Target>
</Project>
In Msi.msbuild script I add an Import to Variables.msbuild script, but the PublishService after this is still the DefaultService:
<Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003" DefaultTargets="CreateInstaller">
<Import Project="Variables.msbuild" />
<Target Name="CreateBatchScripts">
<Message Text="PublishService = $(PublishService)" />
</Target>
</Project>
How can I overwrite this property value in runtime?
First of all, you are never giving a value to PublishService. I assume in DefaultVariables.msbuild what you wanted to do is
<Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<!-- default values if nothing is set in Main.proj -->
<PropertyGroup>
<PublishService> Condition="'$(PublishService)'==''">DefaultService</PublishService>
</PropertyGroup>
</Project>
Then, I suggest you also rename the property in Variables.msbuild and remove the condition Condition="'$(PublishService)'==''. As you have given the property a default value in DefaultVariables.msbuild, the condition will not be fulfilled and thus the value will not be changed.
<Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<PropertyGroup>
<PublishService>ErpService</PublishService>
</PropertyGroup>
</Project>

WiX wxl file doesn't replace ProductTitleVersion

here's my .wixproj:
<?xml version="1.0" encoding="utf-8"?>
<Project DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003" ToolsVersion="4.0">
<PropertyGroup>
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
...
<MSIProductTitleVersion Condition="'$(MSIProductTitleVersion)' == ''">1.1.1.1 (Staging)</MSIProductTitleVersion>
...
<PropertyGroup Condition=" '$(Configuration)' == 'Debug' ">
<OutputPath>bin\Debug\</OutputPath>
<IntermediateOutputPath>obj\Debug\</IntermediateOutputPath>
<DefineConstants>
Debug;CabName=$(MSICabName);ProductTitleVersion=$(MSIProductTitleVersion);ProductVersion=$(MSIProductVersion);Manufacturer=$(MSIManufacturer);ProductCode=$(MSIProductCode);UpgradeCode=$(MSIUpgradeCode);PackageCode=$(MSIPackageCode);
</DefineConstants>
</PropertyGroup>
wxl:
<?xml version="1.0" encoding="utf-8"?>
<WixLocalization Culture="en-us" xmlns="http://schemas.microsoft.com/wix/2006/localization">
<String Id="WelcomeDlgDescription">The Setup Wizard will install [ProductTitleVersion] on your computer. Click Next to continue or Cancel to exit the Setup Wizard.</String>
The end result is just a blank space in the installer dialog header.
Using ProductVersion works as expected.
OK so, this was it; in my .wxs file, I needed:
<Property Id="ProductTitleVersion">$(var.ProductTitleVersion)</Property>
</Product>
</Wix>
I guess the .wxs then makes the .wixproj values available in the .wxl processing.

How to re-run property evaluation in MSBuild target?

I have a custom MSBuild target, partial snippet as follows ..
<Target Name="PublishHtm">
<PropertyGroup>
<PublishHtmTemplateContents>$([System.IO.File]::ReadAllText($(PublishHtmTemplatePath)))</PublishHtmTemplateContents>
<PublishHtm>$(PublishHtmTemplateContents)</PublishHtm>
</PropertyGroup>
<WriteLinesToFile Lines="$(PublishHtm)" File="$(PublishDir)\publish.htm" Overwrite="true"/>
</Target>
This is a rework attempt for this solution in that I'm trying to isolate this template to an external file. The template contains MSBuild property references such as $(ApplicationName). When doing this exactly as described in the linked solution, it works fine, but when loading the template in as a string, none of these property expressions are evaluated by the time it gets to the file.
<SPAN CLASS="BannerTextApplication">$(ApplicationName)</SPAN>
Is there an MSBuild expression/function I can use to get the string to be reevaluated given the context that the Target is being invoked?
BTW I'd rather not work around the problem using find/replace or regex replace, and stick with the MSBuild expression engine.
Using Visual Studio 2012 & .NET Framework 4.5.
Sorry for not getting back to this question for awhile.
Initially I thought that to solve this problem we'll need to bend MSBuild in very unusual way (plan for today was to write complex inline task which will do regex-replace in external file using Msbuild properties as tokens ). But I think this can be solved easier, using CDATA section, which is valid inside property definition:
Here is main script:
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003" DefaultTargets="Build">
<PropertyGroup>
<MyOtherProperty>$([System.DateTime]::Now)</MyOtherProperty>
<Version>1.0.1b</Version>
<ProjectName>MSBuild Rox</ProjectName>
<Author>Alexey Shcherbak</Author>
</PropertyGroup>
<Target Name="Build">
<ItemGroup>
<PropsToPass Include="MyOtherProperty=$(MyOtherProperty)" />
<PropsToPass Include="Version=$(Version)" />
<PropsToPass Include="ProjectName=$(ProjectName)" />
<PropsToPass Include="Author=$(Author)" />
</ItemGroup>
<MSBuild Projects="TransformHTML.Template.proj" Properties="#(PropsToPass)" />
</Target>
</Project>
And here is your template. It's not pure html, it's still msbuild file, but at least without ugly encoding for html tags in xml. It's just a block in CDATA
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003" DefaultTargets="Transform">
<PropertyGroup>
<HtmlProperty><![CDATA[
<body>
<div>$(MyOtherProperty)</div>
<div>$(Version)</div>
<div>$(ProjectName)</div>
<div>$(Author)</div>
</body>
]]></HtmlProperty>
</PropertyGroup>
<Target Name="Transform">
<Message Text="HtmlProperty: $(HtmlProperty)" Importance="High" />
</Target>
</Project>
Maybe it's not very elegant ( I personally don't like the section with #PropsToPass) but it'll do the job. You can put everything inline into single file and then you don't need to pass properties to MSBuild task. I don't like massive html-encoding from proposed "this solution" but I'd rather prefer to keep HTML template in the same script where it'll be transformed, just in nice html format, without encoding.
Single file example:
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003" DefaultTargets="Build">
<PropertyGroup>
<MyOtherProperty>$([System.DateTime]::Now)</MyOtherProperty>
<Version>1.0.1b</Version>
<ProjectName>MSBuild Rox</ProjectName>
<Author>Alexey Shcherbak</Author>
</PropertyGroup>
<Target Name="Build">
<PropertyGroup>
<HtmlProperty><![CDATA[
<body>
<div>$(MyOtherProperty)</div>
<div>$(Version)</div>
<div>$(ProjectName)</div>
<div>$(Author)</div>
</body>
]]></HtmlProperty>
</PropertyGroup>
<Message Text="HtmlProperty: $(HtmlProperty)" Importance="High" />
</Target>
</Project>
You can also download these files here
You can do it using Eval task
<Target Name="PublishHtm">
<PropertyGroup>
<PublishHtmTemplateContents>$([System.IO.File]::ReadAllText($(PublishHtmTemplatePath)))</PublishHtmTemplateContents>
<Eval Values="$(PublishHtmTemplateContents)">
<Output TaskParameter="Result" ItemName="EvalItemTemp"/>
</Eval>
<PublishHtm>%(EvalItemTemp.Identity)</PublishHtm>
</PropertyGroup>
<WriteLinesToFile Lines="$(PublishHtm)" File="$(PublishDir)\publish.htm" Overwrite="true"/>
</Target>
Actually the task does nothing except returning exactly the same value it received, however when you pass the returned value %(EvalItemTemp.Identity) to anywhere, msbuild does evaluation!
Eval task source:
<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<Choose>
<When Condition="'$(MSBuildToolsVersion)' == 'Current' OR $(MSBuildToolsVersion.Split('.')[0]) >= 14">
<PropertyGroup>
<TasksAssemblyName>Microsoft.Build.Tasks.Core.dll</TasksAssemblyName>
</PropertyGroup>
</When>
<Otherwise>
<PropertyGroup>
<TasksAssemblyName>Microsoft.Build.Tasks.v$(MSBuildToolsVersion).dll</TasksAssemblyName>
</PropertyGroup>
</Otherwise>
</Choose>
<UsingTask TaskName="Eval" TaskFactory="CodeTaskFactory" AssemblyFile="$(MSBuildToolsPath)\$(TasksAssemblyName)">
<ParameterGroup>
<Values ParameterType="Microsoft.Build.Framework.ITaskItem[]" Required="True" Output="False" />
<Result ParameterType="Microsoft.Build.Framework.ITaskItem[]" Required="False" Output="True" />
</ParameterGroup>
<Task>
<Code Type="Class" Language="cs" Source="$(MSBuildThisFileDirectory)TaskSource\EvalTask.cs"/>
</Task>
</UsingTask>
</Project>
Where TaskSource\EvalTask.cs is
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Microsoft.Build.Framework;
using Microsoft.Build.Utilities;
using System.Diagnostics;
using System.Threading;
namespace Varonis.MSBuild.Tasks
{
public class Eval : Task
{
[Required]
public ITaskItem[] Values { get; set; }
[Output]
public ITaskItem[] Result { get; set; }
public override bool Execute()
{
Result = new TaskItem[Values.Length];
for (int i = 0; i < Values.Length; i++)
{
Result[i] = new TaskItem(Values[i].ItemSpec);
}
return true;
}
}
}

How to add a custom Property as a child of a PropertyGroup in MSBuild?

I have the following build script, which I run with MSBuild:
<?xml version="1.0" encoding="utf-8"?>
<Project DefaultTargets="Compile" xmlns="http://schemas.microsoft.com/developer/msbuild/2003" ToolsVersion ="3.5">
<PropertyGroup>
<BuildDir Condition=" '$(BuildDir)'==' ' ">$(BaseDir)/build</BuildDir>
<ProdDir >$(BuildDir)/prod</ProdDir>
<TestDir>$(BuildDir)/test</TestDir>
<MMC2SourceDir>SteuerungsZugriffTest/mmc2</MMC2SourceDir>
<UserSourceDir>SteuerungsZugriffTest/user</UserSourceDir>
<TestXMLDir>$(BuildDir)/test-results</TestXMLDir>
<SolutionFile Condition=" '$(SolutionFile)'==' ' ">HMI2.0.sln</SolutionFile>"
<NUnitTest>nunit-console.exe</NUnitTest>
</PropertyGroup>
<Target Name="Prepare">
<Message Text="Prepare everything" />
<MakeDir Directories="$(BuildDir)" />
<MakeDir Directories="$(ProdDir)" />
</Target>
...
When I now start script on the command line:
D:\MyDir>msbuild /property:BaseDir=D:\MyDir MyScript.build
I got the following error on the commandline output:
D:\MyDir>MyScript.build(11,78): error MSB4067: Das <#text>-Element unterhalb des <PropertyGroup>-Elements ist unbekannt.
Which basically means: The element<#text> is an unknown child.
Does anybody have an idea?
Edit: Sorry, I completed now the script
You have an extra " at the end of this line
<SolutionFile Condition=" '$(SolutionFile)'==' ' ">HMI2.0.sln</SolutionFile>"
It is outside a tag, so it is considered as a text element...