How to change PowerShell default module installation folder? - powershell

Is there a way to change PowerShell module installation folder (the folder that modules are placed after Install-Module)?
This is why I want to do this:
I'm on Windows 10, PowerShell 5.1.17763.503
My default installation folder is Documents\WindowsPowerShell\Modules
My Documents folder have been moved to a location containing , symbol (corporate policies)
PS has a bug loading .ps1 that contain classes and have , in the file path (similar to this issue.)
What I've tried:
I thought the installation folder is the first folder in the $env:PSModulePath and I can change it. When I've opened "Edit System Environment Variables" I saw the installation folder is not in the $env:PSModulePath. It's automatically added on the variable when you start PowerShell.

There is no way to change the behaviour of Install-Module so it installs modules in a custom path.
However, You can use Install-Module [...] -Scope AllUsers to install the modules for all users. This would install the modules in $env:ProgramFiles\PowerShell\Modules, but this operation requires elevated permissions (a.k.a. Local Administrator rights).
If you download and install modules to a custom path yourself (or use an alternative implementation to Install-Module), you can modify $env:PSModulePath as you wish.
You can use a profile to patch the $env:PSModulePath every time you start a PowerShell session by adding this to one of your profiles:
# Prepend custom module path.
$env:PSModulePath = ((#("C:\mymodulepath") + ($env:PSModulePath -split ";")) -join ";")
From Modifying the PSModulePath Installation Path
To add paths to this variable, use one of the following methods:
To add a temporary value that is available only for the current session, run the following command at the command line:
$env:PSModulePath = $env:PSModulePath + ";c:\ModulePath"
To add a persistent value that is available whenever a session is opened, add the following command to a Windows PowerShell profile:
$env:PSModulePath = $env:PSModulePath + ";c:\ModulePath"
For more information about profiles, see about_Profiles in the
Microsoft TechNet library.
To add a persistent variable to the registry, create a new user environment variable called PSModulePath using the Environment
Variables Editor in the System Properties dialog box.
To add a persistent variable by using a script, use the SetEnvironmentVariable method on the Environment class. For example,
the following script adds the "C:\Program Files\Fabrikam\Module" path
to the value of the PSModulePath environment variable for the
computer. To add the path to the user PSModulePath environment
variable, set the target to "User".
$CurrentValue = [Environment]::GetEnvironmentVariable("PSModulePath", "Machine")
[Environment]::SetEnvironmentVariable("PSModulePath", $CurrentValue + ";C:\Program Files\Fabrikam\Modules", "Machine")

Related

git : The term 'git' is not recognized as the name of a cmdlet, function, script file, or operable program [duplicate]

I installed AWS SAM from the msi installer from AWS for windows.
after running the installer, I ran sam --version in cmd and powershell.
PS C:\Users\dgupta> sam --version
SAM CLI, version 1.26.0
It returns the version I just installed. However in VS code, I opened a terminal and ran sam --version it errors out.
Windows PowerShell
Copyright (C) Microsoft Corporation. All rights reserved.
Try the new cross-platform PowerShell https://aka.ms/pscore6
sam : The term 'sam' is not recognized as the name of a cmdlet, function, script file, or operable program. Check the spelling of the name, g of the name,
or if a path was included, verify that the path is correct and try again.
At line:1 char:1
+ sam --version
+ ~~~
+ CategoryInfo : ObjectNotFound: (sam:String) [], CommandNotFoundException
+ FullyQualifiedErrorId : CommandNotFoundException
why is this happening ? doesn't VS Code terminal and normal terminal have access to the same environment variables ?
It's impossible to diagnose your problem without further information, but perhaps these troubleshooting tips help:
If you're invoking an external executable (sam) by name only, your problem must be that the directory in which the executable resides isn't listed in the $env:PATH environment variable defined for the current process.
However, it is possible that the external sam executable's directory isn't in $env:PATH and that sam is an auxiliary PowerShell command of the same name that knows the true sam's location and invokes it behind the scenes.
For instance an alias - such as New-Alias sam 'C:\path\to\sam.exe' - or a function - such as function sam { & C:\path\to\sam.exe $args } - could be defined.
From the PowerShell session where sam is found:
To determine what type of command the name sam refers to in your session, use the following and check the value of the CommandType column:
Get-Command sam
If the command type is Application, you are indeed dealing with an external executable, and the Source column will report its full path, from which you can glean the executable's directory path (which you can determine directly with Split-Path (Get-Command -Type Application sam).Path
You then need to diagnose why that directory isn't in $env:Path in the other session - see first section below.
If the command type isn't Application:
You need to determine where the auxiliary alias or function is defined and why your other session doesn't see it, which, if the problem is reproducible in new sessions, must be connected to what profile files (as reflected in the automatic $PROFILE variable) were loaded.
Diagnose why a directory is missing from $env:PATH:
Possible reasons:
You've just installed an executable, and the installer modified the persistent $env:PATH definition in the registry.
Any running processes started before this modification or even started afterwards directly from such a process do not see the modification.
Solution:
Start a new session, which in your case means restarting Visual Studio Code, but be sure to start it from the Start Menu / taskbar / File Explorer, as they are aware of the modified environment. When in doubt, log off and back on to your Windows session, or reboot your machine.
Alternatively, refresh $env:PATH from the registry in-session - see below.
Something in your current PowerShell session has (possibly inadvertently) removed sam's directory from the in-process $env:PATH variable.
Solution:
Refresh the in-process $env:PATH definition from the registry with the following command (note that any prior in-process modifications are then lost):
$env:PATH = [Environment]::GetEnvironmentVariable('Path', 'Machine') + ';' + [Environment]::GetEnvironmentVariable('Path', 'User')
If these solutions don't help (persistently), the problem must be :
Either: Even the persistent Path variable definition is lacking an entry for the directory or interest (even though installers normally do add such an entry).
Or: The problem arises from what PowerShell profile files are loaded into the different environments.
See the next sections.
Add a directory entry to the persistent definition of the Path environment variable yourself:
Interactively:
Run sysdm.cpl, select the Advanced tab, and click on Environment Variables..., then modify the Path variable as desired.:
Note: To modify the Path variable under System variables, i.e. the system-wide part of the Path variable, you need to be an administrator.
After having modified Path this way, you need to open a new shell session in the manner described above in order to see the effects.
Programmatically:
See this answer for helper function Add-Path; the answer also explains why set.exe should not be used.
Diagnose what profile files were loaded into a session:
PowerShell's profile files are (by default) loaded (dot-sourced) on session startup and allow sessions to be customized, which can include things such as custom alias definitions, functions, and even in-process $env:PATH additions.
There are multiple profile files, all of which are loaded (by default), if present, along two independent dimensions: all-users vs. current-user, and all-hosts vs. current-host (a host being the PowerShell host environment, such as a regular console window or the terminal in Visual Studio Code).
The automatic $PROFILE variable reports the current-user, current-host profile-file path, but actually has normally invisible properties listing all paths (you can make them visible with $PROFILE | select * - see this answer).
What profiles are loaded into a session for a given user is determined by the following factors:
Fundamentally, whether profile loading is suppressed altogether, using the CLI's -NoProfile switch.
If not suppressed (the default, even with -Command and -File invocations):
What edition of PowerShell you're using: The comes-with Windows, legacy Windows PowerShell edition (whose latest and final version is 5.1), whose CLI is powershell.exe, vs. the install-on-demand cross-platform PowerShell (Core) edition, whose CLI is pwsh.exe, have separate profile locations.
The type of the host environment, as reflected in the automatic $Host variable.
To see what command line was used to invoke the current session, run the following:
[Environment]::CommandLine
Note:
In a PowerShell Integrated Console in Visual Studio Code you'll always see -NoProfile among the parameters, but the profiles may still be loaded during startup, depending on the settings of PowerShell extension
It follows from the above that different host environments load different sets of profile files, and in the PowerShell Integrated Console provided by Visual Studio Code's PowerShell extension, different profile files are indeed loaded (if loading is enabled via the settings) - compared to regular console windows[1]
If you want your PowerShell Integrated Consoles to load the same current-user profile as regular console windows:
Via Visual Studio Code's settings, make sure that the PowerShell: Enable Profile Loading setting is enabled.
From a PowerShell Integrated Console, run psedit $PROFILE to open the host-specific current-user profile for editing.
Add the following content:
. ($PROFILE -replace '\.VSCode', '.PowerShell')
[1] Note that you can use PowerShell in the Visual Studio Code terminal even without the PowerShell extension, and such session do use the same profiles as regular console windows - see this answer.

How to permanently remove a UNC path from $env:PSModulePath for PowerShell?

Where I work, users have their folders redirected to a UNC path to save data. This seems to have affected my PowerShell because every time I start up powershell, it attempts to load modules from the UNC path and it takes a long time. This also affects how I use cmdlets because it tries to search the UNC path for cmdlet context.
When I look at the output of $env:PSModulePath I can see the UNC directory. But it doesn't show up in System's Environment Variables dialog editor.
How can I get rid of this so that Powershell doesn't keep looking for module support from the UNC directory? I understand that I can edit an existing sessions $env:PSModulePath, but I want it gone forever.
The Microsoft documentation page about_PSModulePath explains it. By default, PowerShell builds the $env:PSModulePath value by concatenating:
The user's "Documents" folder, likely the UNC path you are mentioning.
The contents of the PSModulePath system environment variable.
You can find out the path of the "Documents" folder as follows:
[Environment]::GetFolderPath('MyDocuments')
If you define a user-level environment variable PSModulePath in addition to the system environment variable PSModulePath, it will replace your "Documents" folder in $env:PSModulePath, which won't contain the UNC path anymore.
To permanently change the PSModulePath environment variable, you can use the .NET method SetEnvironmentVariable on the System.Environment class.
Example:
[Environment]::SetEnvironmentVariable("PSModulePath", "Some_Path", "Machine")
Keep in mind, this will overwrite what you had before on this variable. So make sure before you run the method as the PSModulePath will certainly have paths that you might need.
Also, if your company is using GPOs to set the PSModulePath variable, then the only way to remove the UNC path is to talk to your administrator that handles that.
I don't know why it is not shown in your system variables GUI. You should be able to remove it with something along these lines:
$yourvalueyouwanttodelete = 'somepath'
$oldval = [environment]::GetEnvironmentVariable("PSModulePath")
$arr_oldval = $oldval -split ";"
$arr_newval = $arr_oldval | ? {$_ -ne $yourvalueyouwanttodelete}
$newval = $arr_newval -join ";"
[environment]::SetEnvironmentVariable("PSModulePath", $newval)
The way I resolved this was to set the Module Path in the All users profile
For me $PROFILE.AllUsersAllHosts returned:
C:\Program Files\PowerShell\7\profile.ps1
I created that file and added the following:
$ModulePath = "c:\program files\powershell\7\Modules"
[Environment]::SetEnvironmentVariable("PSModulePath", $ModulePath)
I ran into the same issue after removing PowerShell 7 from my device. What appears to be happening is that the PSModulePath variable to My Documents is removed from the environment variables under Advanced System Settings. Powershell then uses the UNC path, which is configured by group policy.
The solution, that worked for me was to add a new Environment Variable called PSModulePath with the value of C:\Users\YourUserNameHere\Documents. Now powershell has a place to look for those PS Modules.

Changing a value in the Path environment variable

My company uses a program that breaks when Java is updated. This is due to the program install (I assume) placing a static path to Java in the Path environment variable. For example, the current Path variable in question is C:\Program Files (x86)\Java\jre1.8.0_171\bin\client, but if Java is updated and the program is re-installed, the Path variable will update to include C:\Program Files (x86)\Java\jre1.8.0_181\bin\client.
I was able to find exactly what I needed (I think) here https://blogs.technet.microsoft.com/heyscriptingguy/2007/11/08/hey-scripting-guy-how-can-i-remove-a-value-from-the-path-environment-variable/, but that code is for Powershell 2.0 and doesn't work on Windows 10.
Is this still possible in Windows 10?
You can use the System.Environment class to modify your environment variables machine-wide:
# get the PATH and split it up
$PATH = [Environment]::GetEnvironmentVariable('PATH', 'Machine') -split ';'
# filter out the JRE paths
$PATH = $PATH -notmatch 'java\\jre'
# get any real JRE paths
$PATH += (Get-Item -Path "${Env:ProgramFiles(x86)}\Java\jre*\bin\client").FullName
$PATH = $PATH -join ';'
[Environment]::SetEnvironmentVariable('PATH', $PATH, 'Machine')
Note: You will need to run your shell elevated to execute these commands.
Java is not a Windows issue, and therefore TechNet will not help you. There is a fix below.
Windows 10 and Windows 8:
Open the Legacy Control Panel
Click the Advanced system settings link.
Click Environment Variables. In the section System Variables, find the PATH environment variable and select it.
Click Edit.
If the PATH environment variable does not exist, click New.
In the Edit System Variable (or New System Variable) window, specify the value of the PATH environment variable.
Click OK.
Close all remaining windows by clicking OK.
Reopen the PowerShell window, and run your Java code.
Source: https://www.java.com/en/download/help/path.xml

Persisting PSModulePath across all sessions

I have a PSModule that I would like to put in my own PSTools directory instead of the standard powershell reserved directory for PSModule. I used the command
$env:PSModulePath += ';c:\MyPSModule'
This works but it is only good for my current session and PS seems to have forgotten my settings after a new session is created and I have to set it up again.
How do I persist my $env settings across all powershell sessions and if possible for all users? If possible, I do not want to hack the registry. Just ps command only if this is feasible.
$CurrentValue = [Environment]::GetEnvironmentVariable("PSModulePath", "Machine")
[Environment]::SetEnvironmentVariable("PSModulePath", $CurrentValue + ";C:\MyPSModule", "Machine")
To add a persistent variable by using a script, use the
SetEnvironmentVariable method on the Environment class. For example,
the above script adds the "C:\MyPSModule" path
to the value of the PSModulePath environment variable for the
computer. To add the path to the user PSModulePath environment
variable, set the target to "User".
https://msdn.microsoft.com/en-us/library/dd878326(v=vs.85).aspx

Powershell import-module doesn't find modules

I'm learning PowerShell and I'm trying to build my own module library.
I've written a simple module XMLHelpers.psm1 and put in my folder $home/WindowsPowerShell/Modules.
When I do:
import-module full_path_to_XMLHelpers.psm1
It works. But when I do:
import-module XMLHelpers
It doesn't work and I get the error:
Import-Module : The specified module 'xmlhelpers' was not loaded because no valid module file was found in any module directory.
I've checked that the environment variable PSModulePath contains this folder. As it is a network folder, I've also tried to move it to a local folder and to modify PSModulePath but without success
$env:PSModulePath=$env:PSModulePath+";"+'C:\local'
Any idea on what could cause this issue?
The module needs to be placed in a folder with the same name as the module. In your case:
$home/WindowsPowerShell/Modules/XMLHelpers/
The full path would be:
$home/WindowsPowerShell/Modules/XMLHelpers/XMLHelpers.psm1
You would then be able to do:
import-module XMLHelpers
1.This will search XMLHelpers/XMLHelpers.psm1 in current folder
Import-Module (Resolve-Path('XMLHelpers'))
2.This will search XMLHelpers.psm1 in current folder
Import-Module (Resolve-Path('XMLHelpers.psm1'))
I think that the Import-Module is trying to find the module in the default directory C:\Windows\System32\WindowsPowerShell\v1.0\Modules.
Try to put the full path, or copy it to C:\Windows\System32\WindowsPowerShell\v1.0\Modules
I experienced the same error and tried numerous things before I succeeded. The solution was to prepend the path of the script to the relative path of the module like this:
// Note that .Path will only be available during script-execution
$ScriptPath = Split-Path $MyInvocation.MyCommand.Path
Import-Module $ScriptPath\Modules\Builder.psm1
Btw you should take a look at http://msdn.microsoft.com/en-us/library/dd878284(v=vs.85).aspx which states:
Beginning in Windows PowerShell 3.0, modules are imported automatically when any cmdlet or function in the module is used in a command. This feature works on any module in a directory that this included in the value of the PSModulePath environment variable ($env:PSModulePath)
I had this problem, but only in Visual Studio Code, not in ISE. Turns out I was using an x86 session in VSCode. I displayed the PowerShell Session Menu and switched to the x64 session, and all the modules began working without full paths. I am using Version 1.17.2, architecture x64 of VSCode. My modules were stored in the C:\Windows\System32\WindowsPowerShell\v1.0\Modules directory.
Some plugins require one to run as an Administrator and will not load unless one has those credentials active in the shell.
My finding with PS 5.0 on Windows 7: $ENV:PsModulePath has to end with a . This normally means it will load all modules in that path.
I'm not able to add a single module to $env:PsModulePath and get it to load with Import-Module ExampleModule. I have to use the full path to the module. e.g. C:\MyModules\ExampleModule. I am sure it used to work.
For example:
Say I have the modules:
C:\MyModules\ExampleModule
C:\MyModules\FishingModule
I need to add C:\MyModules\ to $env:PsModulePath, which will allow me to do
Import-Module ExampleModule
Import-Module FishingModule
If for some reason, I didn't want FishingModule, I thought I could add C:\MyModules\ExampleModule only (no trailing \), but this doesn't seem to work now. To load it, I have to Import-Module C:\MyModules\ExampleModule
Interestingly, in both cases, doing Get-Module -ListAvailable, shows the modules, but it won't import. Although, the module's cmdlets seem to work anyway.
AFAIK, to get the automatic import to work, one has to add the name of the function to FunctionsToExport in the manifest (.psd1) file. Adding FunctionsToExport = '*', breaks the auto load. You can still have Export-ModuleMember -Function * in the module file (.psm1).
These are my findings. Whether there's been a change or my computer is broken, remains to be seen. HTH
try with below on powershell:
Set-ExecutionPolicy -ExecutionPolicy Unrestricted
import-module [\path\]XMLHelpers.psm1
Instead of [] put the full path
Full explanation of this and that
First of all check Your account type,some imports are not allowed to normal partner accounts.