Showing posts with label MSBuild. Show all posts
Showing posts with label MSBuild. Show all posts

Saturday, July 2, 2016

Generating Xml Comments Documentation using MSBuild

I had a requirement to generate Xml Comments Documentation for my Web API layer using MSBuild and after using the GenerateDocumentation MSBuild Project property as defined in the MSBuild project documentation  https://msdn.microsoft.com/en-us/library/bb629394.aspx), I noticed that the Xml Comments files were still not being generated!

This problem was quite the dilemma and incredibly perplexing since I had already set the Xml Documentation file path for my project:


After doing a TON of research, I discovered that the Xml Documentation files are based on EACH CONFIGURATION!!

Of course, this is what my Release configuration looked like:



That means that you need to configure it for BOTH your Debug AND Release Configurations!!

Once, I also configured the Xml Documentation file for my Release configuration, my Xml Comments documentation was FINALLY being generated!


Thursday, June 23, 2016

Publishing a Web Application using psake

I have long used MSBuild scripts for setting up my continuous integration builds, but I have started migrating some of my MSBuild scripts over to psake to make the code easier to test and maintain.

One of the problems I struggled with was setting up publishing for a Web Application.  Apparently, this is a bane for many developers or DevOps team members, so I was able to find a StackOverflow article which described a partial solution for my needs: http://stackoverflow.com/questions/4768190/how-to-publish-web-site-using-psake

Of course, this particular snippet did not exactly work for my needs, so I tweaked it to more closely suit my needs as follows:

Of course, you will need to set up a Publishing Profile for your web application, in order for this particular script to work, but once that has been set up, you simply pass the publishUrl property in order to alter the publishing output path!

That is all there is to it!

Tuesday, April 19, 2016

Changing the Assembly Version using Jetbrains TeamCity

If you are using a process outside of Jetbrains TeamCity to manage your assembly version information, then you may end up using a process that leverages MSBuild to alter AssembyInfo.cs files or GlobalAssemblyInfo.cs files.

In the past, I have used MSBuild Extension Pack with the AssemblyInfo task to accomplish this: http://msbuildextensionpack.com/

However, since I am using Jetbrains TeamCity as part of my CI build processes, I can use the AssemblyInfo Patcher Build Feature instead!  https://confluence.jetbrains.com/display/TCD9/AssemblyInfo+Patcher

This can be done as follows:








Since this runs before the 1st build step it requires no changes to your existing build steps and configuration!

Pretty awesome, huh??

Friday, April 1, 2016

psake and MSBuild - Better together

I was recently introduced to an alternative method of building projects using a tool called psake.

This is basically a project which leverages PowerShell to do the heavy lifting of tasks that would normally require custom .NET tasks or extensions to MSBuild to accomplish normally.

https://github.com/psake/psake

The documentation for psake can be found here:
http://psake.readthedocs.org/en/latest/

Psake is also conveniently available as a NuGet package: https://www.nuget.org/packages/psake

For a quick tutorial on getting started with psake, you can check out this blog post: https://www.pluralsight.com/blog/software-development/psake-better-build-system-net

Since psake is built on PowerShell which itself is built on the .NET Framework, it opens up a lot of possibilities to accomplish things which are not readily built into MSBuild.

Of course, now that MSBuild is open source, the number of built-in MSBuild tasks will probably grow over time, but psake will be able to easily fill those gaps in the interim!!

Thursday, January 21, 2016

Ignoring error messages from Visual Studio Post Build events

I don't use Post Build events in my Visual Studio solutions very often since I prefer to code this directly into MSBuild as part of my Continuous Integration build process usually run by a CI Server such as Jetbrains TeamCity or Team Foundation Build.

However, since I work on a wide variety of projects as part of my consultancy, I frequently encounter projects which still leverage Visual Studio Post Build events.

A large number of Visual Studio projects have a Post Build event which redirects the output to another directory on the file system and may even include a set of commands needed to create the correct target directory structure.

The problem with this approach is using standard command line commands such as mkdir will emit errors if a directory already exists, thus causing Visual Studio to raise an error if a particular command in the Post Build event fails even though it may have worked just fine overall.

So, how do you handle this problem?

Well, using the capabilities of MSBuild, you can modify the Visual Studio project file to ignore these Post Build event error messages!

The solution provided here is by far my favorite solution to this problem: http://blogs.msdn.com/b/astebner/archive/2006/08/08/691849.aspx

It overrides the PreBuildEvent (or PostBuildEvent) target in order to ignore the exit codes or continue the Post Build event even if an error occurs.  Alternatively, you can even do both!

Once you include this target in your relevant Visual Studio project files, the Post Build event error messages you are encountering should disappear!

Tuesday, September 15, 2015

Updating Path Variables for Advanced Installer

Unfortunately, Advanced Installer does not have great command-line support or API support for Path Variables, therefore, you often have to resort to workarounds to accomplish things that would otherwise be easily possible if Advanced Installer had better command-line or API support.

One such case is when dealing with Path Variables.  If you look at Advanced Installer's command-line for Path Variables, you will notice that there is only support for adding New Path Variables or Deleting Path Variables:

http://www.advancedinstaller.com/user-guide/new-path-variable.html

http://www.advancedinstaller.com/user-guide/delete-path-variable.html

But what if you want to simply update your existing Path Variables stored in your PathVariables.xml file?  Well, unfortunately, there is no solution for that built into Advanced Installer's command-line support!

Therefore, you can use a workaround courtesy of MSBuild and MSBuild Extension Pack as in the following code snippet:
<Target Name="BuildPackageWithPathVars" DependsOnTargets="PrepareNRClaims">
   <Message Text="This is the Advanced Installer Path $(AdvancedInstallerPath)" />
   <MSBuild.ExtensionPack.Xml.XmlFile TaskAction="UpdateAttribute" File="$(PathVariablesFile)" XPath="/PathVariables/Var[@Name='Published_Dir']" Key="Path" Value="$(PublishFolder)" />
   <MSBuild.ExtensionPack.Xml.XmlFile TaskAction="UpdateAttribute" File="$(PathVariablesFile)" XPath="/PathVariables/Var[@Name='PackagingFiles_Dir']" Key="Path" Value="$(PackagingFilesDir)" />
   <MSBuild.ExtensionPack.Xml.XmlFile TaskAction="UpdateAttribute" File="$(PathVariablesFile)" XPath="/PathVariables/Var[@Name='Prerequisites_Dir']" Key="Path" Value="$(PrerequisitesFilesDir)" />
   <MSBuild.ExtensionPack.Xml.XmlFile TaskAction="UpdateAttribute" File="$(PathVariablesFile)" XPath="/PathVariables/Var[@Name='PackagingSigning_Dir']" Key="Path" Value="$(CodeSigningDir)" />
   <ItemGroup>
     <BuildArg Include="/rebuild" />
     <BuildArg Include="&quot;$(AdvancedInstallerProjectFilePath)&quot;" />
   </ItemGroup>
   <Exec Command="&quot;$(AdvancedInstallerPath)&quot; /loadpathvars $(PathVariablesFile)" />
   <Message Text="This is the command to be run: &quot;$(AdvancedInstallerPath)&quot; @(BuildArg, ' ')" />
   <Exec Command="&quot;$(AdvancedInstallerPath)&quot; @(BuildArg, ' ')" ContinueOnError="False"  />
 </Target>

 

Once you have loaded the Path Variables into Advanced Installer, you should then be able to successfully build the installation package using the update PathVariables.xml file values!

Monday, September 14, 2015

The "Copy" task does not support copying directories.

I was recently trying to perform a standard copy using the Copy task in MSBuild when I was suddenly faced with this error message:

The "Copy" task does not support copying directories.

Well, fortunately, I came across this article which describes how to workaround this limitation of the base MSBuild Copy Task:  http://blogs.msdn.com/b/msbuild/archive/2005/11/07/490068.aspx 

Of course, another alternative is to simply use the RoboCopy task from the MSBuild Extension Pack: https://github.com/mikefourie/MSBuildExtensionPack/releases

Wednesday, August 26, 2015

Visual Studio External Tools Limitation

If you use the External Tools feature available in Visual Studio for running your external tools such as MSBuild, you might encounter a severe limitation in the IDE which may prevent you from using Visual Studio as your de facto MSBuild Tool.

When you add an External Tool to Visual Studio, you have the option to specify arguments as well as "Prompt for Arguments"






However, if you look at the length of the arguments that you can specify, you will quickly discover that there is a HARD limit to how many characters that you can add to the Arguments field for your External Tools!

Therefore, if you attempt to create an argument consisting of several hundred characters, you will notice that the Visual Studio IDE will truncate out all of the additional characters from your arguments, thus resulting in unexpected behavior if you do not expect the IDE to truncate your arguments!

So what is the solution to this problem??

Well, you can use an alternative IDE/editor such as EditPlus as described in this article: http://samirvaidya.blogspot.com/2013/10/how-to-run-msbuild-from-editplus-3x.html

Otherwise, you can simply use PowerShell!!


Below is a sample PowerShell script for running MSBuild with Targets and Properties:

$MSBuild = "C:\Program Files (x86)\MSBuild\14.0\Bin\amd64\MSBuild.exe"
$MSBuildProjFile = "C:\MyBuild.proj"
$MSBuildTarget = "PublishProject"
$WebProjectPath = "C:\MyWebProject.csproj"
$SolutionPath = "C:\MyBuildSolution.sln"
$PublishFolder = "C:\Published"
 
 
Clear-Host
 
#Run the MSBuild Command
Write-Host $MSBuild $MSBuildProjFile /t:$MSBuildTarget /p:"SolutionPath=$SolutionPath;WebProjectPath=$WebProjectPath;PublishFolder=$PublishFolder"
& $MSBuild $MSBuildProjFile /t:$MSBuildTarget /p:"SolutionPath=$SolutionPath;WebProjectPath=$WebProjectPath;PublishFolder=$PublishFolder"

Friday, May 15, 2015

Setting up MSBuild as an External Tool in Visual Studio

If you want to use MSBuild as an External Tool for your MSBuild files, fortunately, this is very easy to accomplish in Visual Studio.

  1. From the Tools menu, click External Tools
  2. When the External Tools dialog displays, click on the Add button
  3. Type in MSBuild (32-bit or 64-bit respectively) and point to the location of your MSBuild executable
  4. For the Arguments, select "Item Path" from the list of available arguments by clicking on the ellipsis (...) button
  5. Check the checkbox for "Use Output window" and "Prompt for arguments"
  6. Click on the OK button
  7. MSBuild will now display as an External Tool listed in your Tools menu
  8. Whenever you want to run your MSBuild (.proj) file, you simply open the MSBuild file and select the External Tool from the Tools menu.
  9. That is all there is to it!!
 The locations of MSBuild for the respective versions of Visual Studio are the following:

Visual Studio 2012:  C:\Windows\Microsoft.NET\Framework\v4.0.30319\MSBuild.exe, C:\Windows\Microsoft.NET\Framework64\v4.0.30319\MSBuild.exe

Visual Studio 2013:  C:\Program Files (x86)\MSBuild\12.0\Bin\MSBuild.exe, C:\Program Files (x86)\MSBuild\12.0\Bin\amd64\MSBuild.exe

Visual Studio 2015:  C:\Program Files (x86)\MSBuild\14.0\Bin\MSBuild.exe, C:\Program Files (x86)\MSBuild\14.0\Bin\amd64\MSBuild.exe











Friday, April 24, 2015

Updating a Web.config or App.config file using MSBuild

Normally, if you want to update your Web.config file or App.config file with specific settings, you will normally use a Config Transformation.

However, the problem with Config Transformations is that they require a separate file for EACH environment you want to deploy.  Therefore, you can easily see the number of Config Transformation files growing as you add more environments for development and testing.

So, what is the solution?

Well, in the past, you could update these files using an XmlTask such as the one found in MSBuild Extension Pack.

However, with the release of MSBuild v. 4.0, this is no longer needed with the inclusion of the XmlPoke Task.

In order to update your target Config file with the appropriate values, you simply provide the following:
  1. The path to your Config file
  2. The XPath that you want to update
  3. The new value for the specified element or attribute

Therefore, you can update an appSetting in your Web.config file using MSBuild in the following manner:

<Project ToolsVersion="12.0" DefaultTargets="UpdateWebConfig" InitialTargets="UpdateWebConfig" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">

    <Target Name="UpdateWebConfig">

        <PropertyGroup>

            <WebConfigFile>C:\Code\Web.config</WebConfigFile>

            <AppSettingPath>/configuration/appSettings/add[@key='MySetting]/@value</AppSettingPath>

            <AppSettingNewValue>MyNewValue</AppSettingNewValue>

        </PropertyGroup>

        <XmlPoke XmlInputPath="$(WebConfigFile)" Query="$(AppSettingPath)" Value="$(AppSettingNewValue)" />

    </Target>

</Project>
 
 

If you are interested in updating multiple AppSettings in batch, you can do something like the following:




<Target Name="UpdateWebConfigAppSettings">
 <PropertyGroup>
    <Value1>myvalue1</Value1>
    <Value2>myvalue2</Value2>
    <Value3>myvalue3</Value3>
    <Value4>myvalue4</Value4>
    <Value5>myvalue5</Value5>
  </PropertyGroup>
  <ItemGroup>
    <AppSettingKey Include="Key1">
      <Value>$(Value1)</Value>
    </AppSettingKey>
    <AppSettingKey Include="Key2">
      <Value>$(Value2)</Value>
    </AppSettingKey>
    <AppSettingKey Include="Key3">
      <Value>$(Value3)</Value>
    </AppSettingKey>
    <AppSettingKey Include="Key4">
      <Value>$(Value4)</Value>
    </AppSettingKey>
    <AppSettingKey Include="Key5">
      <Value>$(Value5)</Value>
    </AppSettingKey>
  </ItemGroup>
  <XmlPoke XmlInputPath="C:\Code\Web.config" Query="/configuration/appSettings/add[@key='@(AppSettingKey)']/@value" Value="%(AppSettingKey.Value)" />
</Target>


If you want to integrate with a Continuous Integration Build Server such as Jetbrains TeamCity, you simply have to ensure that you pass these properties into your MSBuild script by using System Properties (ex: system.Value1)

 

That is all there is to it!! Easy as pie!!

Thursday, April 16, 2015

Previewing Web.config and App.config Transformations

Have you ever wondered when you create a Web.config transformation or an App.config transformation if the transformation will be applied correctly without having to publish the site?

Well, with the Slow Cheetah Visual Studio Extension you can do just that!  https://visualstudiogallery.msdn.microsoft.com/69023d00-a4f9-4a34-a6cd-7e854ba318b5

It allows you to right click on any Web.config or App.config transformation and select "Preview Transform".  This provides you with a before and after look of your final Web.config file.

This allows you to easily view your final rendering to check for errors and make any corrections as needed before you perform a Publish or a Config Transformation is applied as part of your Continuous Integration Build Process.

How cool is that??

Wednesday, April 15, 2015

Running MSBuild without Visual Studio

I recently wanted to write and test some very basic MSBuild scripts but I didn't want to install Visual Studio.  If you recall, MSBuild stopped shipping with the .NET Framework and began shipping with Visual Studio.

So, what was I to do?

Well, fortunately, Microsoft released the Microsoft Build Tools 2013 to address this exact problem: http://www.microsoft.com/en-us/download/details.aspx?id=40760

The download is less than 20 MB and after installing the Build Tools on my machine, I was able to successfully run my MSBuild scripts!

Tuesday, February 24, 2015

Digitally Signing a WinZip Self-Extractor Executable

If you are looking for guidance on signing an executable created using WinZip Self-Extractor, unfortunately, WinZip does not provide you with much guidance other than pointing you to Microsoft's Authenticode website: http://kb.winzip.com/kb/entry/118/#codesign

Fortunately, WinZip Self-Extractor Executables can be readily signed using Microsoft's SignTool executable.

In fact, this process can actually be automated using MSBuild to digitally sign your WinZip Self-Extractor Executables as in the following MSBuild script:
 
<Target Name="DigitallySignPackage">
  <PropertyGroup>
    <CodeSigningCert></CodeSigningCert>
    <CodeSigningPassword></CodeSigningPassword>
    <TimeStampServer>http://timestamp.verisign.com/scripts/timstamp.dll</TimeStampServer>
    <SignToolPath>&quot;C:\Program Files (x86)\Microsoft SDKs\Windows\v7.1A\Bin\signtool.exe&quot;</SignToolPath>
    <UnsignedExe></UnsignedExe>
  </PropertyGroup>
  <ItemGroup>
    <SigningArgs Include="sign" />
    <SigningArgs Include="/f $(CodeSigningCert)" />
    <SigningArgs Include="/p $(CodeSigningPassword)" />
    <SigningArgs Include="/t $(TimeStampServer)" />
    <SigningArgs Include="$(UnsignedExe)" />
  </ItemGroup>
  <Message Text="This is the name of the executable: $(UnsignedExe)" />
  <Exec Command="$(SignToolPath) @(SigningArgs, ' ')" />
</Target>



Friday, February 6, 2015

Using the C:\Program Files (x86) directory in MSBuild projects

In prior versions of MSBuild, it was always difficult to properly obtain the path to the C:\Program Files (x86) directory without either hard-coding it into the application or writing some conditional statements to correctly determine the proper Program Files directory on the system depending on whether you were running MSBuild on a 32-bit or a 64-bit OS.

Well, fortunately, with the release of MSBuild v. 4.0, this property is now a Reserved property, though it is not well known called MSBuildProgramFiles32.

Here is a list of all of the new MSBuild Properties that were released with MSBuild v. 4.0: http://sedodream.com/2010/03/11/MSBuild40ReservedProperties.aspx
http://devonenote.com/2011/04/msbuild-reserved-properties/

For the complete listing of the Well Known and Reserved MSBuild Properties, you can check out the MSDN documentation here: https://msdn.microsoft.com/en-us/library/ms164309.aspx

Monday, January 19, 2015

Running the StyleCop Task using the MSBuild Extension Pack

If you are attempting to use the StyleCop Task included with the MSBuild Extension Pack, you may encounter problems with executing the task due to an undocumented feature requirement for the MSBuild Extension Pack:

You need to copy the MSBuild.ExtensionPack.StyleCop.dll to the StyleCop installation directory!! (usually C:\Program Files (x86)\StyleCop 4.7)

Once you do this, you will be able to successfully execute the StyleCop Task included with MSBuild Extension Pack.

Friday, January 9, 2015

MSBuild Extension Pack's new home

If you have been a long time user of the MSBuild Extension Pack, you may have noticed that they have moved from CodePlex to GitHub.

Fortunately, the project is still under active development and new releases can now be found here: https://github.com/mikefourie/MSBuildExtensionPack/releases

Thursday, December 25, 2014

Using the CallTarget Task to pass different parameters in MSBuild

If you have a task in MSBuild that you want to re-use over and over again similar to how you would call a function/method in a programming language such as C#, it is not readily obvious how to accomplish this in MSBuild.

Fortunately, there is a way to accomplish this using MSBuild and the CallTarget Task though the solution is not readily obvious.

  1. First of all, declare a set of Properties in a PropertyGroup that you want to use as parameters to your Target.  It is important that these Properties be declared globally in your MSBuild file so that the Target is always aware of the different values of your Properties.  If the Properties are declared locally to your Target then they will not be available across multiple calls to your Target.
  2. Next, declare your Target that you will need to call multiple times.  Within the Target, utilize the Properties that you defined in your global PropertyGroup.
  3. Finally, declare another Target which will be responsible for calling your Target using the CallTarget task multiple times.  In this Target, you will override the values defined in the Global Property between consecutive calls to your Target.
Therefore, your final MSBuild file will look like the following:

 
<Project ToolsVersion="12.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
  <Import Project="$(MSBuildExtensionsPath32)\ExtensionPack\4.0\MSBuild.ExtensionPack.tasks" />
  <Import Project="$(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v10.0\WebApplications\Microsoft.WebApplication.targets" />
  <PropertyGroup>
    <AdvancedInstallerPath>$(ProgramFiles)\Caphyon\Advanced Installer 11\bin\x86\AdvancedInstaller.com</AdvancedInstallerPath>
    <AdvancedInstallerProjectFilePath>Sample.aip</AdvancedInstallerProjectFilePath>
    <PathVariableName>Infragistics_Dir</PathVariableName>
    <PathVariableValue>$(PrerequisitesFilesDir)\Infragistics</PathVariableValue>
  </PropertyGroup>
  <Target Name="TestBuildPathVariables">
    <PropertyGroup>
      <PathVariableName>MyPathVariable</PathVariableName>
      <PathVariableValue>$(PrerequisitesFilesDir)</PathVariableValue>
    </PropertyGroup>
    <CallTarget Targets="PathVariableTarget" />
    <PropertyGroup>
      <PathVariableName>MyPathVariable2</PathVariableName>
      <PathVariableValue>$(PackagingFilesDir)</PathVariableValue>
    </PropertyGroup>
    <CallTarget Targets="PathVariableTarget" />
  </Target>
<Target Name="PathVariableTarget">
    <ItemGroup>
      <PathVariableArg Include="/edit" />
      <PathVariableArg Include="&quot;$(AdvancedInstallerProjectFilePath)&quot;" />
      <PathVariableArg Include="/NewPathVariable" />
      <PathVariableArg Include="-name $(PathVariableName) -value $(PathVariableValue) -valuetype Folder" />
    </ItemGroup>
    <Message Text="This is the command to be run: $(AdvancedInstallerPath) @(PathVariableArg, ' ')" />
    <Exec Command="&quot;$(AdvancedInstallerPath)&quot; @(PathVariableArg, ' ')" />
</Target>
</Project>

Friday, December 19, 2014

Handling spaces for file paths in MSBuild

If you need to deal with file/folder paths that contain spaces in it, this can be problematic when dealing with MSBuild since MSBuild does not automatically handle file paths with spaces in it similar to the command shell.

Fortunately, there is an easy solution to handling these file/folder paths that contain spaces in them.

My preference is to encapsulate them in a PropertyGroup element and assign them to a Property.  Then, I can surround them with the escaped HTML sequence for double quote characters &quot; and then simply use these properties throughout my MSBuild project file!


Monday, January 6, 2014

Changing the logging level of MSBuild in the Visual Studio IDE

If you have ever had to troubleshoot problems with build compilation, you probably know that, by default, Visual Studio, does not provide you with a lot of error detail in the Output window.

Well, fortunately, since Visual Studio internally uses the MSBuild engine, you can modify the build logging detail or verbosity directly from within the IDE!!

  1. From the Tools menu, select Options
  2. Expand the "Projects and Solutions" menu item to display the "Build and Run" menu option
  3. Change the MSBuild logging level for the "MSBuild project build output verbosity" and "MSBuild project build log file verbosity" settings
  4. Re-compile your project or solution to see the additional details in your build compilation!




Tuesday, December 10, 2013

Changes with MSBuild and Visual Studio 2013

 

I have been working with MSBuild for many years and as many people know, MSBuild has typically been located here: C:\Windows\Microsoft.NET\Framework\v4.0.30319\MSBuild.exe

However, when attempting to build a Visual Studio 2013 project using MSBuild, I received the following error message:

The imported project "C:\Program Files (x86)\MSBuild\Microsoft\VisualStudio\v11.0\WebApplications\Microsoft.WebApplication.targets" was not found. Confirm that the path in the declaration is correct, and that the file exists on disk.

Then after some research, I found this article: http://timrayburn.net/blog/visual-studio-2013-and-msbuild/

This indicated the the location of MSBuild moved to a new path here (for 64-bit version): C:\Program Files (x86)\MSBuild\12.0\bin\amd64\msbuild.exe.  (The path for the 32-bit version is C:\Program Files (x86)\MSBuild\12.0\bin\msbuild.exe)

After changing the location of my MSBuild executable to this new path, and re-building using MSBuild, my build completed successfully!