What happens if I define one environment variable in terms of the value of another environment variable?

Raymond Chen

In Windows, you can call up the Environment Variables dialog box to edit both the System environment variables and the User environment variables. What happens if you use the % sign to reference one environment variable from another?

Environment variable processing occurs in several steps.¹

  • Core system environment variables: ALLUSERSPROFILE, ProgramData, PUBLIC, SystemDrive, SystemRoot.
  • System environment variables of type REG_SZ.
  • System environment variables of type REG_EXPAND_SZ.
  • Core user environment variables: APPDATA, COMPUTERNAME, LOCALAPPDATA, ProgramFiles, USERPROFILE.
  • User environment variables of type REG_SZ.
  • User environment variables of type REG_EXPAND_SZ.
  • Account environment variables: USERDNSDOMAIN, USERDOMAIN, USERNAME.

The rule is that each step can redefine variables set by a previous step, and variables of type REG_EXPAND_SZ can depend on variables set by a previous step, but cannot depend on variables set elsewhere within the same step or by a future step.

This means, for example, that you can use %USERPROFILE% in the definition of a User environment variable of type REG_EXPAND_SZ,, but not in the definition of a System environment variable.

There is a bonus special rule for the PATH environment variable: The User definition of the PATH environment variable is appended to the System definition, rather than replacing it.²

If you have a REG_EXPAND_SZ between variables at the same step, it is unspecified whether the expansion is the old value or the new value, so don’t do that.³

¹ This is a simplified discussion for the purpose of exposition.

² This special rule also applies to the vestigial LibPath and Os2LibPath environment variables.

³ To avoid people taking dependencies on implementation details, I would have enforced the rule more strictly and consistently and said that all REG_EXPAND_SZ expansions use the value of the variable as defined by previous steps, and any changes made in the same step are not visible. But of course the implementation was written before the realization that people would try to create dependencies among variables in the same group.

4 comments

Discussion is closed. Login to edit/delete existing comments.

  • Petri Oksanen 0

    There is also this limitation with environment variable assignments that I recall from bat-files:

    @echo off
    setlocal
    
    (
    set VAR1=foo
    set VAR2=%VAR1%bar
    )
    
    echo %VAR2%
    

    This will output “bar”, not the expected “foobar”.
    Has this kind of limitation been retained over the decades for legacy compatibility?

      • Petri Oksanen 0

        Oh, you are right, this whole thing:

        @echo off
        setlocal ENABLEDELAYEDEXPANSION
        
        (
        set VAR1=foo
        set VAR2=!VAR1!bar
        )
        
        echo %VAR2%

        It correctly prints “foobar”.
        This was so many years ago, I’ve forgotten the details.
        I think this was covered in the Windows NT Workstation Resource Kit book, that would had been where I had studied this back then, because I looked now in my old Windows NT and Windows 2000 pocket reference books from O’Reilly that I still have left, and it’s not mentioned in either of them.
        Bat-files of course have a use but they are frustratingly primitive so I started installing ActivePerl on all Windows machines under my control from 2000 onwards.
        Nowadays it’s all Powershell against the cloud tenant, except if I need to do some onetime processing with regular expressions, nothing beats “perl -wne” for that. 🙂

Feedback usabilla icon