1

I'm writing a Powershell script to configure a build environment and then carry out the build. This entails setting the system path so that it includes the compiler and build system (in this case, qmake and mingw32-make), and then proceeding with the build.

I've set things up so that the function for modifying the system path, broadly based on this reference, is in a separate file like this:

Function AddTo-UserPath
{
    Param
    (
        [Parameter(mandatory=$true)]
        [System.IO.DirectoryInfo[]]$PathsToAdd
    )

    $MachinePath = [System.Environment]::GetEnvironmentVariable('PATH','Machine')
    $UserPath = [System.Environment]::GetEnvironmentVariable('PATH','User')
    $VerifiedPathsToAdd = $Null
    $MachinePathArray = $MachinePath -Split ‘;’ -replace ‘\\+$'
    $UserPathArray = $UserPath -Split ‘;’ -replace ‘\\+$'
    Foreach ($PathToAdd in ($PathsToAdd | % { $_.FullName.TrimEnd(‘\’) } ) )
    {
        if($MachinePathArray -contains $PathToAdd)
        {
            Write-Verbose “$PathToAdd already exists in Machine Path”
        }
        elseif($UserPathArray -contains $PathToAdd)
        {
            Write-Verbose “$PathToAdd already exists in User Path”
        }
        else
        {
            $VerifiedPathsToAdd += ";$PathToAdd"
        }
    }

    if($VerifiedPathsToAdd -ne $null)
    {
        [Environment]::SetEnvironmentVariable('PATH', $UserPath + $VerifiedPathsToAdd, 'User')
    }
}

...so that in my main script file I can write:

# Load the module containing the AddTo-UserPath function
Import-Module $PSScriptRoot\..\ps1utils\myfunctions.ps1

# Add the required directories to the system path
AddTo-UserPath C:\Qt\Tools\mingw530_32\bin, C:\Qt\5.9.7\mingw53_32\bin

# Start the build
qmake qwt.pro
mingw32-make -j
mingw32-make -j install

If I run my script from the Powershell ISE, I can put a breakpoint at the 'qmake' line and verify from the Windows GUI that my path has been modified as required; I can even pop open a separate cmd window and run qmake and mingw32-make quite happily. My script, however, gives me the errors:

qmake : The term 'qmake' is not recognized as the name of a cmdlet, function, script file, or operable program.
mingw32-make : The term 'mingw32-make' is not recognized as the name of a cmdlet, function, script file, or operable program. 

...and if I check the value of $env:Path then sure enough it doesn't reflect the changes that I've just made.

In a way this isn't surprising; I've read plenty of times that if you change the system path from within a Powershell window then you have to close and reopen the window for the change to take effect. The problem is that I can't figure out how to work around it from within my script - the whole point of doing this is to automate my build process, so it's hardly appropriate for me to have to manually close one Powershell window and open up another one before my script can proceed. There has to be a better way.

One thing that occurred to me was that maybe I needed to spawn a new process, so I tried putting my build commands into a separate script file and writing:

AddTo-UserPath C:\Qt\Tools\mingw530_32\bin, C:\Qt\5.9.7\mingw53_32\bin
powershell -file TheRestOfMyBuildProcess.ps1

...but that didn't work either.

So now I'm out of ideas, I haven't been able to find a solution online, and I'd love to know what's the proper way to do this.

1 Answer 1

1

Changing the PATH in PowerShell is isolated to the current session and is only temporary, which is what you are seeing.

You may make a permanent change to the PATH environmental variable by changing it directly in the registry. All variables are stored under the registry key HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\Session Manager\Environment.

A PowerShell script to add to PATH will look like :

$oldPath=(Get-ItemProperty -Path 'Registry::HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\Session Manager\Environment' -Name PATH).Path

$newPath=$oldPath+’;C:NewFolderToAddToTheList’

Set-ItemProperty -Path 'Registry::HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\Session Manager\Environment' -Name PATH –Value $newPath

You will need to restart PowerShell to see the change, but from now on all applications will use the updated PATH.

This was found in the "Hey, Scripting Guy! Blog" article Use PowerShell to Modify Your Environmental Path, where you will find more information and ideas.

Another useful post is Reload the path in powershell where the following syntax was proposed:

$env:Path = [System.Environment]::GetEnvironmentVariable("Path","Machine") + ";" + [System.Environment]::GetEnvironmentVariable("Path","User") 
5
  • Thank you for your answer, but I'm afraid it doesn't help me. What I'm seeing is nothing to do with the path change being temporary. Because I do it using the .Net SetEnvironmentVariable command, it is in fact permanent; I have tested this carefully. The problem is simply that Powershell doesn't see the updated path. What I need is a way to force Powershell to see it, even if that means programmatically restarting Powershell and continuing my script. Since Powershell is supposed to be all about automation, it's hard to believe there's no way of automating a build like this, Nov 5, 2018 at 0:19
  • You need to restart Powershell to recreate the PATH, but not as a child of the current script, since the child inherits the parent's environment. I have added a possible solution for reloading the PATH in the current session after a permanent change.
    – harrymc
    Nov 5, 2018 at 9:38
  • That looks much more promising, but I'm afraid I'll be unable to try it out for 24 hours or so; I'll let you know if it does the trick, and accept your answer if so. Nov 5, 2018 at 21:21
  • No hurry and good luck.
    – harrymc
    Nov 5, 2018 at 21:24
  • Yes, that's nailed it. I'll accept your answer now. Nov 6, 2018 at 21:37

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .