Open cmenzi opened 10 months ago
cc @SydneyhSmith since this seems to be a PSResourceGet issue.
@SydneyhSmith would it be possible to proritize this? I'm from Azure Data and we have very significant support costs in our org related to modules being in OneDrive. I can also reach out internally if needed.
@KirillOsenkov
There is also the Save-PSResource -IncludeXml -Path 'your\custom\path'
cmdlet, it already does this.
As long as the path is in PSModulePath Import-Module
will work.
@o-l-a-v Yes, this is also what I mentioned in the issue. But nobody will remember this all the time.
You usually go to PowerShell Gallery and copy&paste the install-psresource Az
and run it. There are also scripts, where somebody ensures that a certain module is installed.
I would really prefer an environment variable or a one-time setting Set-PSDefaultResourceLocation, ..
@cmenzi
Oops, yep, also mentioned in 1st post.
This is how PowerShell have worked since forever. We've requested the ability to choose path for years. I don't see it happening any time soon. Thus Save-PSResource and set PSModulePath is currently the best workaround IMO.
I'd like PSResourcePath to just use the first path in PSModulePath in user context if choosing CurrentUser as scope (and PSModulePath env variable in system context if scope "Machine").
@o-l-a-v
This is how PowerShell have worked since forever.
This module PSResourceGet
would have been the chance to change that, isn't it :-). I mean it's something new that could also behave it bit different. I mean every command name has change from Install-Module to Install-PSResource, ...
Why not changing a bit the behavoir or adding one parameter?
This is blocking PowerShell/PowerShell/issues/15552 from moving forward.
For far longer than PowerShell has been around, the localappdata
and programdata
folders have been the standard way to store application data for user and computers.
Please, make the change so that this can move on.
For far longer than PowerShell has been around, the
localappdata
andprogramdata
folders have been the standard way to store application data for user and computers.
In windows, there is more than windows to think about with a change like this
How about a new environment variable for given scope (AllUsers vs. CurrentUser), say PSResourceGetInstallPathOverride
, that can be set with a new cmdlet Set-PSResourceInstallPathOverride -Path <path> -Scope <CurrentUser|AllUsers>
, which then should be used if present by Install-PSResource
and Update-PSResource
with fallback to current default behavior?
Easy to implement. Should not introduce breaking changes. Don't have to wait for PowerShell to change anything. More reasoning:
I've started a draft PR ^ where the basics already work:
It can be tested by cloning the branch and build the module with for instance:
& .\build.ps1 -Clean -Build -BuildFramework net472
Then import the built DLL with for instance:
Import-Module -Name 'C:\Users\olavb\Git\Others\PowerShell--PSResourceGet\out\Microsoft.PowerShell.PSResourceGet\Microsoft.PowerShell.PSResourceGet.dll'
Waiting for some response from PSResourceGet maintainers before spending more time on it. I might try to add some more functionality while I wait.
I think it should just look at powershell.config.json (if it exists) and use the PSModulePath there (if it exists), and otherwise fall back to what it is now.
If there is a powershell.config.json in Split-Path $Profile
with a "PSModulePath" use that for "CurrentUser" ...
If there is a powershell.config.json in in $PSHome
with a "PSModulePath" use that for "AllUsers" ...
Those values will be in the PSModulePath, unless the user removes them, after startup.
@Jaykul
Setting PSModulePath in powershell.config.json says it "Overrides the PSModulePath settings for this PowerShell session.".
Sounds to me you either set PSModulePath env variable, or as a setting in this JSON?
That's not a great solution either. If it overrides PSModulePath the environment variable, then you'd potentially want multiple paths here too. Which path should PSResourceGet default to, the first one?
You're misunderstanding it, @o-l-a-v -- I mean, I'm not saying the docs are great, but just try it.
Each config file (one in $PSHome
and one in Split-Path $Profile
) overrides one of the paths that PowerShell ADDS to the PSModulePath environment variable (for all future sessions). It's only used at the start of each session -- so if you change your PSModulePath in your profile (as I do), you might not even notice, but here's how it works if you don't have a profile:
Set your PSModulePath environment variables to short strings we can identify:
[System.Environment]::SetEnvironmentVariable("PSModulePath", "PATH3", "User")
[System.Environment]::SetEnvironmentVariable("PSModulePath", "PATH4", "Machine")
Start a new PowerShell instance (e.g. a new tab in Windows Terminal), the PSModulePath will be something like this:
C:\Users\Jaykul\Documents\PowerShell\Modules;C:\Program Files\PowerShell\Modules;c:\program files\powershell\7\Modules;PATH3;PATH4
Now set the user config file. It's important that you understand you can only put a single path to a folder in this string, to replace the native path (which would be a "Modules" folder adjacent to the config file). You can use other environment variables with %ComSpec% syntax, but you cannot put multiple folders with a path separator. For demonstration purposes, we'll again use a short string we can identify:
$path = Join-Path (Split-Path $Profile) powershell.config.json
$config = @{}
if (Test-Path $path) {
$config = Get-Content $path | ConvertFrom-Json -AsHashtable
}
$config.PSModulePath = "PATH1"
$config | ConvertTo-Json | set-content $path
And start a new PowerShell instance (e.g. a new tab in Windows Terminal), the PSModulePath will be something like this:
PATH1;C:\Program Files\PowerShell\Modules;c:\program files\powershell\7\Modules;PATH3;PATH4
Finally, just to finish the demo, set the PSHome config:
$path = Join-Path $PSHOME powershell.config.json
$config = @{}
if (Test-Path $path) {
$config = Get-Content $path | ConvertFrom-Json -AsHashtable
}
$config.PSModulePath = "PATH2"
$config | ConvertTo-Json | set-content $path
And start a final PowerShell instance (you may want to run it -noprofile
because it's going to be super broken, with no modules available, including PSReadLine). The PSModulePath will be:
PATH1;C:\Program Files\PowerShell\Modules;PATH2;PATH3;PATH4
Hopefully it's clear how those configs interact with the environment variables, and why reading them makes sense (with a fallback to the default of a "Modules" folder next to the config file path, if they're not set).
Incidentally, I find it really weird that the only path that cannot be overridden points at a folder that doesn't even exist on my systems.
Oh, okay. Thats nice. And should work the same on all platforms. I should've tried rather than trusting the docs. Thanks for the very detailed explaination @Jaykul. 😊
Edit: But it can't be used with Windows PowerShell 5.1, which PSResourceGet also supports.
@Jaykul - Yes thank you, I've banged my head against that before: it looks like it works at first, namely that the first entry in $PSModulePath is changed, but installing a module still installs to the old, default path, but now import-module can't find it. (The docs even warn that the powershellget commandlets don't pay attention to this setting)
IMO this makes it worse-than-useless (because it breaks existing functionality for no trade-off). If you can get the rest of the ecosystem to honor powershell.config.json
(and get the docs updated!), please do!
@OranguTech wrote:
IMO this makes it worse-than-useless (because it breaks existing functionality for no trade-off). If you can get the rest of the ecosystem to honor
powershell.config.json
(and get the docs updated!), please do!
That's definitely my goal 😉
There's an issue in the ModuleFast repo too. They are not following this setting yet, but they do (by default) install the modules in %LOCALAPPDATA%\powershell\Modules
so that's what I have mine set to...
For reference I've made a function that will be incorporated into moduleFast that provides how I envision PowerShell should be providing the info, hopefully a similar PR will reveal a public API for this. https://github.com/PowerShell/PowerShell/issues/15552#issuecomment-2327851719
In summary and testing:
Summary of the new feature / enhancement
Install-Module and now also Install-PSResourceGet do not allow to specify the Path where Modules are installed. It only works via Save-Module or Save-PSResource.
It would be great if there is a environment variable or parameter to control where powershell modules are installed when using Scope CurrentUser
Proposed technical implementation details (optional)
No response