Question

Tom Hunter on Wed, 17 Aug 2011 07:43:56


I'm using the BuildInParallel attribute of the MSBuild task to run build projects in parallel. The root project is building four child projects. The child projects are using a custom MSBuild task which starts a new process using System.Diagnostics.Process. For some reason the spawned process fail to run properly when UseShellExecute is false. I've no idea why this is and I can't figure out what the error is - all that happens is the Process.ExitCode is 1, no exception..

Here's the custom MSBuild task:

using System;
using Microsoft.Build.Utilities;
using System.Diagnostics;

public class MSBuildProcessTask : Task
{
    public string Executable { get; set; }
    public string Arguments { get; set; }

    public override bool Execute()
    {
        using (var p = new Process())
        {
            try
            {
                p.StartInfo = new ProcessStartInfo(Executable, Arguments)
                                {
                                    UseShellExecute = false,
                                    //RedirectStandardOutput = true
                                };
                //p.OutputDataReceived += (o, e) =>
                //{
                //    if (e.Data != null)
                //    {
                //        Log.LogMessage(MessageImportance.Normal, e.Data);
                //    }
                //};
                p.Start();
                //p.BeginOutputReadLine();
                p.WaitForExit();
            }
            catch (Exception e)
            {
                throw; // for setting breakpoint
            }
            finally
            {
                if (p.ExitCode != 0)
                {
                    Log.LogError("Error.  Exit code: " + p.ExitCode);
                }
                p.Close();
            }
        }
        return true;
    }
}

And here's the root MSBuild project file (Test.proj, actually I'm only building two child project here but still get the error..):

<?xml version="1.0" encoding="utf-8" ?>
<Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
    <UsingTask TaskName="MSBuildProcessTask" AssemblyFile="C:\Users\Tom\Sandbox\repository_trunk\MSBuildProcessTask\MSBuildProcessTask\bin\Debug\MSBuildProcessTask.dll" />
    <Target Name="Default">
        <ItemGroup>
            <ProjectFiles Include="$(MSBuildProjectDirectory)\Test.1.proj" />
            <ProjectFiles Include="$(MSBuildProjectDirectory)\Test.2.proj" />
            <!--<ProjectFiles Include="$(MSBuildProjectDirectory)\Test.3.proj" />
            <ProjectFiles Include="$(MSBuildProjectDirectory)\Test.4.proj" />-->
        </ItemGroup>
            <MSBuild BuildInParallel="true" Projects="@(ProjectFiles)" />
    </Target>
</Project>

And here's an example of the child project files (Test.1.proj):

<?xml version="1.0" encoding="utf-8" ?>
<Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
    <UsingTask TaskName="MSBuildProcessTask" AssemblyFile="C:\Users\Tom\Sandbox\repository_trunk\MSBuildProcessTask\MSBuildProcessTask\bin\Debug\MSBuildProcessTask.dll" />
    <Target Name="Default">
        <Message Text="Hello" />
        <MSBuildProcessTask Executable="sqlcmd" Arguments="-S .\SQLEXPRESS -Q &quot;SELECT @@VERSION&quot;" />
    </Target>
</Project>

My command line is: C:\Windows\Microsoft.NET\Framework\v4.0.30319\MSBuild.exe /m /nr:false C:\Users\Tom\Sandbox\repository_trunk\MSBuildProcessTask\MSBuild ProcessTask\Test.proj

And here's a sample output:

C:\Users\Tom>C:\Windows\Microsoft.NET\Framework\v4.0.30319\MSBuild.exe /m /nr:false C:\Users\Tom\Sandbox\repository_trunk\MSBuildProcessTask\MSBuildPr
ocessTask\Test.proj
Microsoft (R) Build Engine Version 4.0.30319.1
[Microsoft .NET Framework, Version 4.0.30319.235]
Copyright (C) Microsoft Corporation 2007. All rights reserved.

Build started 16/08/2011 22:22:06.
     1>Project "C:\Users\Tom\Sandbox\repository_trunk\MSBuildProcessTask\MSBuildProcessTask\Test.proj" on node 1 (default targets).
     1>Project "C:\Users\Tom\Sandbox\repository_trunk\MSBuildProcessTask\MSBuildProcessTask\Test.proj" (1) is building "C:\Users\Tom\Sandbox\reposito
       ry_trunk\MSBuildProcessTask\MSBuildProcessTask\Test.1.proj" (2) on node 1 (default targets).
     2>Default:
         Hello
     1>Project "C:\Users\Tom\Sandbox\repository_trunk\MSBuildProcessTask\MSBuildProcessTask\Test.proj" (1) is building "C:\Users\Tom\Sandbox\reposito
       ry_trunk\MSBuildProcessTask\MSBuildProcessTask\Test.2.proj" (3) on node 2 (default targets).



------------------------------------------------------------------------------------------------------------------------------------------------------
------------------------------------------------------------------------------------------------------------------------------------------------------

Microsoft SQL Server 2008 (SP1) - 10.0.2531.0 (X64)
        Mar 29 2009 10:11:52
        Copyright (c) 1988-2008 Microsoft Corporation
        Express Edition (64-bit) on Windows NT 6.1 <X64> (Build 7601: Service Pack 1)


(1 rows affected)
     3>Default:
         Hello
     2>Done Building Project "C:\Users\Tom\Sandbox\repository_trunk\MSBuildProcessTask\MSBuildProcessTask\Test.1.proj" (default targets).
     3>C:\Users\Tom\Sandbox\repository_trunk\MSBuildProcessTask\MSBuildProcessTask\Test.2.proj(6,3): error : Error.  Exit code: 1
     3>Done Building Project "C:\Users\Tom\Sandbox\repository_trunk\MSBuildProcessTask\MSBuildProcessTask\Test.2.proj" (default targets).
     1>Done Building Project "C:\Users\Tom\Sandbox\repository_trunk\MSBuildProcessTask\MSBuildProcessTask\Test.proj" (default targets).

Build succeeded.

       "C:\Users\Tom\Sandbox\repository_trunk\MSBuildProcessTask\MSBuildProcessTask\Test.proj" (default target) (1) ->
       "C:\Users\Tom\Sandbox\repository_trunk\MSBuildProcessTask\MSBuildProcessTask\Test.2.proj" (default target) (3) ->
       (Default target) ->
         C:\Users\Tom\Sandbox\repository_trunk\MSBuildProcessTask\MSBuildProcessTask\Test.2.proj(6,3): error : Error.  Exit code: 1

    0 Warning(s)
    1 Error(s)

Time Elapsed 00:00:00.23

C:\Users\Tom>

As you can see we only get output from one of the SQLCMD commands. The problem is that the new process doesn't always seem to run, and doesn't produce any error message (only ExitCode 1). 


Sponsored



Replies

Yi Feng Li on Thu, 18 Aug 2011 06:46:27


Hello ,

Thank you for your question.

I am trying to involve someone familiar with this topic to further look at this issue. There might be some time delay. Appreciate your patience.

Thank you for your understanding and support.

Yi

Tom Hunter on Sun, 21 Aug 2011 17:52:00


Hi Yi, did you have any luck finding anyone who could shed any light on this?

Thanks,
Tom 

Hongye Sun - MSFT on Wed, 24 Aug 2011 07:26:10


Hi Tom,

Process.Start won't report any error when the target process terminated by itself. You should depend on the target process itself to identify its error information. You can output the process's StandardError (http://msdn.microsoft.com/en-us/library/system.diagnostics.process.standarderror.aspx) and StandardOutput (http://msdn.microsoft.com/en-us/library/system.diagnostics.process.standardoutput.aspx) to further investigate on this issue.

Thanks.

Daniel Nolan (ReadyRoll) on Thu, 27 Nov 2014 01:10:00


I'm also having this problem with running SQLCMD.EXE in my custom task so who knows it may be specific to that CLI tool.

What I have noticed is that the issue doesn't happen on Windows Server 2012 R2. The only other environment I tried it on (where it failed) was Windows Server 2008 R2. I'm pretty sure I'm using the same version of SQLCMD.EXE on both servers (the version that ships with SQL Server 2014).

Interestingly, if I call SQLCMD.EXE directly within my MSBuild target, rather than using Process.Start within a custom task, there is no problem executing the tool. So it would be interesting to find out how the <Exec/> task runs the process vs how Process.Start does it.

Just thinking out loud, perhaps a work-around is to save a temporary .targets file that contains a single <Exec/> call to SQLCMD.EXE, and run Process.Start against MSBUILD.EXE. Hacky but might do the job.