MSBuild error MSB3073

Problem:

Building project with console MSBuild sometimes causes an Error MSB3073: The command exited with code 1.

For example, simple exec msbuild task fails:

<exec Command=”echo HelloWorldMessage” />

This appears at msbuild.exe output as:

‘C:\Documents’ is not recognized as an internal or external command,  operable program or batch file.

MSBuild wraps your command with a temporary bat file and stores it to the user Temp directory.  Then MSBuild tries to execute your bat file with CMD. Usually, user Temp directory path starts with ‘C:\Documents and Settings\UserName’.  So, first command CMD interpretation looks like ‘C:\Documents’.

Solution:

  1. Go to environment variables menu.
  2. Change TEMP and TMP variables to the values without spaces. For example, ‘C:\Temp’.
  3. Create new temp directory ‘C:\Temp’.
Posted in Programming | Tagged , | Leave a comment

MSBuild: Key file importing error

Sometimes you have to sign with an existing key file building .NET project assembly through console msbuild.exe

There is manual way to import key file without installed Visual Studio.

MSBuild message:

Error MSB3325: Cannot import the following key file: keyfile.pfx.
The key file may be password protected.
To correct this, try to import the certificate again or manually install
the certificate to the Strong Name CSP with the following
key container name: VS_KEY_XXXXXXXXXXXXXXX.

Here is the solution:

  1. Check user has administrator rights from command line:
  2. > net localgroup Administrators
  3. Change dir to the keyfile.pfx directory.
  4. Execute the following tool with command:
  5. > sn.exe  -i  keyfile.pfx VS_KEY_XXXXXXXXXXXXXXX

sn.exe location example: %PROGRAMFILES%\Microsoft Visual Studio 8\SDK\v2.0\Bin

Posted in Programming | Tagged , , , , | Leave a comment

Howto automate simple Windows build server.

Requirements:

  • cygwin — windows bash scripting utility
  • mailsend — free email notification utility
  • msbuild — standard .NET Framework build utility
  • team explorer — source control utility (tfs)

Features:

  • auto build with Debug and Release configurations
  • builds separately every commited TFS changeset
  • current date appended to MSI file name
  • different email notifications for successful and failed builds with description

Algorithm structure:

  1. This script should be called periodically, for example, every 10 minutes to check for the new changesets with Windows task scheduler.
  2. In case changeset hasn’t built yet (there are no folders with a given building changeset number), we have to start build process.
  3. Get source code from  TFS server for the given changeset number.
  4. Build Debug and Release configurations for the given changeset. Log files are stored in destination folders.
    1. Debug/[changesetnumber]
    2. Release/[changesetnumber]
  5. Send notifications emails for the selected users at the end of a build process for the given changeset:
    1. in case of successful build, email contains network links to the destination folders with msi installation files. Also changeset commiter user name included, comment and edit files list.
    2. in case of failed build, debug.log and release.log build process files attached to the email letter. Also log files copies are stored in destination folders of build server.

Main projects autobuild.bat build file example:

c:\cygwin\bin\bash.exe --login -i /cygdrive/c/WT_Build/firstproject.sh >>C:\WT_Build\log.txt 2>&1
c:\cygwin\bin\bash.exe --login -i /cygdrive/c/WT_Build/secondproject.sh >>C:\WT_Build\log.txt 2>&1

Script file example firstproject.sh:

#!/bin/bash
SERVER="http://tfsserver:portnumber/"
SERVERPATH='$/TFSProjetDirectory/trunk/ProjectName/'
WORKSPACE="WORKSPACENAME"

BUILD_PARAMETERS="/p:PostBuildEvent=""" #skip post build events

CC_SUCCESS_BUILD="firstemail@mailserver.com,secondemail@mailserver.com"
CC_FAILED_BUILD="firstemail@mailserver.com"

PROJECT_BUILD_DIR="ProjectNameSuffix"

GETPATH="$(cygpath -u 'C:\WT_Build\TFSProjetDirectory\trunk\ProjectName')"
DOTNETPATH="$(cygpath -u 'C:\WINDOWS\Microsoft.NET\Framework\v3.5\')"
SETUPPATH="$GETPATH"/SetupProjectDirectory
SETUPPROJECTPATH="$(cygpath -w $SETUPPATH/SetupProjectName.wixproj)"

SETUP_DEBUG_EN_RESULT="$SETUPPATH"/bin/Debug/en-US/MsiOutputName*.msi
SETUP_DEBUG_RU_RESULT="$SETUPPATH"/bin/Debug/ru-RU/MsiOutputName*.msi
SETUP_RELEASE_EN_RESULT="$SETUPPATH"/bin/Release/en-US/MsiOutputName*.msi
SETUP_RELEASE_RU_RESULT="$SETUPPATH"/bin/Release/ru-RU/MsiOutputName*.msi

#include file with auto build utilities
source /cygdrive/c/WT_Build/auto_build_utils.sh

echo "----------------------------------------------------------"
echo "Checking TFS for the new changesets...."

CreatePath $GETPATH

#we load last solution history. 15 latest changesets are taken
$TF history $SERVERPATH /version:T /recursive /stopafter:15 /noprompt /server:$SERVER |
tail -n+3 |
sort |
while read changeset commiter other
do
    if [ ! -d "$BUILDPATH"/Debug/"$changeset" ] && [ ! -d "$BUILDPATH"/Release/"$changeset" ] ; then
    # Control will enter here if destination DIRECTORY doesn't exist
		DeleteCode $GETPATH
		CreatePath $GETPATH

		CreatePath "$BUILDPATH"/Debug/"$changeset"
		CreatePath "$BUILDPATH"/Release/"$changeset"

		getCodeLogfile=$BUILDPATH"/Release/"$changeset"/getcode.log"
		debugBuildLogfile=$BUILDPATH"/Debug/"$changeset"/debug.log"
		releaseBuildLogfile=$BUILDPATH"/Release/"$changeset"/release.log"

		GetCode $changeset $getCodeLogfile
		BuildChangeset $changeset $debugBuildLogfile $releaseBuildLogfile

#Project name considered to be like MyProjectSetupFileName.0.9.4102.30983_110326_171041_EN_Debug.msi
		setupDebugEnOutput="$BUILDPATH"/Debug/"$changeset"/`basename $SETUP_DEBUG_EN_RESULT | cut -d'.' -f1,2,3,4,5`_"$DATE"_EN_Debug.msi
		setupDebugRuOutput="$BUILDPATH"/Debug/"$changeset"/`basename $SETUP_DEBUG_RU_RESULT | cut -d'.' -f1,2,3,4,5`_"$DATE"_RU_Debug.msi
		setupReleaseEnOutput="$BUILDPATH"/Release/"$changeset"/`basename $SETUP_RELEASE_EN_RESULT | cut -d'.' -f1,2,3,4,5`_"$DATE"_EN_Release.msi
		setupReleaseRuOutput="$BUILDPATH"/Release/"$changeset"/`basename $SETUP_RELEASE_RU_RESULT | cut -d'.' -f1,2,3,4,5`_"$DATE"_RU_Release.msi

		CopyResults $SETUP_DEBUG_EN_RESULT $setupDebugEnOutput
		CopyResults $SETUP_DEBUG_RU_RESULT $setupDebugRuOutput
		CopyResults $SETUP_RELEASE_EN_RESULT $setupReleaseEnOutput
		CopyResults $SETUP_RELEASE_RU_RESULT $setupReleaseRuOutput

		MailBuildReport $changeset $commiter $debugBuildLogfile $releaseBuildLogfile

	echo -e "\n"
    fi
done

echo Done.

Auto build utilities file auto_build_utils.sh:

#!/bin/bash
TF="TF.exe"
MSBUILD="MSBuild.exe"

#http://www.muquit.com/muquit/software/mailsend/mailsend.html">http://www.muquit.com/muquit/software/mailsend/mailsend.html
MAILSEND="$(cygpath -u 'C:\WT_Build\mailsend.exe')"

DATE=`date +%y%m%d_%H%M%S`
TFSPATH="$(cygpath -u 'C:\Program Files\Microsoft Visual Studio 9.0\Common7\IDE')"
BUILDPATH="$(cygpath -u 'C:\WT_Build\Builds\'$PROJECT_BUILD_DIR)"

PATH=${PATH}:"$TFSPATH":"$GETPATH":"$DOTNETPATH"

function CreatePath {
    echo -e "\n"
    echo Checking directory: $1

    mkdir -p $1
}

function BuildChangeset {

    echo -e "\n"
    echo Building Release changeset $1...
    $MSBUILD $SETUPPROJECTPATH /t:Rebuild /p:Configuration=Release $BUILD_PARAMETERS >$3 2>&1

    echo -e "\n"
    echo Building Debug changeset $1...
    $MSBUILD $SETUPPROJECTPATH /t:Rebuild /p:Configuration=Debug $BUILD_PARAMETERS >$2 2>&1
}

function GetCode {
    echo -e "\n"
    echo Getting code for changeset $1...

	pushd $GETPATH
    $TF get $SERVERPATH /version:C$1 /recursive /noprompt /overwrite /force >$2 2>&1
	popd
}

function DeleteCode {
    echo Deleteting path: $1

    rm -r -f $1
}

function CopyResults {
    echo -e "\n"
    echo Copying $1
    echo '   'to $2
    cp $1 $2
}

function MailBuildReport {
    if (cat $3 | grep -q "Build succeeded") && (cat $4 | grep -q "Build succeeded")
    then
		( echo 'Release build link \\Vm-wt-build\Builds\'$PROJECT_BUILD_DIR'\Release\'$1 &&
		echo 'Debug build link \\Vm-wt-build\Builds\'$PROJECT_BUILD_DIR'\Debug\'$1  &&
		echo -e "\n\n" &&
		$TF changeset /server:$SERVER /noprompt $1 ) |
		iconv -f CP1251 -t UTF-8 |
		$MAILSEND -d share.server.local -smtp share.server.local -cc $CC_SUCCESS_BUILD -t $2@server.com -f fromuser@server.com -sub "$2: $PROJECT_BUILD_DIR Build for changeset $1 READY"
    else
		firstLog="$(cygpath -w $3)"
		secondLog="$(cygpath -w $4)"

		$TF changeset /server:$SERVER /noprompt $1 |
		iconv -f CP1251 -t UTF-8 |
        $MAILSEND -d share.server.local -smtp share.server.local -cc $CC_FAILED_BUILD -t $2@server.com -f fromuser@server.com -sub "$2: $PROJECT_BUILD_DIR Build changeset $1 FAILED." -a "$firstLog,text/plain" -a "$secondLog,text/plain"
    fi
}
Posted in Programming | Tagged , , , , , | Leave a comment