Search code examples
powershellenvironment-variablesindirection

set Windows Enviromental variable with a local powershell variable


I am trying to set and view windows enviromental variables using locally defined variables. Actual code I tried.

   $strAllowGPU_Group   = "TF_FORCE_GPU_ALLOW_GROWTH"
    $strAllowGPU_True   = "True"
    $strUserEnvs        = "User"
    $strCUDAPath =  "C:\Program Files\NVIDIA GPU Computing Toolkit\CUDA\v11.8\bin"
    $strCheckForCUDA = "C:\Program Files\NVIDIA GPU Computing Toolkit\CUDA"
    $strWhat = $env:${strAllowGPU_Group}
    [System.Environment]::SetEnvironmentVariable(${strAllowGPU_Group},${strAllowGPU_True}, ${strUserEnvs})

I recceive the following error message.

At C:\Users\pgmrdlm\My Drive (pgmrdlm@gmail.com)\DSLR Notes and backup\Software\Scripts\CudaForPixinsight\CudaForPixinsight.ps1:50 char:13

  • $strWhat = $env:${strAllowGPU_Group}
    
  •            ~~~~~ Variable reference is not valid. ':' was not followed by a valid variable name character. Consider using ${} to
    

delimit the name. At C:\Users\pgmrdlm\My Drive (pgmrdlm@gmail.com)\DSLR Notes and backup\Software\Scripts\CudaForPixinsight\CudaForPixinsight.ps1:50 char:18

  • $strWhat = $env:${strAllowGPU_Group}
    
  •                 ~~~~~~~~~~~~~~~~~~~~ Unexpected token '${strAllowGPU_Group}' in expression or statement.
    
    • CategoryInfo : ParserError: (:) [], ParseException
    • FullyQualifiedErrorId : InvalidVariableReferenceWithDrive

This works, and it does exactly what I want. Create a persistant windows variable:

[System.Environment]::SetEnvironmentVariable('TF_FORCE_GPU_ALLOW_GROWTH','True', 'User')

I know this is nothing but me not coding the variable names correctly, but I appoligise. I just don't have a clue.

Thank you in advance.

Dan


Solution

  • tl;dr

    • $env:${strAllowGPU_Group} is invalid syntax: you cannot indirectly access an environment variable this way, via a name stored in another variable (${strAllowGPU_Group})
      Use Get-Content -ErrorAction Ignore Env:$strAllowGPU_Group
      (if you know that the variable to exists, you can omit -ErrorAction Ignore).

    • To test if an environment variable whose name is stored in variable ${strAllowGPU_Group} is defined, use:
      Test-Variable Env:${strAllowGPU_Group}
      (same as: Test-Variable Env:$strAllowGPU_Group and
      Test-Variable "Env:$strAllowGPU_Group")


    Background information:
    • Fundamentally, what follows $ must be a verbatim identifier, optionally prefixed by a verbatim namespace.

      • That is, you cannot indirectly refer to a variable, via its name being stored in another variable with this syntax.

      • Therefore, $env:${strAllowGPU_Group} cannot work, given that what follows env: must be a verbatim environment-variable name.

    • As for the incidental aspect of using {...} around a variable name in a PowerShell variable reference:

      • {...} is only necessary if:

        • (a) if the name contains unusual characters;[1] e.g.:

          • ${a.b} = 'foo'; ${a.b} - unusual variable name a.b requires enclosure in {...}
        • (b) inside an expandable (double-quoted) string ("..."), if the characters following the variable name in the string would otherwise be mistaken for being part of the variable name; e.g.:

          • $var='foo'; "A ${var}l and his money are soon parted." - without {...}, PowerShell would try to reference a variable named varl
      • However, you're free to always use {...}:

        • $foo_bar = 'baz'; ${foo_bar} - $foo_bar is sufficient, but ${foo_bar} works too.
      • If you do use {...}, it must enclose both the namespace prefix[2] (if present) and the variable name:

        • E.g., $env:HOME is the same as ${env:HOME}
        • By contrast, $env:{HOME} is broken syntax.

    Solutions:

    To use variable indirection with environment variables, i.e. to access them via their name being stored in another variable, you must use cmdlets that access the Env: drive:

    • To test if an environment variable whose name is stored in $strAllowGPU_Group (aka ${strAllowGPU_Group}) exists, use the following:

      Test-Path Env:$strAllowGPU_Group
      
      • Note: This assumes that $strAllowGPU_Group has a non-empty value; if $strAllowGPU_Group evaluates to $null (including when no such variable is defined) or the empty string, the command invariably returns $true.
    • To get the value of the environment variable whose name is stored in variable $strAllowGPU_Group:

      Get-Content -ErrorAction Ignore Env:$strAllowGPU_Group
      
    • To set the value of the environment variable whose name is stored in variable $strAllowGPU_Group:

      Set-Content Env:$strAllowGPU_Group 'new value' 
      

    Note:


    [1] For the exact rules, see the relevant section of the conceptual "about_Variables" help topic, Variable Names that Include Special Characters

    [2] For more information about PowerShell's namespace variable notation, see this answer.