PowerShell / PowerShell/PSResourceGet

Installing fails catastrophically when PreRelease modules have a binary assembly in use

Open
#78 3 comments 3 reactions 0 assignees View on GitHub

Nobody has claimed this yet.

Dominant language
C#
Stars
576
Forks
114
Avg merge
1d 2h
Merged PRs (30d)
7

Description

PreRelease modules that have binary assemblies cannot be upgraded if they are imported in any PowerShell session on the machine, because the binary will be locked.

It's practically impossible to update a PreRelease version of a module with binaries if you import it in your profile.

Expected Behavior

Update-Module should work, and should never break a working module.

Current Behavior:

PackageManagement\Install-Package : Administrator rights are required to install or update. Log on to the computer with an account that has Administrator
rights, and then try again, or install by adding "-Scope CurrentUser" to your command. You can also try running the Windows PowerShell session with elevated
rights (Run as Administrator).
At C:\Program Files\WindowsPowerShell\Modules\PowerShellGet\1.6.7\PSModule.psm1:12955 char:20
+ ...           $sid = PackageManagement\Install-Package @PSBoundParameters
+                      ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    + CategoryInfo          : InvalidArgument: (System.Collections.ArrayList:String) [Install-Package], Exception
    + FullyQualifiedErrorId : AdministratorRightsNeededOrSpecifyCurrentUserScope,Copy-Module,Microsoft.PowerShell.PackageManagement.Cmdlets.InstallPackage
Unfortunately, this error message is utterly incorrect, in every way

First: administrator rights won't help. What we need to do is to close every instance of PowerShell (including in terminals, in editors, etc), and then open a new instance with -noprofile (NOTE: if we're trying to upgrade PSReadLine -- try using ISE, because that's the only way to avoid using PSReadLine).

Second: "adding -Scope CurrentUser to your command" won't help. That's not a valid parameter for this command! 🙈💥💀🔥 And in any case, we're actually trying to upgrade to CurrentUser scope! The reason we can't is because the file is locked, not because we are trying to install somewhere we're not allowed to.

Third: Why are we repeating the advice to run "the Windows PowerShell session with elevated
rights (Run as Administrator)." For goodness sakes!

Additionally, the failed upgrade results in obliterating the existing install of the module.

Because the previous install was in the same folder, it's now gone (except for that binary file) -- AND WE CANNOT REINSTALL IT for the same reason the upgrade failed.

Possible Solution

Two possible solutions. My favorite would be:

  1. Always install modules into folders with full semver names
  2. If there's a +metadata or -postfix create a junction point with the System.Version name. I.e. 4.0.0 -> 4.0.0-beta02 ...
  3. When updating a pre-release, just adjust the junction after the install is successful.

Alternatively, if junctions are not supported in the file system:

  1. When PowerShellGet realizes that it's going to be installing to the same folder as an existing module, it should move all of the files to a SemVer-named folder before attempting to install the new version.
  2. If the install fails for any reason (e.g. network interruption), it should clean up by moving the old version back!
  3. The old pre-release version could even be left behind (and restored if the user removes the new pre-release), and could be cleaned up explicitly by the user at a later date -- just like regular versions.

Steps To Reproduce:

  1. Install-Module PANSIES -RequiredVersion 1.4.0-beta02 -Scope CurrentUser
  2. Import-Module PANSIES
  3. Get-InstalledModule Pansies and see you have beta02
  4. Attempt to Update-Module PANSIES -AllowPrerelease (should update to -beta03 but will instead die in a mysterious fire)
  5. Get-InstalledModule Pansies and see you don't have beta03, nor do you have beta02 anymore!

Context

My module PANSIES, and the built-in PSReadLine are just two examples of this which I have imported in my profile (or which PowerShell imports by default) which simply break when you try to update them.

Your Environment


> $PSVersionTable

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

> Get-Module PowerShellGet

ModuleType Version    Name                                ExportedCommands                                                                                    
---------- -------    ----                                ----------------                                                                                    
Script     1.6.7      PowerShellGet                       {Find-Command, Find-DscResource, Find-Module, Find-RoleCapability...}                               


> Get-Module -ListAvailable PowerShellGet,PackageManagement

ModuleType Version    Name                                ExportedCommands                                                                                    
---------- -------    ----                                ----------------                                                                                    
Script     1.1.7.2    PackageManagement                   {Find-Package, Get-Package, Get-PackageProvider, Get-PackageSource...}                              
Script     1.1.7.0    PackageManagement                   {Find-Package, Get-Package, Get-PackageProvider, Get-PackageSource...}                              
Script     1.1.1.0    PackageManagement                   {Find-Package, Get-Package, Get-PackageProvider, Get-PackageSource...}                              
Binary     1.0.0.1    PackageManagement                   {Find-Package, Get-Package, Get-PackageProvider, Get-PackageSource...}                              
Script     1.6.7      PowerShellGet                       {Find-Command, Find-DSCResource, Find-Module, Find-RoleCapability...}                               
Script     1.6.0      PowerShellGet                       {Install-Module, Find-Module, Save-Module, Update-Module...}                                        
Script     1.1.3.1    PowerShellGet                       {Install-Module, Find-Module, Save-Module, Update-Module...}                                        
Script     1.0.0.1    PowerShellGet                       {Install-Module, Find-Module, Save-Module, Update-Module...}                                        

Contributor guide

Open the contributing guide

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

Research direction

Begin with the Update-Module reproduction using PANSIES and the listed PowerShellGet and PackageManagement versions. Trace the Install-Package path around the locked binary and failed replacement. Done means a prerelease update reports the locking problem accurately, preserves the existing module when installation fails, and succeeds after the module is no longer in use.

Written by the indexing model from the issue text.

Assessment

Tech stack
powershell
Domain
cli, tooling
Issue type
Bug
Difficulty
5/5
Estimated time
Over a week
Activity status
Stale
Clarity
Mostly clear
Newbie friendliness
28/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.