Skip to content
This repository has been archived by the owner on Feb 19, 2019. It is now read-only.

Chocolatey does not recapture PATHs modified by external installer #153

Closed
Iristyle opened this issue Sep 13, 2012 · 35 comments
Closed

Chocolatey does not recapture PATHs modified by external installer #153

Iristyle opened this issue Sep 13, 2012 · 35 comments

Comments

@Iristyle
Copy link
Contributor

Neither cmd, nor Powershell will ever refresh their local copies of environment variables.

This is problematic for a couple of reasons

  • The chocolateyInstall.ps1 may need access to tooling that is now a part of PATH
  • The existing Powershell session must be closed, then reopened to use something that was just installed

The problem here is that Powershell does not "recapture" the environment variables once a session has been started.

So PATH could be modified, after running an installer, but Chocolatey cannot gain access to these without using the .NET System EnvironmentVariable APIs or manually accessing the real location in the registry -- i.e..

(Get-ItemProperty 'HKLM:\SYSTEM\CurrentControlSet\Control\Session Manager\Environment' -Name Path).Path

IMHO, what needs to be done is that the environment needs to be refreshed after a given installer wraps up.

I think that it makes sense to do the recapture after an install runs.

https://github.com/chocolatey/chocolatey/blob/master/src/helpers/functions/Install-ChocolateyPackage.ps1#L63

To recapture any changes made to PATH by external processes.

$Env:PATH = (@(,[Environment]::GetEnvironmentVariable('PATH', 'Machine') -s
plit ';') + @([Environment]::GetEnvironmentVariable('PATH', 'User') -split ';') | Select -Unique) -join ';'
@ferventcoder
Copy link
Contributor

Command is a bit harder, but for powershell you suggested the following:

Env:PATH = (@(,[Environment]::GetEnvironmentVariable('PATH', 'Machine') -s
plit ';') + @([Environment]::GetEnvironmentVariable('PATH', 'User') -split ';') | Select -Unique) -join ';'

@ghost ghost assigned ferventcoder Sep 13, 2012
@ferventcoder
Copy link
Contributor

#134

@ferventcoder
Copy link
Contributor

It's in issue #134

@Iristyle
Copy link
Contributor Author

So I have a couple of questions

  • Is this the most appropriate spot in the codebase to do the environment refresh?
  • Would it make sense to do a full environment refresh? (there may be other variables that these new tools need)
  • Are there are any potential perm issues?

@Iristyle
Copy link
Contributor Author

That PoshCode snippet is craziness... let me (manually) see if it actually works ;0

@ferventcoder
Copy link
Contributor

How do you do a full environment refresh? I would love for that to happen with both powershell and command...

@Iristyle
Copy link
Contributor Author

I can think of 2 ways to do this.. not sure on security implications.

  • Iterate the registry to get all the environment variable names (it wouldn't simply be good enough to look at the names in the current session, because the list could have additions or removals)
  • Launch a new PS session, capture the environment variable state there, and push it back to the initiating session (probably on the slow side)

@ferventcoder
Copy link
Contributor

Install-ChocolateyPath actually pushes the new path...perhaps we can emulate that a bit.

@ferventcoder
Copy link
Contributor

But it won't carry all the way back to the command line. That's what I'm hoping that crazy poshcode will do.

@Iristyle
Copy link
Contributor Author

Ok -- just tried the PoshCode sample...

  • Started a session
  • Manually tweaked my PATH variables in control panel
  • Opened a new session -- verified changes are in new session
  • Verified changes are not in old session
  • Ran crazy PoshCode

Original session does not have the new PATH

So in short, no go.

@ferventcoder
Copy link
Contributor

Boo...

@Iristyle
Copy link
Contributor Author

So if you want to get the keys

#user
Get-Item HKCU:\Environment | Select -ExpandProperty Property

#machine
Get-Item 'HKLM:\SYSTEM\CurrentControlSet\Control\Session Manager\Environment' | Select -ExpandProperty Property

@mwrock
Copy link
Contributor

mwrock commented Sep 13, 2012

I think this might work. Assuming new_var is the environment variable set.

Get-WmiObject Win32_Environment | where-object -filter {$_.Name -eq 'new_var'} | select VariableValue

@Iristyle
Copy link
Contributor Author

Yeah, except how do you know what new_var is if an MSI just ran and added some new stuff? ;0

@ferventcoder
Copy link
Contributor

Need both powershell and cmd shell versions...

@mwrock we'd need to iterate over all of them.

@mwrock
Copy link
Contributor

mwrock commented Sep 13, 2012

Yup. You would have to build a list before the install and then do a delta.

@Iristyle
Copy link
Contributor Author

For cmd -- fun!

http://stackoverflow.com/a/11147132/87793

@ferventcoder
Copy link
Contributor

@ferventcoder
Copy link
Contributor

HA! We found the same article!

@Iristyle
Copy link
Contributor Author

I have used those reg tools before, but I cringe every time I see that old DOS batch style pattern matching stuff. I think the cmd guys had Larry Wall aspirations.

@Iristyle
Copy link
Contributor Author

I think the biggest issue then is the security considerations. As long as I can get to HKLM, the Powershell refresh is pretty straightforward.

@Iristyle
Copy link
Contributor Author

I also need to double check the rules for environment -- i.e. we know that PATH is special cased to munge Machine and User -- but not sure if any other variables are treated specially.

I believe that User variables override Machine variables when the names overlap and there is no special casing like for PATH. Will try a few tests here to be sure.

@Iristyle
Copy link
Contributor Author

Verified - User overrides Machine.

I gave PATHEXT a shot since it has a similar format to PATH. When I defined a User variant, it totally ate the Machine variant.

So unless someone has a definitive resource somewhere about this -- I'm going to assume that only PATH has special treatment.

@rismoney
Copy link
Contributor

say i wrote a helper chocolatey-restart that simply closes the active session and reopens a fresh posh. is this invasive? would it work?

another random thought-maybe wmi event consumers can track the change to env vars...

@mwrock
Copy link
Contributor

mwrock commented Sep 16, 2012

I played with some ideas today and I think I found a way to make this work for all env vars in ps and cmd with little batch ugliness. The gist of it is this. I'd have a Refresh-Environment.ps1 and RefreshEnvironment.bat. The ps1 would do something like:

$newVars=(powershell -outputformat xml -command "Get-WmiObject Win32_Environment | select Name, VariableValue")

What I foud is that you have to either use WMI or go directly to the registry and from a different process. Then it would use the xml api to build a PS dictionary of the environment variables that propperly resolves the system and user variables and does spacial handling on the path via concatenation. Finally it iterates the dictionary and flushes it to the env:\ drive. Then it outputs

gci env:

to standard output.

The bat calls the ps1 and flushes it to a file via >> and uses the

FOR /F "tokens=2,3* delims= " %%i in (vars.txt) do SET %i=%j

Based on some prototype tests, I think this works. I plan to extract this into a separate chocolatey/repo since I think it has usage scenarios outside of chocolatey. The snippits above might not be syntactically perfect but hopefully you get the idea. Hopefully I can get to this before the end of the weekend. Thoughts?

@ferventcoder
Copy link
Contributor

I'm down for it if it works. :D

@Iristyle
Copy link
Contributor Author

I just cooked this up and it works just fine -- no separate process or WMI necessary (I tend to avoid WMI because its just a wrapper on top of other stuff -- with the ability to fail due to DCOM issues, etc)

This is for Powershell only, not cmd.

https://gist.github.com/3732568

@mwrock
Copy link
Contributor

mwrock commented Sep 16, 2012

Very nice. Plugged that into my test simulator and it works. I think adding the batch compatibility should be straight forward by having this output the new vars to std out and then having a .bat call that and taking the FOR strategy I mentioned above.

@Iristyle
Copy link
Contributor Author

I'm just about done with a pull req.. just trying to get the unit tests to run under your test suite properly.

Will kick it off just so you guys can have a look, but don't pull it quite yet ;0

@Iristyle
Copy link
Contributor Author

Also note that I may have the wrong spot for integration into Chocolatey.. I'll let you guys sort that part out if it's in the wrong spot.

Iristyle@8515ce2#L0R63

@mwrock
Copy link
Contributor

mwrock commented Sep 16, 2012

Yeah I think this should probably go into Chocolatey-Nuget instead of Install-ChocolateyInstallPackage so it can be applied to all install scenarios.

@Iristyle
Copy link
Contributor Author

Roger that -- will fix.

@Iristyle
Copy link
Contributor Author

Pull updated with tests that work properly now...

@mwrock
Copy link
Contributor

mwrock commented Sep 16, 2012

Great job! I'll add in the batch file version later unless someone else beats me too it.

@mwrock
Copy link
Contributor

mwrock commented Oct 14, 2012

I'm closing this since it was essentially fixed with fd8b079. That should allow chocolatey (but not the caller) to use paths set by installers. There is another issue for the caller: #134

@mwrock mwrock closed this as completed Oct 14, 2012
ferventcoder added a commit to ferventcoder/chocolatey that referenced this issue Jun 16, 2014
…md.exe

This adds a command RefreshEnv.cmd to the bin files, so that one can update
environment variables out of band. There is zero chance it will work once
chocolatey.cmd calls exit /b %ERRORLEVEL% as exiting the batch effectively
destroys any updates to local environmental changes. The way it currently
works is effectively the same as using setlocal due to the use of exit.

Since this command can be called out of band, it should be called out of
band, whenever the user wants to refresh their environment variables they
can call this. Note this only works in cmd.exe shell. There is no current way
to update a powershell session other than importing the helper functions as
a module and running Update-SessionEnvironment.
ferventcoder added a commit to ferventcoder/chocolatey that referenced this issue Jun 16, 2014
* stable:
  (chocolatey-archiveGH-460) Fix for "Package depending on newer chocolatey is installed using existing chocolatey"
  (chocolatey-archiveGH-459) Fix for "Cannot find Update-SessionInformation"
  (maint) formatting
  (chocolatey-archiveGH-153)(chocolatey-archiveGH-134) Update PATH on cmd.exe
  (maint) ensure powershell module loading preference is on
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Projects
None yet
Development

No branches or pull requests

4 participants