Gathering outputs from an MSBuild exec task - msbuild

I have a batch script that I want to call from an MSBuild project, and the documentation says I can't use output from the batch (either console / environment variables) in the MSBuild project.
Is there a workaround?

You can redirect the output of the command to a file using "> output.txt" and read that into a variable.
<PropertyGroup>
<OutputFile>$(DropLocation)\$(BuildNumber)\Output.txt</OutputFile>
</PropertyGroup>
<Exec Command="dir > "$(OutputFile)"" />
<ReadLinesFromFile File="$(OutputFile)">
<Output TaskParameter="Lines" ItemName="OutputLines"/>
</ReadLinesFromFile>
<Message Text="#(OutputLines->'%(Identity)', '%0a%0d')" />

Related

Wix bootstrapper - Set version number in Bundle

I've got a Wix installer that uses a bootstrapper to launch my msi file. I've done this by calling a batch file as a post build event in my wix project. This then calls candle and light manually and passes various variables into the Bundle.wxs file. This all works and generates the exe which calls my msi file..
However, I now want to pass the msi BuildVersion into the bundle file. In the wxs file that creates the msi I am using the BuildVersion that I have setup in the BeforeBuild section, using the BuildVersion=%(AssemblyVersion.Version).
I cannot access this variable no matter what I try, in order to pass it to my build_bootstrapper.bat file. I can however pass in hardcoded values. I am currently setting up my own AssemblyVersionNumber enviornment variable as you can see below in the AfterBuild section:
<AssemblyVersionNumber Condition="'$(AssemblyVersionNumber)' == ''">$(BuildVersion)</AssemblyVersionNumber>
but it is empty by the time it gets to my script file (even though it's populated if hardcoded). I've tried everything.
Does anybody have any ideas of how I can get the %(AssemblyVersion.Version); to my command file from the post build step?
Thanks in advance
<Target Name="BeforeBuild">
<GetAssemblyIdentity AssemblyFiles="..\..\App\AppThing\bin\Release\AppThing.exe">
<Output TaskParameter="Assemblies" ItemName="AssemblyVersion" />
</GetAssemblyIdentity>
<PropertyGroup>
<DefineConstants>BuildVersion=%(AssemblyVersion.Version);</DefineConstants>
</PropertyGroup>
</Target>
<Target Name="AfterBuild">
<PropertyGroup>
<DefineConstants>BuildVersion=%(AssemblyVersion.Version);</DefineConstants>
<AssemblyVersionNumber Condition="'$(AssemblyVersionNumber)' == ''">$(BuildVersion)</AssemblyVersionNumber>
</PropertyGroup>
</Target>
<PropertyGroup>
<PreBuildEvent>$(ProjectDir)scripts\copy_services.bat $(SolutionDir) $(ProjectDir)</PreBuildEvent>
</PropertyGroup>
<Target Name="AfterClean">
<Message Text="Cleaning wix files, TargetDir is: $(TargetDir)" Importance="High" ContinueOnError="true" />
<CreateItem Include="$(TargetDir)\**\*.*">
<Output TaskParameter="Include" ItemName="BinFilesDir" />
</CreateItem>
<Delete Files="#(BinFilesDir)" />
</Target>
<PropertyGroup>
<PostBuildEvent>$(ProjectDir)scripts\build_bootstrapper.bat $(ProjectDir) $(ConfigurationName) $(AssemblyVersionNumber)</PostBuildEvent>
</PropertyGroup>
$(BuildVersion) isn't set to anything.
You're setting define constants to "BuildVersion=%(AssemblyVersion.Version)" but never actually defining a MSBuild property called "BuildVersion" so the value of $(BuildVersion) is "".
Use %(AssemblyVersion.Version).
<AssemblyVersionNumber Condition="'$(AssemblyVersionNumber)' == ''">%(AssemblyVersion.Version)</AssemblyVersionNumber>

How to pass parameter to Wix patch?

We are creating patch using Wix. It is given below
<Family DiskId="5000"
MediaSrcProp="Sample"
Name="Sample"
SequenceStart="5000">
<UpgradeImage SourceFile="Z:\MyViewName\Latest_UnCompressed\EmailTrans.msi" Id="Latest">
<TargetImage SourceFile="Z:\MyViewName\Prev_Uncompressed\EmailTrans.msi" Order="2" Id="Previous" IgnoreMissingFiles="no"/>
</UpgradeImage>
</Family>
I do not want to use <UpgradeImage SourceFile="Z:\MyViewName , Because this may change often.
I am using Msbuild target like below to build it
<Target Name="CreateUncompressFolder">
<RemoveDir Condition="Exists('$(OldUncompressedMsiPath)')" Directories="$(OldUncompressedMsiPath)" />
<MakeDir Condition="!Exists('$(OldUncompressedMsiPath)')" Directories="$(OldUncompressedMsiPath)" />
<RemoveDir Condition="Exists('$(NewUncompressedMsiPath)')" Directories="$(NewUncompressedMsiPath)" />
<MakeDir Condition="!Exists('$(NewUncompressedMsiPath)')" Directories="$(NewUncompressedMsiPath)" />
</Target>
<Target Name="UnCompressMsi" DependsOnTargets="CreateUncompressFolder">
<Exec Command="msiexec.exe /a "$(NewMsiPath)" /qb TARGETDIR="$(NewUncompressedMsiPath)""/>
<Exec Command="msiexec.exe /a "$(OldMsiPath)" /qb TARGETDIR="$(OldUncompressedMsiPath)""/>
</Target>
<Target Name="BuildMsp">
<Exec Command="candle.exe "$(PatchWxsName)""/>
<Exec Command="light.exe "$(WixObj)" -out "$(PCPName)""/>
<Exec Command="msimsp.exe -s "$(PCPName)" -p "$(MspName)" -l "Patch.log" "/>
</Target>
Is it possible to pass Z:\MyViewName as parameter via Msbuild ?
You need to use the DefineConstants and have msbuild pass in parameters to your .wixproj as parameters. In Automating WiX with MSBuild, you'll see he's passing in PRODUCTVERSION as a MSBUILD parameter to the wixproj and he can then reference the value of PRODUCTVERSION using $(var.PRODUCTVERSION) in his WXS file.
Another approach I've seen done, which is pretty much the same in the link i mentioned is to instead add the XML element DefineConstants as a property to the PropertyGroup in the .wixproj file instead of creating the property on the fly in the BeforeBuild target.
E.x.:
<Project>
<PropertyGroup>
<Configuration/>
<Platform/>
<DefineConstants>
BuildVersion=$(ProductVersion);
WixVarName=$(MSBuildPropertyName);
WixVarName1=$(MSBuildPropertyName1);
WixVarName2=$(MSBuildPropertyName2);
</DefineConstants>
<OutputPath/>
<OutputName/>

Change output directory where test results file is generated

I am using MSTest to execute my unit tests against a web service on a remote server.
Is there way to change the path to where the results file(.trx) is generated. Currently my test results is generated in the directory which the Exec command is invoked from:
<Target Name="ExecuteTheTests" AfterTargets="StartService" Condition="'$(ServiceStarted)' == 0 And '$(Configuration)' == 'Release'">
<Message Text="Executing the Unit Tests" Importance="high" />
<PropertyGroup>
<TestSuccessOrNot>0</TestSuccessOrNot>
</PropertyGroup>
<Exec Command=""C:\\Program Files (x86)\\Microsoft Visual Studio 11.0\\Common7\\IDE\\MSTest.exe" /testcontainer:..\..\..\..\\_MyOutput\\UnitTests.dll /detail:testname ">
<Output TaskParameter="ExitCode" PropertyName="TestSuccessOrNot" />
</Exec>
<Error Condition="$(TestSuccessOrNot) == 1" Text="Unit tests fail!" />
Thanks,
Many Bothans died* to bring you this message:
mstest.exe /resultsfile:c:\BadPlaceForTestResults.trx
j/k, many Bothans didn't die, they just typed "MsTest.exe /?"

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.

How do I select all read-only files with msbuild?

I'm trying to write an MsBuild script to zip some files up. I need to select all of the read-only files recursively from a folder into an ItemGroup to add to the zip.
I'm using the community tasks Zip task, but am struggling with selecting files based on their attributes.
Is there anything around to do this out of the box, or do I need to write a custom task?
Thanks for you help.
You can use Property Functions (added to msbuild 4) to figure out if a file is read-only like so:
<ItemGroup>
<MyFiles Include="Testing\*.*" >
<ReadOnly Condition='1 == $([MSBuild]::BitwiseAnd(1, $([System.IO.File]::GetAttributes("%(Identity)"))))'>True</ReadOnly>
</MyFiles>
</ItemGroup>
<Target Name="Run" Outputs="%(MyFiles.Identity)">
<Message Text="%(MyFiles.Identity)" Condition="%(MyFiles.ReadOnly) != True"/>
<Message Text="%(MyFiles.Identity) ReadOnly" Condition="%(MyFiles.ReadOnly) == True" />
</Target>
Have you looked at the community build tasks site?
It has a zip task and an attribute change task - they should get you most of they way there.
This seems to do the job with a bit of dirty command line usage.
<Exec Command="dir .\RelPath\ToFolder\ToSearchIn /S /AR /B > readonlyfiles.temp.txt"/>
<ReadLinesFromFile File="readonlyfiles.temp.txt">
<Output TaskParameter="Lines" ItemName="ReadOnlyFiles"/>
</ReadLinesFromFile>
<Delete Files="readonlyfiles.temp.txt"/>
That gives absolute paths to the files.
To get relative paths, try something like this:
<Exec Command="dir .\RelPath\ToFolder\ToSearchIn /S /AR /B > readonlyfiles.temp.txt"/>
<FileUpdate Files="readonlyfiles.temp.txt"
Multiline="True"
Regex="^.*\\RelPath\\ToFolder\\ToSearchIn"
ReplacementText="RelPath\ToFolder\ToSearchIn"
/>
<ReadLinesFromFile File="readonlyfiles.temp.txt">
<Output TaskParameter="Lines" ItemName="ReadOnlyZipFiles"/>
</ReadLinesFromFile>
<Delete Files="readonlyfiles.temp.txt"/>