Search code examples
msbuildmsbuild-task

How to pass env-var to MSBuild Task and make it effective for all sub-process? (concrete code)


I have a question about passing environment variables to MSBuild Task. See my code below:

a.proj

<Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003" 
    DefaultTargets="A1">
    
    <Target Name="A0">
        <Message Text="A0 start."/>
        <MSBuild Projects="b.proj" Properties="myvar=000" />
        <Message Text="A0 end."/>
    </Target>

    <Target Name="A1" DependsOnTargets="A0">
        <Message Text="A1 start."/>
        <MSBuild Projects="b.proj" Properties="myvar=111" />
        <Message Text="A1 end."/>
    </Target>
</Project>

b.proj

<Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
    <Target Name="B">
        <Message Text="B start."/>
        <Exec command="c.bat" />
    </Target>
</Project>

c.bat

echo [C]myvar=%myvar%

I hope that c.bat can see myvar's value passed from a.proj. My code above failed to do that.

enter image description here

Consider(Assume) a running <MSBuild> Task a process on the OS, then, I'd like to pre-set environment variable myvar for that process, so that its subprocesses(no matter how deep) can all see myvar's value.

How can I achieve that? Thank you.


Solution

  • When MSBuild starts, it maps the environment variables in its process to MSBuild Properties. For example the environment variable COMPUTERNAME is available in an MSBuild project as the $(COMPUTERNAME) property.

    But Properties are not added to the environment variables.

    The Exec task creates a new process. The new process will inherit the environment variables of the 'parent' process and Exec has a parameter for passing additional environment variable definitions that will either add to or override the existing environment variables. The parameter is EnvironmentVariables.

    Modify your Exec task as follows:

            <Exec command="c.bat" EnvironmentVariables="myvar=$(myvar)" />
    

    Example

    The following is a full example of the environment variable passing.

    Given a file 'test.proj':

    <Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
    
      <Target Name="TestExecPassVar">
        <MSBuild Projects="$(MSBuildThisFile)" Targets="ExecPassVar" Properties="myvar=000" />
        <MSBuild Projects="$(MSBuildThisFile)" Targets="ExecPassVar" Properties="myvar=111" />
        <MSBuild Projects="$(MSBuildThisFile)" Targets="ExecPassVar" />
      </Target>
    
      <Target Name="ExecPassVar">
        <Exec Command="test.bat" EnvironmentVariables="myvar=$(myvar)" EchoOff="true" />
      </Target>
    
    </Project>
    

    And given a file 'test.bat':

    @echo running test.bat
    @echo %myvar%
    

    Running the command

    set myvar=222
    

    and then

    msbuild test.proj
    

    will produce output like the following (which has been edited to remove paths and other noise):

    Project "test.proj" on node 1 (TestExecPassVar target(s)).
    Project "test.proj" (1) is building "test.proj" (1:2) on node 1 (ExecPassVar target(s)).
    ExecPassVar:
      running test.bat
      000
    Done Building Project "test.proj" (ExecPassVar target(s)).
    
    Project "test.proj" (1) is building "test.proj" (1:3) on node 1 (ExecPassVar target(s)).
    ExecPassVar:
      running test.bat
      111
    Done Building Project "test.proj" (ExecPassVar target(s)).
    
    Project "test.proj" (1) is building "test.proj" (1:4) on node 1 (ExecPassVar target(s)).
    ExecPassVar:
      running test.bat
      222
    Done Building Project "test.proj" (ExecPassVar target(s)).
    
    Done Building Project "test.proj" (TestExecPassVar target(s)).
    

    The test project invokes its own ExecPassVar target three times. The first two times it passes Properties that define a $(myvar) property. The third time no property is passed and the $(myvar) property is undefined.

    The Exec task uses the EnvironmentVariables parameter.

    When the $(myvar) property is defined, the batch file sees a myvar environment variable with the passed value.

    When the $(myvar) property is not defined, the EnvironmentVariables parameter value evaluates to "myvar=". This doesn't override or clear the value of myvar and the value of 222, that was set before the msbuild command, is seen by the batch file.