PSResourceGet icon indicating copy to clipboard operation
PSResourceGet copied to clipboard

[Feature Request]: Ability to configure PSRepository on a system-wide level

Open Glober777 opened this issue 7 years ago • 30 comments

It would be great if there was a way to register a PSRepository on the system-wide level, so that if configured once, it would work for all the users on a particular system.

Expected Behavior

Register-PSRepository should have a -Scope parameter added, to control whether a particular PSRepository needs to be registered for just the current user of for the whole system (similar to the behavior of Execution Policy). It would also be great to have an extra scope option, that would register PSRepository just for the current session (like mentioned in PowerShell/PowerShellGet#65)

Apart from the Register-PSRepository, the remaining set of the *-PSRepository cmdlets should also have the -Scope parameter. Set-PSRepository and Unregister-PSRepository cmdlets should require admin privileges to work against system-wide PSRepository settings and 'Get-PSRepository' cmdlet should not require admin privileges at all.

Current Behavior

Currently Register-PSRepository only works for the user that is executing the cmdlet.

Context

Having an ability to register PSRepository on a system-wide level would allow us to pre-configure our internal Repositories in the Virtual Machine templates, thus making the provisioning process much simpler.

Additionally, that would simplify maintaining existing PSRepository configurations in a consistent fashion across all our systems.

Your Environment


PS C:\Users> $PSVersionTable

Name                           Value
----                           -----
PSVersion                      5.1.15063.726
PSEdition                      Desktop
PSCompatibleVersions           {1.0, 2.0, 3.0, 4.0...}
BuildVersion                   10.0.15063.726
CLRVersion                     4.0.30319.42000
WSManStackVersion              3.0
PSRemotingProtocolVersion      2.3
SerializationVersion           1.1.0.1


PS C:\Users>
PS C:\Users> Get-Module

ModuleType Version    Name                                ExportedCommands
---------- -------    ----                                ----------------
Manifest   3.1.0.0    Microsoft.PowerShell.Utility        {Add-Member, Add-Type, Clear-Variable, Compare-Object...}
Script     1.2        PSReadline                          {Get-PSReadlineKeyHandler, Get-PSReadlineOption, Remove-PS...


PS C:\Users>
PS C:\Users> Get-Module -ListAvailable PowerShellGet,PackageManagement


    Directory: C:\Program Files\WindowsPowerShell\Modules


ModuleType Version    Name                                ExportedCommands
---------- -------    ----                                ----------------
Script     1.1.7.0    PackageManagement                   {Find-Package, Get-Package, Get-PackageProvider, Get-Packa...
Script     1.1.1.0    PackageManagement                   {Find-Package, Get-Package, Get-PackageProvider, Get-Packa...
Binary     1.0.0.1    PackageManagement                   {Find-Package, Get-Package, Get-PackageProvider, Get-Packa...
Script     1.6.0      PowerShellGet                       {Install-Module, Find-Module, Save-Module, Update-Module...}
Script     1.1.2.0    PowerShellGet                       {Install-Module, Find-Module, Save-Module, Update-Module...}
Script     1.0.0.1    PowerShellGet                       {Install-Module, Find-Module, Save-Module, Update-Module...}


    Directory: C:\Program Files (x86)\WindowsPowerShell\Modules


ModuleType Version    Name                                ExportedCommands
---------- -------    ----                                ----------------
Binary     1.0.0.1    PackageManagement                   {Find-Package, Get-Package, Get-PackageProvider, Get-Packa...
Script     1.0.0.1    PowerShellGet                       {Install-Module, Find-Module, Save-Module, Update-Module...}


PS C:\Users>
PS C:\Users> Get-PackageProvider

Name                     Version          DynamicOptions
----                     -------          --------------
msi                      3.0.0.0          AdditionalArguments
msu                      3.0.0.0
NuGet                    2.8.5.210        Destination, ExcludeVersion, Scope, SkipDependencies, Headers, FilterOnTag...
PowerShellGet            1.6.0.0          PackageManagementProvider, Type, Scope, AllowClobber, SkipPublisherCheck, ...
Programs                 3.0.0.0          IncludeWindowsInstaller, IncludeSystemComponent


PS C:\Users> Get-PackageProvider -ListAvailable

Name                     Version          DynamicOptions
----                     -------          --------------
msi                      3.0.0.0          AdditionalArguments
msu                      3.0.0.0
nuget                    2.8.5.208
NuGet                    2.8.5.210        Destination, ExcludeVersion, Scope, SkipDependencies, Headers, FilterOnTag...
NuGetProvider            2.8.5.208
PowerShellGet            1.6.0.0          PackageManagementProvider, Type, Scope, AllowClobber, SkipPublisherCheck, ...
PowerShellGet            1.1.2.0
PowerShellGet            1.0.0.1
Programs                 3.0.0.0          IncludeWindowsInstaller, IncludeSystemComponent

Glober777 avatar Dec 26 '17 09:12 Glober777

I also support this request.

If an admin runs Install-Module -Scope AllUsers on a system, a different admin has to first register this repository in order to call Update-Module. Every time I touch a system and want to install or update a module, I first have to check to see if the repository is registered. Even if we fully automate the onboarding of that system, I still have to register a repository by hand.

What I do now is just include the repository registration logic in any and all scripts that install modules.

KevinMarquette avatar Mar 05 '18 10:03 KevinMarquette

+1 for this enhancement.

sam-bryant avatar May 29 '18 14:05 sam-bryant

Windows PowerShell team, any guidance on where the "AllUsers" repositories configuration file would live? I see 2 options:

  1. $script:ProgramFilesPSPath as this is where the AllUsers Modules are installed
  2. $script:PSGetProgramDataPath seems like the place for this configuration but might not work for "AllUsers" on Linux/OSX

bradleywehmeier avatar Jun 06 '18 14:06 bradleywehmeier

@bradleywehmeie, thanks for looking into this feature request. Yes, $script:PSGetProgramDataPath is the right place for this configuration file.

For non-Windows platforms, please update the $script:PSGetProgramDataPath to '/usr/local/share/powershellget'.

Current:

    $script:PSGetProgramDataPath = Microsoft.PowerShell.Management\Join-Path -Path ([System.Management.Automation.Platform]::SelectProductNameForDirectory('CONFIG')) -ChildPath 'PowerShellGet'

Expected:

    $script:PSGetProgramDataPath = '/usr/local/share/powershellget'

bmanikm avatar Jun 06 '18 19:06 bmanikm

Main Question

How do we expect Unregister-PSRepository to function when the Scope parameter is omitted? Should it be allowed to modify the AllUsers scope if the Scope is omitted OR should the Scope be required anytime the AllUsers scope is being modified?

Example:

Register-PSRepository -Name Test -Scope AllUsers ...

# Should this be allowed?
Unregister-PSRepository -Name Test

# Or should we require the Scope?
Unregister-PSRepository -Name Test -Scope AllUsers

Additional Context

With either implementation, the Set/Unregister-PSRepository cmdlets work as you would expect but I ran into a limitation with the Unregister-PackageSource cmdlet and pipelining. The value for Scope is not pipelined to the Unregister-PackageSource cmdlet so there are occasions where it will produce the incorrect result when attempting to work on the AllUsers scope.

For example:

Register-PSRepository -Name Test -Scope AllUsers ...

Get-PackageSource -Name Test -Scope AllUsers | Unregister-PackageSource

If we are strict about requiring the AllUsers to be specified, this will result in a Not Found error because no scope will end up being passed to Remove-PackageSource so it will assume "CurrentUser" scope. If we aren't strict, then Remove-PackageSource won't assume a scope and will find the Test PackageSource and remove it.

In both implementations if the PackageSource exists in both the CurrentUser and AllUsers (a case which is possible), Get-PackageSource -Name Test -Scope AllUsers | Unregister-PackageSource will remove the wrong PackageSource. It will find Test in the CurrentUsers scope and remove it from there instead of the AllUsers scope which was pipelined. For this reason maybe this additional context is a moot point and we should simply state that using *-PackageSource for AllUsers scope is not recommended/supported.

bradleywehmeier avatar Jun 12 '18 21:06 bradleywehmeier

@bradleywehmeier If a user is trying to unregister an AllUsers scoped repository, it is required to ensure that user has the admin privileges similar to the Uninstall and Update cmdlets.

As part of this enhancement, are you allowing the duplicate PSRepository names? I think we should allow this as the users and admin may give the same name for the psrepositories. if not, can we follow the same design as the Uninstall and Update cmdlets where -Scope parameter is not required on Unregister-PSRepository.

If we are allowing the duplicate psrepository names

  • Add Scope optional parameter on Unregister-PSRepository cmdlet
  • Admin privileges check is also required for the AllUsers scoped psrepositories
  • Scope parameter is optional for the AllUsers scoped psrepositories
  • If Scope parameter is not specified, Unregister-PSRepository cmdlet first checks if the given name is registered for the currentuser scope and unregisters it.

Above is also applicable to the Set-PSRepository cmdlet.

We need to add -Scope optional parameter in PowerShellGet provider dynamic options for the sources at https://github.com/PowerShell/PowerShellGet/blob/development/PowerShellGet/public/providerfunctions/Get-DynamicOptions.ps1#L31 similar to https://github.com/PowerShell/PowerShellGet/blob/development/PowerShellGet/public/providerfunctions/Get-DynamicOptions.ps1#L44 For more details, please take a look at the ScriptSourceLocation dynamic option implementation in PowerShellGet provider functions.

For the pipeline operations with scope, it is required to specify -Provider PowerShellGet like below

Get-PackageSource -Name Test -Provider PowerShellGet -Scope AllUsers | Unregister-PackageSource

bmanikm avatar Jun 13 '18 20:06 bmanikm

@bmanikm Yes admin is required for modifications to AllUsers Scope. Dynamic Parameters have been taken care of.

Duplicate Repository names have to be supported because there is no way to avoid a situation where an admin defines an AllUsers repo that overlaps with a setting that a user has already set. In this case the user will get the instance they defined (CurrentUser scope) not the AllUsers scope.

“Scope parameter is optional for the AllUsers scoped psrepositories” answers my real question here.

With the rest having been taken care of look for a pull request in the next couple of days after I look it over one last time.

bradleywehmeier avatar Jun 13 '18 23:06 bradleywehmeier

Also please consider validating the install and update scenarios with the duplicate psrepository names as the source locations can be different.

bmanikm avatar Jun 14 '18 00:06 bmanikm

Regarding the case of duplicate PSRepository names with different source locations:

  • For Install, the repository that will be used is the CurrentUser scoped PSRepository. This is the same PSRepository that is shown in Get-PSRepository in this case so it is consistent.
  • For Update, I'm assuming the desired behavior is to use the same source location that was originally used to install. Is that assumption correct?

The name overlap does cause problems for Update. It wants to use the PSRepository source location defined in CurrentUser regardless of what source location was used for the install.

bradleywehmeier avatar Jul 25 '18 19:07 bradleywehmeier

The more I think about it, I'm not sure if my assumption was correct.

  • On one hand, downloading updates from the same location you downloaded makes perfect sense.
  • On the other hand, the primary mechanism that is used to reference a particular PSRepository is the Name and we allow situations where the source location is allowed to change and PowerShellGet continues to function with the new location.

When there are duplicate PSRepository names and one is chosen to be the "winner", I can also make an argument to treat that scenario in the same way we treat the PSRepository source location having been changed and using the source location from the "winner".

There are other rough edges with PowerShellGet like the current behavior of using a "CurrentUser" PSRepository to install "AllUsers" modules. If those are not causing issues, then maybe this confusion will also be negligible.

One alternative would be to Prefix the AllUsers scoped PSRepositories so that name collisions were not possible. I originally avoided that so that PackageManagement cmdlets (e.g. Register-PackageSource) and PowerShellGet cmdlets (e.g. Register-PSRepository) would have the same/similar parameters. If that's not something that matters since most people will be using the PowerShellGet cmdlets, I can spend some time implementing that approach to see if it has fewer issues.

Thanks all for your input on this. I appreciate the effort in helping me get this right.

bradleywehmeier avatar Jul 25 '18 21:07 bradleywehmeier

@bradleywehmeier thanks for looking into this feature!

Some thoughts

  • By default, Get-PSRepository cmdlet should list all the registered repositories in both scopes (CurrentUser and AllUsers). We need to add the Scope property/column in the Get-PSRepository output format.
  • Duplicate repository names should not be allowed in a single scope.
  • In case of duplicate repository names, CurrentUser scope gets precedence over AllUsers scope.
  • During the Install operation, we also need to add a property called RepositoryScope in the PSRepositoryItemInfo in PSGetModuleInfo.xml/[ScriptName]_InstalledScriptInfo.xml file so that update operation picks the correct repository name and scope. This follows the current update functionality.

bmanikm avatar Jul 25 '18 23:07 bmanikm

I also support this. I had a very confusing few hours the other day, trying to configure a proxy PowerShellGet package source through DSC. Since DSC runs as the system user, I couldn't see the repositories it was registering. I am now trying to figure out how to configure the proxy repository for all users. (Does anyone have any good solutions to that?)

maxwell-clarke-intranel avatar Sep 14 '18 02:09 maxwell-clarke-intranel

Agreed this is much needed feature. I'm trying to use the PackageManagement DSC resource to configure our internal/proxy nexus repository as part of an OS deployment but is only applied under the NT Autority\System account. The modules install fine from the internal repo as part of the DSC config, however normal users still see the default PSGallery repo meaning they cannot pull approved and custom internal modules when required.

tmmruk avatar Oct 21 '18 19:10 tmmruk

I just want to chime in that this causes problems using Jenkins automation as well. Jenkins agents sometimes run under system or certain service account logins and i have no good way to configure the psrepository for them.

hematic avatar Nov 21 '18 15:11 hematic

+1 for this feature. We've want to move to using PowerShellGet exclusively for module distribution but we get constant requests for assistance with setting up the right repos which is slowing down adoption. This feature would solve that.

mrhockeymonkey avatar May 29 '19 09:05 mrhockeymonkey

@SteveL-MSFT As a quick observation, this is actually a OneGet issue and not a PowerShellGet issue.

I created the following issue in OneGet to ALIGN the two projects. https://github.com/OneGet/oneget/issues/468

As Program Manager for PowerShell Core, you can facilitate, advocate for, and resource a solution to this problem!

jzabroski avatar Jul 23 '19 15:07 jzabroski

I can not use Register-PackageSource (or psrepository) by my service build account that has no local logon permissions. So how do I need to use all this package management mess? Should I use another solutions?

VerdonTrigance avatar Oct 08 '19 16:10 VerdonTrigance

@SydneyhSmith any chance this can be added to 3.0? This is a huge missing feature in a multi-user environment.

ThomasNieto avatar Aug 20 '20 16:08 ThomasNieto

Any updates on this? Our job scheduling tools uses temporary user profiles so full automation of things that utilize that tool is not possible unless I use @KevinMarquette's solution, which I'd like to avoid.

sam-bryant avatar Feb 08 '21 14:02 sam-bryant

Hello,

Is there any update on this topic ? This is a a much needed feature for me as my configuration manager runs as system, I cannot register PSRepositories / install modules

jpatigny avatar Apr 29 '21 12:04 jpatigny

Also plus 1. Definitely needed for enterprises trying to run private repositories.

awickham10 avatar Aug 10 '21 22:08 awickham10

Thanks all! We'll definitely prioritize this scenario since it's been a popular request

alerickson avatar Aug 10 '21 23:08 alerickson

+1 for this feature!

CasperStekelenburg avatar Jan 26 '22 15:01 CasperStekelenburg

+1 for this feature!

Make that + 2!

Leenton avatar Mar 26 '22 01:03 Leenton

Tracking this feature work in https://github.com/PowerShell/PowerShellGet/issues/616

SydneyhSmith avatar May 03 '22 21:05 SydneyhSmith

+1!

rvigliotti-sf avatar Nov 29 '22 11:11 rvigliotti-sf

+1, looking forward to being able to set this and remove a fair bit of workaround code :)

robinmalik avatar Dec 09 '22 16:12 robinmalik