Introduction
The article is about writing a simple build script for multiple projects and solutions using Power Shell and MSBuild
, with an option to fix the build error during the build and continue the build without having to restart the complete build.
Background
I had to put together a build script in a very short time, about an hour. I could write this power shell script for doing the build and it served my purpose well.
About the script
Overview of the build steps
The Image below outlines the build steps, that I have considered. As you can see its a vanilla flow. You may notice some of the build steps are missing from this diagram, some of them are omitted to keep this script as simple as possible. Some of these are:
- Auto update source prior to build
- Controlling assembly version
- Auto-increment Version Number
- Build output path is not configurable. Will be taken from the project properties.
- Labelling source files.
Extracting the latest source files
Step 1 : Close all DevEnv
Fix and continue feature expects the devevn process is not running, hence a request to close all the devenv is made in the beginning of the script. However this will not stop the script from running.
Step 2 : Initialize Build Configuration
Following are the build initialization and configuration used in the build.
- Base directory for build
- Handling dependency relationships (SolutionConfig.txt defines the order in which the solutions should be built)
- Location of MSBuild.exe
- MS Build log configuration
- Location of devenv
- In case you are using any windows sdk tools in pre or post actions in the build, location of Windows SDK as part of the path.
Step 3: For every solution in the in the SolutionConfig.txt file do Build
- Check if the file exists
- The extension of the file is .sln. If you wish to include more files such as .csproj, vcxproj, etc you can do the necessary change in the script. This is to avoid errors in the SolutionConfig.txt file.
Step 4: MSBuild
MSBuild is a platform for building applications. Using MSBuild we can build projects on systems where visual studio is not installed. To read more about MSBuild visit MSDN MSBuild.
Step 5: Resolving a broken build
To be able to resolve a broken build, you need to run this script on a machine that has Visual Studio installed. The script will launch Visual studio and open the solution that was failed. Once resolving all the errors, close visual studio to continue building next solution in the order.
Step 6: Complete build
Build will successfully complete if all the projects compile without errors. In case you choose not to fix the error, the build will terminate in an error.
Putting it all together
Clear-Host
Write-Host "Please make sure you do not have any instances of Visual studio running before running the script..." -ForegroundColor Red -BackgroundColor White
Write-Host "You have 10 seconds" -ForegroundColor Red -BackgroundColor White
Start-Sleep -s 10
$baseDirectory = "D:\Project1\Source"
$solutionFilesPath = "$baseDirectory\SolutionConfig.txt"
$projectFiles = Get-Content $solutionFilesPath
$msbuild = "C:\WINDOWS\Microsoft.NET\Framework\v4.0.30319\MSBuild.exe"
$MSBuildLogger="/flp1:Append;LogFile=Build.log;Verbosity=Normal; /flp2:LogFile=BuildErrors.log;Verbosity=Normal;errorsonly"
$devenv = "C:\Program Files\Microsoft Visual Studio 10.0\Common7\IDE\devenv.exe"
$action = "Y"
# $env:Path = $env:Path + ";C:\Program Files\Microsoft SDKs\Windows\v7.0A"
foreach($projectFile in $projectFiles)
{
if ($projectFile.EndsWith(".sln"))
{
$projectFileAbsPath = "$baseDirectory\$projectFile"
$filename = [System.IO.Path]::GetFileName($projectFile);
$action = "Y"
while($action -eq "Y")
{
if(Test-Path $projectFileAbsPath)
{
Write-Host "Building $projectFileAbsPath"
& $msbuild $projectFileAbsPath /t:rebuild /p:PlatformTarget=x86 /fl "/flp1:logfile=$baseDirectory\msbuild.log;Verbosity=Normal;Append;" "/flp2:logfile=$baseDirectory\errors.txt;errorsonly;Append;"
#& $devenv $projectFileAbsPath /Rebuild
if($LASTEXITCODE -eq 0)
{
Write-Host "Build SUCCESS" -ForegroundColor Green
Clear-Host
break
}
else
{
Write-Host "Build FAILED" -ForegroundColor Red
$action = Read-Host "Enter Y to Fix then continue, N to Terminate, I to Ignore and continue the build"
if($action -eq "Y")
{
& $devenv $projectFileAbsPath
wait-process -name devenv
}
else
{
if($action -eq "I")
{
Write-Host "Ignoring build failure..."
break
}
else
{
Write-Host "Terminating Build... Please restart the build once the issue is fixed." -ForegroundColor Red
break
}
}
}
}
else
{
Write-Host "File does not exist : $projectFileAbsPath"
Start-Sleep -s 5
break
}
}
if($action -eq "N")
{
break;
}
}
}
Remember to set the Language of your code snippet using the
Language dropdown.
Use the "var" button to to wrap Variable or class names in
<code> tags like this
.
Points of Interest
Logging MS Build out put to file
MSBuild provides pretty extensive mechanism for logging the build output and error. Following script creates 2 log files one for successful build and the other for error.
$msbuild = "C:\WINDOWS\Microsoft.NET\Framework\v4.0.30319\MSBuild.exe"
$MSBuildLogger="/flp1:Append;LogFile=Build.log;Verbosity=Normal; /flp2:LogFile=BuildErrors.log;
& $msbuild $projectFileAbsPath /t:rebuild /p:PlatformTarget=x86 /fl "/flp1:logfile=$baseDirectory\msbuild.log;Verbosity=Normal;Append;" "/flp2:logfile=$baseDirectory\errors.txt;errorsonly;Append;"
Waiting for the process to exit
To wait for the process to exit in power shell I am waiting by the name of the process, this can be done with respect to a process id as well.
Wait-Process -name devenv
Alternatively, following command can be used to start a process and wait for its completion.
Start-Process $devenv -NoNewWindow -Wait
Or
$proc = Start-Process <path to exe> -NoWindow
$proc.WaitForExit()
Validate if path exists
To check if a directory or a file exis we can use Test-Path
command let.Test-Path can also be used to verify if a registry entry exist when used with Windows PowerShell registry provider.
SVN Update and Labelling Source
If you are using SVN as your source control you can include the following command to update your source before performing any of the steps as per the flow chart above. Its required to add the path of svn to the $env.Path. If you need to checkout more than one folder, you can specify the url of multiple folders in a single command separated by a spaces.
& svn co $repositoryUrl1 $repositoryUrl2 $destinationDir
To label source files in SVN after successful builds, you can create tags. This is usually associated with a successful build, successfully generating a incremental version number for the assemblies being build.
Win SDK Tools
When Projects build using .Net 4.0 as target framework Windows Sdk was not working with the default win sdk folder that is referenced by Visual stuido 2010. The additional path that needs to be referenced for .Net 4.0 dlls is:
C:\Program Files\Microsoft SDKs\Windows\v7.0A\bin\NETFX 4.0 Tools
By default the path referenced by visual studio 2010 is:
C:\Program Files\Microsoft SDKs\Windows\v7.0A\bin
References
MSBuild Reference
Windows PowerShell Reference
Handling Dependency Relationships
The Build Process