Why is the Powershell Environment PATH different to the System Environment PATH? - powershell

I'm having this weird situation :
My user's and system's PATH variable is different than the PATH in powershell.
When I do :
PS C:\$env:path
C:\Windows\System32\WindowsPowerShell\v1.0\;c:\oldpath
However this is not correct, it looks like it stuck on some old PATH variable of my system, so none of the udpates I've done on it didn't change this variable (I do restart after every change to test).
Why is this happening? Do I have to set a PATH variable just for powershell?

The change might be "delayed", so try one or more of these solutions:
Log off and on again;
Task Manager > Restart "Windows Explorer" (explorer.exe)
Restart your launcher app (launchy, SlickRun, etc)
Reboot
Explanation:
Powershell will inherit the environment of the process that launched it (which depends on how you launch it). This is usually the interactive shell (explorer.exe). When you modify the environment from computer properties, you modify the environment of explorer.exe, so if you launch powershell from explorer.exe, (for example from the start menu) you should see the new environment.
However, if you launch it from something else (say a cmd.exe shell that you already had opened), then you won't since that process was launched under the old environment.
In other words: be careful how you are launching things.

In my case, I installed an app that incorrectly added itself to the PATH by creating a powershell profile that would override $env:PATH and blow out the existing configuration every time I started powershell.
Check if you have profile at USER\Documents\WindowsPowerShell\Microsoft.PowerShell_profile.ps1 and if it's doing anything fishy like setting $env:PATH.

Related

Powershell IDE: How to restart interactive shell to clear all variables without leaving Powershell ISE?

Let's say I've been using Powershell ISE for a while and my environment space is starting to get dirty, and I need to restart the interactive shell... I don't want to close my editor and reopen it. How to restart powershell ISE interactive shell to clear all variables without closing and reopening the Powershell ISE?
First, the obligatory notice:
The PowerShell ISE is no longer actively developed and there are reasons not to use it (bottom section), notably not being able to run PowerShell (Core) 6+.
The actively developed editor that offers the best PowerShell development experience, across PowerShell editions and platforms, is Visual Studio Code, combined with its PowerShell extension.
ISE:
Colin's helpful answer is a pragmatic solution: open a new tab and close the old one.
However, that new session invariably retains the environment variables of the old one, because the ISE hosts the PowerShell SDK in-process rather than running powershell.exe as a child process.
To restart a session in the current tab you would therefore have to instruct the hosted System.Management.Automation.PowerShell instance to discard its current runspace and create a new one - and I'm not aware of a way to do this.
Even if it were possible, however, the environment variables - which exist at the level of the process that runs the ISE - would be retained.
Visual Studio Code:
It is possible to start a new session in the current tab and to do so without inheriting the old session's environment variables:
While the integrated terminal running is running the PowerShell Integrated Console, which the PowerShell extension comes with - which is the equivalent of the console pane in the ISE - you can kill the current instance by clicking the trash-can icon in the toolbar of the terminal panel as shown below.
After doing so, you're prompted for starting a new session, which runs in a new powershell.exe / pwsh child process.
Alternatively - and preferably - you can configure the PowerShell extension to automatically start a new session whenever you start a new debugging session, as zett42 points out:
Either: Open the Settings (Ctrl-,) view, search for powershell temporary and turn on the PowerShell > Debugging: Create Temporary Integrated Console setting.
Or: Add "powershell.debugging.createTemporaryIntegratedConsole": true directly to your settings.json file.
This automatically starts a new, temporary PowerShell Integrated Console for each debugging session, which remains open until you start the next debugging session, at which point a new temporary console simply replaces the old one.
Curiously, as of extension version 2022.11.0, you cannot exit out of a PowerShell Integrated Console, but you can use the trash-can icon or Stop-Process -Id $PID to kill it, if needed, which in the case of a temporary console will (commendably) not prompt you to restart it; instead, the next debugging session will create a new, temporary console on demand.
This configuration avoids a major pitfall that afflicts the ISE invariably (and may in part be what prompted the question) as well as the PowerShell extension's default configuration:
There, the code runs dot-sourced, i.e. directly in the top-level scope of the same session, so that the state left behind by earlier debugging runs can interfere with subsequent debugging runs; for instance, create a script with content (++$i) and run it repeatedly - you'll see that $i increments every time, across runs.
Starting a new session for every debugging run avoids this problem.
Ctrl+t opens a new powershell tab that starts as if it was a fresh powershell session.
Try either 1 of below to clear variable memory , it shall help
exit # Exit will quit from Powershell.
Get-Variable -Exclude PWD,*Preference | Remove-Variable -EA 0 # this will kill all the memory on current session

PowerShell can't "dot source" profile following system cleaning

I have a problem where PowerShell will no longer run my Microsoft.Powershell_profile.ps1/Profile.ps1 script stating it can't "dot source" the file. This started after I ran a registry cleaner and system optimizer on my machine. Now, I can't figure out what setting has changed, been added, or revoked.
Things to note:
The console always defaults to 'ConstrainedLanguage' because of the attempt to "dot source"
I have tried setting the -ExecutionPolicy to both "Unrestricted" and "RemoteSigned" to no effect
Issue exists in both version 5 & 6
If I run the "PowerShell Integrated Console" in VS Code, as opposed to in the terminal window, it runs fine showing "FullLanguage"
The contents of the profile file do not matter - if I use an empty file, it still won't run.
Placing "Microsoft.Powershell_profile.ps1" in the "\documents" folder does NOT produce a "dot source" error, however it also doesn't recognize any commands from within the profile script.
Things I have tried:
Setting to "FullLanguage" via $ExecutionContext.SessionState.LanguageMode = 0 results in "Cannot set property. Property setting is supported only on core types in this language mode."
Setting the "__PSLockdownPolicy" property to 0 in the registry at "HKLM:\SYSTEM\CurrentControlSet\Control\Session Manager\Environment\" does nothing for v5 and crashes v6
Moving the profile file between $home, "\documents", and $pshome (location dependent on version) to no effect (with the above exception)
Adjusting name between "Microsoft.Powershell_profile.ps1" and "Profile.ps1" (normally adjusted to match intended audience ("All Users", for example) but am trying variations in hopes of making work)
Uninstalling and re-installing different 5.x and 6.x versions to no effect
Running "Powershell -noprofile" doesn't load the profile, so no error but still runs in "ConstrainedLanguage"
Verified AppLocker is not running / has not rules in place
Verified Controlled Folder Access is off
Any help would be appreciated.

Files: bash_profile zhrc confusion

I am not sure this is clear to me and if is neat for my system. I'm aware of the ~/.zhrc file where I can store alias and paths, but today after installing node via brew I was asked to put this: export PATH="$HOME/.npm-packages/bin:$PATH" in my ~/.bash_profile file, which it doesn't exist, thus in my effort to keep my system clean I putted it in the former file but emacs complaint. Now, I removed it and putted it, after creating, in the ~/.bash_profile. Is that OK to keep both in the home directory?
You need to provide the exact wording of whatever error or warning message you
get from emacs to ensure accurate or better answers. However, I will make a
guess and assume the warning you are getting is from the exec-path package.
This package has a check, which you can disable, that looks to make sure you
have variables defined in the correct init file.
In general, most shells support two types of configuration files
Startup or Login init files
Interactive shell init files
The difference is how often or when the files are sourced (loaded). To
understand the difference, you really need to understand when a shell is run and
the relationship between each shell. I'll try to give a vary high level
explanation, but you really should read the manual page for the particular shell
you are using.
Think of your environment as a tree of shell processes. When you login to the
system, a login shell is created. This shell will be the parent of all the other
shells you create. Each time you run a command, it is executed in a new shell
(this isn't 100% accurate, but is accurate enough to explain the main
points). So when you open a terminal, it runs another shell which is a child of
your login shell. When you execute various commands, the system creates a new
shell and runs that command inside the shell. These are all children of your
parent login shell. Some shells only exist for a short period of time (as long
as it takes to execute the command), others may last for hours, days or possibly
weeks (such as the shell that emacs is running in).
The important point to keep in mind is that child shells inherit various
settings from the parent shell. The idea of the 'export' command you will see in
front of some variables is actually a command to the shell telling it to export
the variable to child shells. For example, if we have a line like
export PATH=/usr/local/bin:/usr/bin:/bin
what we are really doing is
PATH=/usr/local/bin:/usr/bin:/bin # set the variable
export PATH # make it available in child shells
We don't always want variables to be exported as some variables need to be reset
in the child shell itself. For example, the variable holding the prompt string.
It would not work to have this variable only defined in the login parent shell
if you want the prompt to have dynamic components, such as the current
directory, date or time. We want these types of variables to be defined in each
shell when it is created.
To handle this, shells have the two different init files. The login init files
are only sourced for the parent shell and are particularly useful for setting
variables that will be common to all child shells. the per-shell init files are
sourced for every new shell and are best used for setting things which need to
be updated or changed each time a shell is started. There are also other shell
configuration files which can be used for other special purposes, such as when
you log out or log off a system, or to just put alias definitions in etc.
Once upon a time, it made a big difference where you put your variables as there
was a performance hit when sourcing these init files. If the per-shell init file
was too large and consumed too many resources, the whole performance of your
environment could be affected. This is largely less of an issue these days due
to increased processing speeds. Unfortunately, because many people didn't
understand the role and relationships between the different shell configuration
files, there is lots of incorrect or misleading information out there regarding
where values should be set. People often advise setting variables in (for
example) bashrc when they should be set in the bash__profile=. The confusion is
partly caused by the fact you can add a variable to bashrc and it will work when
you test it (usually because your test involves forking a new child shell) and
putting it in your bash_profile will only work after the next login.
There are also some platform differences which make things a little less
clear. For example, under OSX, there is actually a special file in the /etc
directory where you should add additional path components (I'm not on a mac just
now, but it is something like /etc/paths or a per path component file in
/etc/path.d). This is done so that you have a global place to set paths which
will ensure desktop processes, such as the dock, which do not run as a child
process of your login shell, are able to be set.
As a general rule, most variables can go in the login profile, with the
exception of variables relating to the prompt or other variables which have a
dynamic content i.e. content which changes depending on time, directory
location or other tracking of interactive actions which are specific to a shell
instance.
Setting of the path (noting OS differences as described above) should go into
the profile or login configuration file. Under bash, this is .bash_profile and
under zsh, it is typically .zprofile. As bash has become the most common shell,
documentation etc often advises adding things to .bash_profile. If your running
zsh, then add the same information using .zprofile.
As you have said you don't have a.bash_profile, but you do have a zshrc file, I
am assuming you are running zsh rather than bash as your login shell. This being
the case, you need to add that path setting to .zprofile in your home
directory. The exec-path package is complaining because you added it to
zshrc/bashrc, which are not the correct place to set path variables. If your
running under OSX, you really need to add the path to the correct file in /etc
(you will need to check the OSX documentation as I cannot remember the precise
filename).

lost PATH while trying to set custom winlogon shell in WindowsXP

I have changed the shell key in windows registry to gain custom shell (Kiosk usage):
[HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows
NT\CurrentVersion\Winlogon]
I set shell key to a batch file which runs two applications as below:
start "myFirstAppTitle" "myAppPath\myApp1.exe"
start "mySecondAppTitle" "myAppPath\myApp2.exe"
Each application runs but the second application which needs some files to be excuted throws an error which says could not find dependency files. whereas the dependency files are adjoining to the exe file and the mentioned app works fine, when starts from startup.
Meanwhile when i run the batch file manually it rusn fine.
I added the PATH command to the batch file but it did't work too.
Change the batch file to this:
set PATH=%PATH%;C:\MyAppPath
start "myFirstAppTitle" "myApp1.exe"
start "mySecondAppTitle" "myApp2.exe"
If you start executables without an absolute path, the path is relative to the current working directory. Also, when you specify an executable with a relative path, %PATH% is not searched for a matching subfolder with a matching executable.
Since the script worked when you manually started it, your working directory probably was C:\. However, when run at logon as a replacement shell, the working directory is most likely "%SystemRoot%\system32".
The problem solved strangely, i removed the title parameter of start command and it worked. In fact i used start command this fashion:
set PATH=%PATH%;C:\MyAppPath
start myapp.exe
start myapp2.exe

Refresh $env:path in Powershell?

I have a PowerShell script that checks that a certain directory is on the PATH (by looking through $env:path). It appears that $env:path is loaded and locally scoped by each application on startup, and that scope is passed on to any child applications. So... if someone opens Firefox, downloads my program, runs it, gets a message that they should change their path, fixes the problem, then runs the program again from the Firefox downloads window, they'll get the same message, unless they start my program from Explorer or restart Firefox.
Is there a way to reload $env:path in my PowerShell script so it'll get the current value, as if it were opened from Explorer?
If you were running outside the context of a browser I would tell you to use
[System.Environment]::SetEnvironmentVariable(string name, string value, EnvironmentVariableTarget target)
to change the Path variable for the user. That third parameter allows you to specify Process, User or Machine. If you specify either User or Machine the change is permanent and will appear in the env blocks of all programs that start after that. However, since you are running within the browser I don't think you would be able to do that.
If the user changes their path, that change will be available to future instances of the browser. Another option is to test (Get-Command) for the app you need in the path and if you can't find it, modify $env:Path yourself in the script each time it runs. That is, unless you don't know what the path should be.