PowerShell / PSResourceGet

PSResourceGet is the package manager for PowerShell
https://www.powershellgallery.com/packages/Microsoft.PowerShell.PSResourceGet
MIT License
483 stars 92 forks source link

RequiredResource is still unusable #1448

Open Jaykul opened 10 months ago

Jaykul commented 10 months ago

Prerequisites

Steps to reproduce

Back in the late 2021 releases of PowerShellGet, the spec for the RequiredResource was:

It worked, back then, and was compatible with my Install-RequiredModule script)...

The last RC I tried before release was totally broken with regards to RequiredResource #1446 -- but the fix in the GA release is just not usable.

It throws if we try to use the simpler syntax:

PS > Install-PSResource -RequiredResource @{ zLocation = "[1.4.3]" } Install-PSResource: The RequiredResource input with name 'zLocation' does not have a valid value, the value must be a hashtable.

It uses NAMES instead of URLs for the repository

PS > Install-PSResource -RequiredResource @{ zLocation = @{ Version = "[1.4.3]"; Repository = "https://www.powershellgallery.com/api/v2" }} Install-PSResource: Cannot resolve -Repository name. Run 'Get-PSResourceRepository' to view all registered repositories.

If you specify Repository = "PSGallery" it works. Even from a file.

RequiredResource files should not be able to specify repositories by name. Out in public, that's insecure and dangerous, since it relies on everyone having the same definition of the name, and the names are registered in an insecure file. I thought that was clear in the original announcement and in all discussions since.

The only repository that we can somewhat trust is registered with the same name on every system is the PSGallery, and that's because you force the name for this very reason: to make sure that nobody accidentally installs modules from a different repository, thinking they're installing from PowerShellGallery.com

I believe RequiredResource files that need to specify an alternative source need to do so with the full URL, and any URLs that aren't registered as trusted should be treated as untrusted.

It installs the lowest version, even if a higher version is already installed

@"
@{
  VSTeam = @{
    Version = "[7.9,)"
    Repository = "PSGallery"
    TrustRepository = `$true
  }
}
"@>Requires.psd1

Install-PSResource -RequiredResourceFile .\Requires.psd1
Get-Module VSTeam -list
    Directory: C:\Users\Jaykul\Documents\PowerShell\Modules

ModuleType Version    PreRelease Name                                PSEdition ExportedCommands
---------- -------    ---------- ----                                --------- ----------------
Script     7.13.3                VSTeam                              Core,Desk {Add-VSTeam, Add-VSTeamAccessControlEntry, Add-VSTeamArea, Add-VSTeamAzureRMServiceEndpoint…}
Script     7.9.0                 VSTeam                              Core,Desk {Add-VSTeam, Add-VSTeamAccessControlEntry, Add-VSTeamArea, Add-VSTeamAzureRMServiceEndpoint…}

Surely it should have noticed that 7.13.3 was already installed, but if not, then it should have installed 7.15 -- not the oldest possible version...

You can't set the upper bound

PS> Install-PSResource -RequiredResource @{ VSTeam = @{ Version = "[7.9.0,7.14.0)"; Repository = "PSGallery" } } -PassThru Install-PSResource: Package(s) 'VSTeam' could not be installed from repository 'PSGallery'.

I really have no idea why that fails. Any time I try to set anything in the upper limit for the version, it failed.

It doesn't work with ProGet

The version range syntax is using some specific syntax to query for ranges that doesn't seem to work with ProGet ...

What repositories was it tested on?

There's no output

I'll probably open another issue making this a "suggestion" later -- if this feature ever makes it to a place where it's usable -- but when I'm installing multiple modules from a hashtable or a file, without knowing for sure which version will be installed, there really should be some indication of what got installed, without needing to specify -Passthru.

Currently, I get more information about what is not installed. E.g.:

WARNING: Resource 'VSTeam' with version '7.9.0' is already installed. If you would like to reinstall, please run the cmdlet again with the -Reinstall parameter

Again, this feature is not supposed to just recursively call Install-PSResource. It needs to be built-for-purpose. When I'm installing dependencies for a project, I want to see the list of all the modules (whether or not they are already installed) by default, but it can't be a partial list (which is all I can get now, if I use -Passthru), and I certainly do not want warnings when everything is ok.

There's more ...

I ran out of steam at this point, but earlier in my testing I noticed a list of possible properties in the hashtable that includes "TrustRepository". It doesn't appear to have any effect (thank goodness), but there's no way that property should be there.

It might be valid to assume that I have inspected any files I'm installing from. It's probably valid to assume I'm ok with the use of 3rd party repositories (assuming they were listed by URL, not by name). But there's no reason to allow a resource list to bypass trust settings without the user explicitly saying so.

For the same reason, I don't think it's appropriate for the RequiredResources manifest/json/hashtable to specify "AcceptLicense" or "Quiet" or "Reinstall" or "SkipDependencyCheck" either.

This feature isn't supposed to just recurse and splat the hashtable. It's supposed to be ... smarter than that.

Frankly, using names and installing the lowest version -- by themselves -- are cause to warn people off using this feature. It's not safe, and it doesn't work the way you think it does. I'm not saying it's deffinitely harmful, but if you refuse to release a version that breaks "compatibility" by going back to using URLs instead of names ... it will have been. 😦

Expected behavior

# The following should ensure the module is installed, supporting _any_ **trusted** repository:

Install-PSResource -RequiredResource @{ zLocation = "[1.4.3]" }

# The following should ensure the module is installed, but only install from the PSGallery:

Install-PSResource -RequiredResource @{
  zLocation = @{ 
    Version = "[1.4.3]"
    Repository = "https://www.powershellgallery.com/api/v2"
  }
}

# The following should fail
# The error should inform the user they cannot reference repositories by name in RequiredResource lists.
PS> @"
@{
  zLocation = @{
    Version = "[1.4.3]"
    Repository = "PSGallery"
  }
}
"@ > RequiredModules.psd1

PS> Install-PSResource -RequiredResourceFile RequiredModules.psd1

Actual behavior

Only the one example which I believe should fail works.

Error details

No response

Environment data

Get-Module Microsoft.PowerShell.PSResourceGet; $PSVersionTable | Format-Table

ModuleType Version    PreRelease Name                                ExportedCommands
---------- -------    ---------- ----                                ----------------
Binary     1.0.0                 Microsoft.PowerShell.PSResourceGet  {Find-PSResource, Get-InstalledPSResource, Get-PSResourceRepository, Get-PSScriptFileInfo…}

Name                           Value
----                           -----
PSVersion                      7.4.0-preview.5
PSEdition                      Core
GitCommitId                    7.4.0-preview.5
OS                             Microsoft Windows 10.0.19042
Platform                       Win32NT
PSCompatibleVersions           {1.0, 2.0, 3.0, 4.0…}
PSRemotingProtocolVersion      2.3
SerializationVersion           1.1.0.1
WSManStackVersion              3.0

Visuals

No response

SydneyhSmith commented 10 months ago

Thanks @Jaykul super appreciate the very detailed feedback-- I went ahead and added this our next project

jpawlowski commented 1 month ago

The version range behavior is indeed totally broken, but it seems to be the API servers' fault as the resulting sorting does not handle SemVer correctly.

I can image the Install-Module command simply sorts the API response by its own to avoid this and developers of PSResourceGet might think "okay, not our fault, it is the API's team fault". But hey, have you heard of user-centered design and development? Hope so.

However, I am really wondering who did quality check the PSResourceGet module as this is one of the simplest things to check. It has been in the works for years now so imagine my face when I noticed this is still unusable.

jpawlowski commented 1 month ago

I also want to refer to these open issues at the PowerShellGalleryrepository:

https://github.com/PowerShell/PowerShellGallery/issues/270 https://github.com/PowerShell/PowerShellGallery/issues/269 https://github.com/PowerShell/PowerShellGallery/issues/267