Managed DevOps Pools How to make custom ENV variables available to azure pipelines agent process

2026-10-29T15:44:50.1133333+00:00

For Linux Managed DevOps Pools, what is the supported way to make custom environment variables such as JAVA_HOME_25_X64, JAVA_HOME_21_X64, and JAVA_HOME available to the Azure Pipelines agent process and all task processes? We use a provisioning Setup.sh script with provisioningScriptShouldRestart: true. Writing these variables to /etc/environment has not made them visible in the agent or pipeline task environment. We need JavaToolInstaller@1 with jdkSourceOption: PreInstalled to work without requiring client pipelines to define variables.

provsioning script:
export TARGETARCH="linux-x64"

export JAVA_HOME_25_X64=/usr/lib/jvm/java-25-openjdk-amd64

export JAVA_HOME_21_X64=/usr/lib/jvm/java-21-openjdk-amd64

export JAVA_HOME_17_X64=/usr/lib/jvm/java-17-openjdk-amd64

export JAVA_HOME_11_X64=/usr/lib/jvm/java-11-openjdk-amd64

export JAVA_HOME=/usr/lib/jvm/java-25-openjdk-amd64

 

echo "export JAVA_HOME_25_X64=$JAVA_HOME_25_X64" >> /home/AzDevOps/.bashrc

echo "export JAVA_HOME_21_X64=$JAVA_HOME_21_X64" >> /home/AzDevOps/.bashrc

echo "export JAVA_HOME_17_X64=$JAVA_HOME_17_X64" >> /home/AzDevOps/.bashrc

echo "export JAVA_HOME_11_X64=$JAVA_HOME_11_X64" >> /home/AzDevOps/.bashrc

echo "export JAVA_HOME=$JAVA_HOME" >> /home/AzDevOps/.bashrc

 

cat >> /etc/environment <<'EOF'

JAVA_HOME=/usr/lib/jvm/java-25-openjdk-amd64

JAVA_HOME_25_X64=/usr/lib/jvm/java-25-openjdk-amd64

JAVA_HOME_21_X64=/usr/lib/jvm/java-21-openjdk-amd64

JAVA_HOME_17_X64=/usr/lib/jvm/java-17-openjdk-amd64

JAVA_HOME_11_X64=/usr/lib/jvm/java-11-openjdk-amd64

TARGETARCH=linux-x64

EOF

Azure DevOps
0 comments No comments

Answer accepted by question author
Jerald Felix 19,080 Reputation points Volunteer Moderator
2026-10-29T16:45:26.3766667+00:00

Hello Rowat G@ADM(DS) DEIMS@Defence365,

Greetings! Thanks for raising this question in the Q&A forum.

The variables are not visible because of how the Azure Pipelines agent gets its environment. The agent does not read /etc/environment or ~/.bashrc, since it is not started from an interactive or PAM login shell. Instead, the agent builds the environment for every task from its own process environment, plus the .env file (and .path for PATH) in the agent root directory, which is read when the agent starts. The export lines in your script only affect the provisioning script's own shell and are gone afterwards.

I could not find a Managed DevOps Pools specific setting that injects custom environment variables into the agent, so the approach below relies on the standard agent behavior. Please test it on one pool first.

  1. Write the variables into the agent's .env file. At the end of your Setup.sh, append KEY=value lines (no export, no quotes) to the .env file in the agent root folder:
AGENT_ROOT="<path to the agent folder on the pool VM>"
cat >> "$AGENT_ROOT/.env" <<'EOF'
JAVA_HOME=/usr/lib/jvm/java-25-openjdk-amd64
JAVA_HOME_25_X64=/usr/lib/jvm/java-25-openjdk-amd64
JAVA_HOME_21_X64=/usr/lib/jvm/java-21-openjdk-amd64
JAVA_HOME_17_X64=/usr/lib/jvm/java-17-openjdk-amd64
JAVA_HOME_11_X64=/usr/lib/jvm/java-11-openjdk-amd64
TARGETARCH=linux-x64
EOF

Confirm the agent folder and timing. Run a diagnostic pipeline on the pool to find the real agent folder, for example ps -ef | grep -i Agent.Listener and echo $(Agent.HomeDirectory) in a script step. If the agent is not yet installed when your script runs, the .env file will not exist at that point and writing to it will have no effect. In that case, check whether the folder is created before or after your script and adjust accordingly.

Make sure the agent restarts after the change. The .env file is only read when the agent starts, so changes must be in place before the agent process starts. Keeping provisioningScriptShouldRestart: true helps here, because the agent starts again after the reboot and picks up the file.

Verify from a pipeline. Run this on the pool to confirm what the task processes see:

steps:
- script: |
    printenv | grep -E 'JAVA_HOME|TARGETARCH'
  displayName: Check env
- task: JavaToolInstaller@1
  inputs:
    versionSpec: '21'
    jvmType: 'x64'
    jdkArchitectureOption: 'x64'
    jdkSourceOption: 'PreInstalled'

JavaToolInstaller@1 with PreInstalled looks for the JAVA_HOME_<version>_<arch> variable, so JAVA_HOME_21_X64 must be present in the task environment for version 21 to resolve.

  1. Fallback if the .env approach does not work on Managed DevOps Pools. Define the variables once in a shared YAML template or a variable group that your client pipelines extend. This is less convenient than a pool-level setting, but it works regardless of how the agent is started. If you want pool-level environment variables as a supported feature, please open a support request or a feature request, since I could not find it documented today.

Useful references:

If this answer helps you kindly accept the answer which will help others who have similar questions.

Best Regards,
Jerald Felix.

Was this answer helpful?

1 person found this answer helpful.
0 comments No comments

1 additional answer

Sort by: Most helpful
  1. Likhitha Sulake 110 Reputation points Microsoft External Staff Moderator
    2026-10-29T18:40:54.3033333+00:00

    Hi @Rowat G@ADM(DS) DEIMS@Defence365 ,

    Thank you for your question.

    The behavior you are seeing is related to how the Azure Pipelines agent receives environment variables. Variables configured in /etc/environment or ~/.bashrc are not necessarily available to pipeline tasks because the agent is not launched through an interactive/PAM login shell.

    Also, any export commands executed inside Setup.sh apply only to that script's current shell session. Once the provisioning script completes, those exported values do not automatically persist into the environment used by subsequent pipeline tasks.

    A possible approach is to make the required variables available through the agent's .env file.

    For example:

    Shell

    AGENT_ROOT="<path to the agent folder on the pool VM>"

     

    cat >> "$AGENT_ROOT/.env" <<'EOF'

    JAVA_HOME=/usr/lib/jvm/java-25-openjdk-amd64

    JAVA_HOME_25_X64=/usr/lib/jvm/java-25-openjdk-amd64

    JAVA_HOME_21_X64=/usr/lib/jvm/java-21-openjdk-amd64

    JAVA_HOME_17_X64=/usr/lib/jvm/java-17-openjdk-amd64

    JAVA_HOME_11_X64=/usr/lib/jvm/java-11-openjdk-amd64

    TARGETARCH=linux-x64

    EOF

    Before implementing this, I recommend confirming the actual agent directory on the pool VM. You can use a diagnostic pipeline to check the agent location, for example:

    Shell

    ps -ef | grep -i Agent.Listener

    echo $(Agent.HomeDirectory)

    The timing is also important. The .env file needs to be available when the agent starts. Therefore, if your provisioning script executes before the agent directory is created, writing the file at that stage may not have the expected result.

    After making the change, ensure that the agent restarts so that it can pick up the updated environment. Since you are already using provisioningScriptShouldRestart:`` ``true, the restart following provisioning may help with this.

    You can then validate what is available to the pipeline using:

    YAML

    steps:

    • script: |

    printenv | grep -E 'JAVA_HOME|TARGETARCH'

    displayName: Check env

     

    • task: JavaToolInstaller@1

    inputs:

    versionSpec: '21'

    jvmType: 'x64'

    jdkArchitectureOption: 'x64'

    jdkSourceOption: 'PreInstalled'

    For JavaToolInstaller@1 with PreInstalled, please make sure the appropriate version-specific variable, such as JAVA_HOME_21_X64, is available to the task environment.

    If the .env approach does not work as expected with Managed DevOps Pools, an alternative would be to define these variables through a common YAML template or variable group shared by the relevant pipelines.

    For additional information, please refer to:

    Azure Pipelines Linux agent documentation

    Managed DevOps Pools settings

    JavaToolInstaller@1 documentation

    I would suggest testing this with one pool first and validating the variables from a pipeline before applying the same approach more broadly.

    Was this answer helpful?


Your answer

Answers can be marked as 'Accepted' by the question author and 'Recommended' by moderators, which helps users know the answer solved the author's problem.