0

I'm writing a script that is trying to install CUDA and set environment variable. As result, it also should check that CUDA is installed successfully. As this check, I run nvcc -V to get compiler version. Unfortunly, for some reason it doesn't work until I open another shell window. But I strongly need exactly that behaviour, because I have to actually run nvcc in the same session.

Here is my script:

param([Parameter(mandatory=$true)][string] $FileName)
$VERSION = "9.1"
$argumentList = "-s nvcc_$VERSION cublas_$VERSION cublas_dev_$VERSION cufft_$VERSION cufft_dev_$VERSION npp_$VERSION npp_dev_$VERSION"
$envPath = ";%ProgramFiles%\NVIDIA GPU Computing Toolkit\CUDA\v$VERSION\bin;%ProgramFiles%\NVIDIA GPU Computing Toolkit\CUDA\v$VERSION\libnvvp";
Write-Host "Install CUDA from $FileName with argumentList $argumentList"
Start-Process -FilePath $FileName -ArgumentList $argumentList -Wait

#adding CUDA to PATH
[Environment]::SetEnvironmentVariable("Path", $env:Path + $envPath, [EnvironmentVariableTarget]::Machine) 

#updating PATH for current session
$env:Path = [System.Environment]::GetEnvironmentVariable("Path","Machine") 

#trying to run something
nvcc -V 

But it shows an error

The term 'nvcc' is not recognized as the name of a cmdlet, function, script file, or operable program. Check the spelling of the name, or if a path was included, verify that the path is correct and try again.

How can it be done?

enter image description here enter image description here

PS C:\Users\SOLO> $PSVersionTable

Name                           Value
----                           -----
PSVersion                      5.1.16299.98
PSEdition                      Desktop
PSCompatibleVersions           {1.0, 2.0, 3.0, 4.0...}
BuildVersion                   10.0.16299.98
CLRVersion                     4.0.30319.42000
WSManStackVersion              3.0
PSRemotingProtocolVersion      2.3
SerializationVersion           1.1.0.1
Alex Zhukovskiy
  • 9,565
  • 11
  • 75
  • 151
  • This [post](https://stackoverflow.com/questions/17794507/reload-the-path-in-powershell) reloads the path for `("Path", "Machine")` **and** `("Path", "User")` - does that help? – Jelphy Jan 16 '18 at 13:34
  • Provided code does exactly same thing. – Alex Zhukovskiy Jan 16 '18 at 13:36
  • `$env:Path + $envPath` -> `"${env:Path};${envPath}"` – Ansgar Wiechers Jan 16 '18 at 14:15
  • @AnsgarWiechers no effect – Alex Zhukovskiy Jan 16 '18 at 15:01
  • I doubt that. Please provide evidence. – Ansgar Wiechers Jan 16 '18 at 15:08
  • @AnsgarWiechers ok, see edit. Line 9 is not working while line 10 does. – Alex Zhukovskiy Jan 16 '18 at 15:11
  • 1
    The PowerShell ISE is a fertile source of problems that don't happen in actual scripts. For completeness, try it again from a PowerShell window with the script in a `.ps1`. Tweaking `$env:path` works in my PS 5.1 window. – Jeroen Mostert Jan 16 '18 at 15:17
  • @JeroenMostert I actually don't use ISE, I just did it for screenshot to show that I have used the right version of the code. If you want shell execution - no problem, see edit. – Alex Zhukovskiy Jan 16 '18 at 15:20
  • Oh, waitaminute -- I only now see that you're using `%ProgramFiles%`. The `%ProgramFiles%` expansion stuff is only supported by CMD and by Windows on launching a new process; if you do this from PowerShell you'll put a *literal* `%ProgramFiles%` in, which of course doesn't work. I vaguely remember there is a question on SO that shows how to expand this stuff outside CMD/Windows, but not where it is or if it covers PowerShell. Consider just using `[Environment]::GetFolderPath("ProgramFiles")` instead (or `$env:ProgramFiles`, but I don't remember if there's 32/64-bit issues). – Jeroen Mostert Jan 16 '18 at 15:27
  • @JeroenMostert I thought it works becasue Windows itself is widely using other environment variables in PATH, for example: https://imgur.com/a/yYhil . But I feel that you are right, trying to replace it with actual path. – Alex Zhukovskiy Jan 16 '18 at 15:31
  • @JeroenMostert yep, you are right. `%ProgramFiles%` is working, but after shell reboot only. If I want to use it from this session, I have to use `$env:ProgramFiles\NVIDIA GPU Computing Toolkit\CUDA\v$VERSION\bin;$env:ProgramFiles\NVIDIA GPU Computing Toolkit\CUDA\v$VERSION\libnvvp` – Alex Zhukovskiy Jan 16 '18 at 15:34
  • 1
    @JeroenMostert The problem is not the `%ProgramFiles%` *per se*, but that `SetEnvironmentVariable()` writes the registry value as a REG_SZ (even if it was a REG_EXPAND_SZ before). Windows expands `%`-variables in registry values only for REG_EXPAND_SZ values. – Ansgar Wiechers Jan 16 '18 at 15:50
  • @AnsgarWiechers: that's *almost* the complete story. If you were to invoke `Environment.SetEnvironmentVariable` with a target of `Process`, the registry is not involved; instead it devolves to [`SetEnvironmentVariable`](https://msdn.microsoft.com/library/windows/desktop/ms686206), which performs no expansion either (and neither does `GetEnvironmentVariable`). As it so happens, we've got `Environment.ExpandEnvironmentVariables` to work around that case. Not relevant here since we already know we want the registry and `%ProgramFiles%`, but possibly useful in other cases. – Jeroen Mostert Jan 16 '18 at 16:00

1 Answers1

1

Your problem is caused by the combination of [Environment]::SetEnvironmentVariable() and %ProgramFiles%. The SetEnvironmentVariable() method writes the corresponding registry value as a REG_SZ, meaning that environment variables in that string (like %ProgramFiles%) won't be expanded when the variable is used.

If you want to keep using %ProgramFiles% write the registry value as a REG_EXPAND_SZ:

$regkey = 'HKLM:\SYSTEM\CurrentControlSet\Control\Session Manager\Environment'
Set-ItemProperty -Path $regkey -Name 'Path' -Value "${env:Path};${envPath}" -Type ExpandString

Otherwise use $env:ProgramFiles instead of %ProgramFiles%, so that the variable is written with the paths already expanded:

$envPath = "$env:ProgramFiles\NVIDIA GPU Computing Toolkit\CUDA\v$VERSION\bin;$env:ProgramFiles\NVIDIA GPU Computing Toolkit\CUDA\v$VERSION\libnvvp";
[Environment]::SetEnvironmentVariable("Path", "${env:Path};${envPath}", [EnvironmentVariableTarget]::Machine)
Ansgar Wiechers
  • 193,178
  • 25
  • 254
  • 328