December 12th, 2023

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

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.

Author

Raymond has been involved in the evolution of Windows for more than 30 years. In 2003, he began a Web site known as The Old New Thing which has grown in popularity far beyond his wildest imagination, a development which still gives him the heebie-jeebies. The Web site spawned a book, coincidentally also titled The Old New Thing (Addison Wesley 2007). He occasionally appears on the Windows Dev Docs Twitter account to tell stories which convey no useful information.

4 comments

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

  • Petri Oksanen

    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

        Oh, you are right, this whole thing:
        <code>
        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...

        Read more