PowerShellGetv2 icon indicating copy to clipboard operation
PowerShellGetv2 copied to clipboard

Update-Module doesn't update dependencies and is generally not good enough

Open PrzemyslawKlys opened this issue 5 years ago • 11 comments

Currently, Update-Module behavior is a bit special. When creating modules and writing blog posts I've usually told people to use Install-Module, and later on use Update-Module when a new version is out. However, that brings more problems then it solves, and I've recently stopped recommending Update-Module.

When you do:

Update-Module <module>

It updates:

  • only main module
  • it doesn't update dependent modules
  • it doesn't download any new modules that were added as dependant on in next version
  • it updates module by downloading new version leaving the old one in its place

This leads to less than useful command. I've people doing Update-Module and then complaining about things not working. But that's because I've updated 3-5 other modules with different functionalities that make the main module what it is.

People have much better results of just using:

Install-Module <module> -Force

Or in some cases:

Install-Module <module> -Force -AllowClober -SkipPublisherCheck -AcceptEula

This gives me:

  • the newest version of the main module
  • the latest version of any dependent modules
  • always downloads any new modules that were added in the new version
  • puts update module next to the old one.

See the difference? It does everything Update-Module was supposed to do, except better.

In my opinion Update-Module should:

  • update the main module
  • update any dependencies (if not used with -force, prompt)
  • update any newly added dependencies
  • preferably uninstall any old modules, but I can see how this can be tricky if some people want to keep using an older version

It also touches the issue described here: https://github.com/PowerShell/PowerShellGet/issues/130

Further clarification:

  • Before

image

  • It seems that Update-Module -Force updates required modules

image

But in my opinion Update-module without force should at least ask for updating required modules.

PrzemyslawKlys avatar Apr 22 '19 12:04 PrzemyslawKlys

@PrzemyslawKlys What happen if you force module version in RequiredModules ? In my opinion, if you don't give something to compare, it doesn't have to update anything because your requirements are already satisfied.

fMichaleczek avatar Apr 24 '19 01:04 fMichaleczek

As shown on the screenshots if you use Update-Module -Force it will update things as required. Problem is Update-Module without force doesn't. It doesn't notice for example if you add new prerequisites (haven't tested with -Force). I often have primary module with functions that work, but I fix things in the backend and now even thou I've fixed them, they are better, faster, have more features people won't notice or worse it will break things and make your screen red. Update-Module should prompt, just like Install-module does if there are any other updates to the required modules that are already on the computer but also prompt for new ones (probably with a different question) if those were added after.

To me using Force is a bit over the top.

PrzemyslawKlys avatar Apr 24 '19 08:04 PrzemyslawKlys

@PrzemyslawKlys I wasn't speaking about Force parameter. I suggest you to try to explicitly put the version in RequiredModules (in your powershell module manifest)

RequiredModules = @( @{ModuleName = "Module1"; ModuleVersion = "1.0"; } )

If it's not working, there is a bug !

When a module require a module without version number, and it's present on your PSModulePath, it's normal, that it does nothing.

fMichaleczek avatar Apr 24 '19 17:04 fMichaleczek

Ok, I wasn't aware of this versioning thing which is great!

Modules that must be imported into the global environment prior to importing this module. This will load any modules listed unless they have already been loaded. (For example, some modules may already be loaded by a different module.). It is also possible to specify a specific version to load using RequiredVersion rather than ModuleVersion. When using ModuleVersion it will load the newest version available with a minimum of the version specified.

Example:

RequiredModules = @(@{ModuleName="myDependentModule"; ModuleVersion="2.0"; Guid="cfc45206-1e49-459d-a8ad-5b571ef94857"})

Example:

RequiredModules = @(@{ModuleName="myDependentModule"; RequiredVersion="1.5"; Guid="cfc45206-1e49-459d-a8ad-5b571ef94857"})

What surely doesn't work is that if you publish a module with no required modules, and then on next version you add required module it won't be picked up by Update-Module. So I would say there's a bug in this one. I remember moving some function to the external module and adding it as RequiredModule and update-module didn't even notice.

The other question is how Update-Module behaves on RequiredVersion vs ModuleVersion in comparison to PowerShell behavior on load.

PrzemyslawKlys avatar Apr 25 '19 11:04 PrzemyslawKlys

I read the code of Update-Module, and his job is to ask Install-Package to install the new version.

When you publish a module on the PSGallery, it converts required/moduleversion to nuspec format.

Install-Package verifies dependencies version in nuspec : InstallPackage.cs#L189

In theory, you will be able to correct your online package.

Can you test with a fake module ?

If it's not working, i will check the nuget package conversion that occurs when you upload a module.

PS : i never publish a module in Gallery, but I will, so I'm very interrested to solve this problem before

fMichaleczek avatar Apr 26 '19 00:04 fMichaleczek

Example 1

Windows PowerShell
Copyright (C) 2016 Microsoft Corporation. All rights reserved.

PS C:\Windows\system32> get-module -ListAvailable PSWinReporting


    Directory: C:\Program Files\WindowsPowerShell\Modules


ModuleType Version    Name                                ExportedCommands
---------- -------    ----                                ----------------
Script     1.7.7.0    PSWinReporting                      {Get-ComputerChanges, Get-ComputerStatus, Get-EventLogClea...
Script     1.7.4      PSWinReporting                      {Start-ADReporting, Start-Notifications, New-SubscriptionT...
Script     1.7.3      PSWinReporting                      {Start-ADReporting, Start-Notifications, New-SubscriptionT...
Script     1.7.0.16   PSWinReporting                      {Start-ADReporting, Start-Notifications, New-SubscriptionT...
Script     1.7.0.15   PSWinReporting                      {Start-ADReporting, Start-Notifications}


PS C:\Windows\system32> get-module -ListAvailable PSEventViewer


    Directory: C:\Program Files\WindowsPowerShell\Modules


ModuleType Version    Name                                ExportedCommands
---------- -------    ----                                ----------------
Script     1.0.2      PSEventViewer                       {Get-Events, Get-EventsFilter, Get-EventsInformation}
Script     0.63       PSEventViewer                       {Get-Events, Get-EventsFilter, Get-EventsInformation}
Script     0.62       PSEventViewer                       {Get-Events, Get-EventsFilter, Get-EventsInformation}
Script     0.61       PSEventViewer                       {Get-Events, Get-EventsFilter, Get-EventsInformation}
Script     0.51       PSEventViewer                       Get-Events


PS C:\Windows\system32> Get-Module -ListAvailable PSSharedGoods


    Directory: C:\Program Files\WindowsPowerShell\Modules


ModuleType Version    Name                                ExportedCommands
---------- -------    ----                                ----------------
Script     0.0.72     PSSharedGoods                       {Add-WinADUserGroups, Find-ADConnectServer, Find-ExchangeS...
Script     0.0.65     PSSharedGoods                       {Add-WinADUserGroups, Find-ADConnectServer, Find-ExchangeS...
Script     0.0.54     PSSharedGoods                       {Add-WinADUserGroups, Find-UsersProxyAddressesStatus, Get-...
Script     0.0.52     PSSharedGoods                       {Add-WinADUserGroups, Find-UsersProxyAddressesStatus, Get-...
Script     0.0.47     PSSharedGoods                       {Add-WinADUserGroups, Get-WinADForestControllers, Get-WinA...
Script     0.0.46     PSSharedGoods                       {Add-WinADUserGroups, Get-WinADForestControllers, Get-WinA...
Script     0.0.45     PSSharedGoods                       {Add-WinADUserGroups, Get-WinADOrganizationalUnitData, Get...


PS C:\Windows\system32> Get-Module -ListAvailable PSWriteExcel


    Directory: C:\Program Files\WindowsPowerShell\Modules


ModuleType Version    Name                                ExportedCommands
---------- -------    ----                                ----------------
Script     0.0.15     PSWriteExcel                        {Add-ExcelWorkSheet, Add-ExcelWorkSheetCell, Add-ExcelWork...
Script     0.0.1      PSWriteExcel


PS C:\Windows\system32> Get-Module -ListAvailable PSWriteHTML
PS C:\Windows\system32> update-module PSWinReporting
PS C:\Windows\system32>
PS C:\Windows\system32> Get-Module -ListAvailable PSWriteExcel


    Directory: C:\Program Files\WindowsPowerShell\Modules


ModuleType Version    Name                                ExportedCommands
---------- -------    ----                                ----------------
Script     0.0.15     PSWriteExcel                        {Add-ExcelWorkSheet, Add-ExcelWorkSheetCell, Add-ExcelWork...
Script     0.0.1      PSWriteExcel


PS C:\Windows\system32> Get-Module -ListAvailable PSSharedGoods


    Directory: C:\Program Files\WindowsPowerShell\Modules


ModuleType Version    Name                                ExportedCommands
---------- -------    ----                                ----------------
Script     0.0.72     PSSharedGoods                       {Add-WinADUserGroups, Find-ADConnectServer, Find-ExchangeS...
Script     0.0.65     PSSharedGoods                       {Add-WinADUserGroups, Find-ADConnectServer, Find-ExchangeS...
Script     0.0.54     PSSharedGoods                       {Add-WinADUserGroups, Find-UsersProxyAddressesStatus, Get-...
Script     0.0.52     PSSharedGoods                       {Add-WinADUserGroups, Find-UsersProxyAddressesStatus, Get-...
Script     0.0.47     PSSharedGoods                       {Add-WinADUserGroups, Get-WinADForestControllers, Get-WinA...
Script     0.0.46     PSSharedGoods                       {Add-WinADUserGroups, Get-WinADForestControllers, Get-WinA...
Script     0.0.45     PSSharedGoods                       {Add-WinADUserGroups, Get-WinADOrganizationalUnitData, Get...


PS C:\Windows\system32> get-module -ListAvailable PSEventViewer


    Directory: C:\Program Files\WindowsPowerShell\Modules


ModuleType Version    Name                                ExportedCommands
---------- -------    ----                                ----------------
Script     1.0.2      PSEventViewer                       {Get-Events, Get-EventsFilter, Get-EventsInformation}
Script     0.63       PSEventViewer                       {Get-Events, Get-EventsFilter, Get-EventsInformation}
Script     0.62       PSEventViewer                       {Get-Events, Get-EventsFilter, Get-EventsInformation}
Script     0.61       PSEventViewer                       {Get-Events, Get-EventsFilter, Get-EventsInformation}
Script     0.51       PSEventViewer                       Get-Events


PS C:\Windows\system32> get-module -ListAvailable PSWinReporting


    Directory: C:\Program Files\WindowsPowerShell\Modules


ModuleType Version    Name                                ExportedCommands
---------- -------    ----                                ----------------
Script     1.8.1.1    PSWinReporting                      {New-SubscriptionTemplates, Set-SubscriptionTemplates, Sta...
Script     1.7.7.0    PSWinReporting                      {Get-ComputerChanges, Get-ComputerStatus, Get-EventLogClea...
Script     1.7.4      PSWinReporting                      {Start-ADReporting, Start-Notifications, New-SubscriptionT...
Script     1.7.3      PSWinReporting                      {Start-ADReporting, Start-Notifications, New-SubscriptionT...
Script     1.7.0.16   PSWinReporting                      {Start-ADReporting, Start-Notifications, New-SubscriptionT...
Script     1.7.0.15   PSWinReporting                      {Start-ADReporting, Start-Notifications}


PS C:\Windows\system32> update-module PSWinReporting -Force
PS C:\Windows\system32> get-module -ListAvailable PSWinReporting


    Directory: C:\Program Files\WindowsPowerShell\Modules


ModuleType Version    Name                                ExportedCommands
---------- -------    ----                                ----------------
Script     1.8.1.1    PSWinReporting                      {New-SubscriptionTemplates, Set-SubscriptionTemplates, Sta...
Script     1.7.7.0    PSWinReporting                      {Get-ComputerChanges, Get-ComputerStatus, Get-EventLogClea...
Script     1.7.4      PSWinReporting                      {Start-ADReporting, Start-Notifications, New-SubscriptionT...
Script     1.7.3      PSWinReporting                      {Start-ADReporting, Start-Notifications, New-SubscriptionT...
Script     1.7.0.16   PSWinReporting                      {Start-ADReporting, Start-Notifications, New-SubscriptionT...
Script     1.7.0.15   PSWinReporting                      {Start-ADReporting, Start-Notifications}


PS C:\Windows\system32> get-module -ListAvailable PSEventViewer


    Directory: C:\Program Files\WindowsPowerShell\Modules


ModuleType Version    Name                                ExportedCommands
---------- -------    ----                                ----------------
Script     1.0.5      PSEventViewer                       {Get-Events, Get-EventsFilter, Get-EventsInformation}
Script     1.0.2      PSEventViewer                       {Get-Events, Get-EventsFilter, Get-EventsInformation}
Script     0.63       PSEventViewer                       {Get-Events, Get-EventsFilter, Get-EventsInformation}
Script     0.62       PSEventViewer                       {Get-Events, Get-EventsFilter, Get-EventsInformation}
Script     0.61       PSEventViewer                       {Get-Events, Get-EventsFilter, Get-EventsInformation}
Script     0.51       PSEventViewer                       Get-Events


PS C:\Windows\system32> Get-Module -ListAvailable PSSharedGoods


    Directory: C:\Program Files\WindowsPowerShell\Modules


ModuleType Version    Name                                ExportedCommands
---------- -------    ----                                ----------------
Script     0.0.74     PSSharedGoods                       {Add-WinADUserGroups, Find-ADConnectServer, Find-ExchangeS...
Script     0.0.72     PSSharedGoods                       {Add-WinADUserGroups, Find-ADConnectServer, Find-ExchangeS...
Script     0.0.65     PSSharedGoods                       {Add-WinADUserGroups, Find-ADConnectServer, Find-ExchangeS...
Script     0.0.54     PSSharedGoods                       {Add-WinADUserGroups, Find-UsersProxyAddressesStatus, Get-...
Script     0.0.52     PSSharedGoods                       {Add-WinADUserGroups, Find-UsersProxyAddressesStatus, Get-...
Script     0.0.47     PSSharedGoods                       {Add-WinADUserGroups, Get-WinADForestControllers, Get-WinA...
Script     0.0.46     PSSharedGoods                       {Add-WinADUserGroups, Get-WinADForestControllers, Get-WinA...
Script     0.0.45     PSSharedGoods                       {Add-WinADUserGroups, Get-WinADOrganizationalUnitData, Get...


PS C:\Windows\system32> Get-Module -ListAvailable PSWriteExcel


    Directory: C:\Program Files\WindowsPowerShell\Modules


ModuleType Version    Name                                ExportedCommands
---------- -------    ----                                ----------------
Script     0.1.0      PSWriteExcel                        {Add-ExcelWorkSheet, Add-ExcelWorkSheetCell, Add-ExcelWork...
Script     0.0.15     PSWriteExcel                        {Add-ExcelWorkSheet, Add-ExcelWorkSheetCell, Add-ExcelWork...
Script     0.0.1      PSWriteExcel

Example 2


PS C:\Windows\system32> get-module -ListAvailable PSWinDocumentation


    Directory: C:\Program Files\WindowsPowerShell\Modules


ModuleType Version    Name                                ExportedCommands
---------- -------    ----                                ----------------
Script     0.3.4      PSWinDocumentation                  {Start-Documentation, Start-ActiveDirectoryDocumentation, Get-WinADForestInformation, Get-WinADDomainInformation...}
Script     0.3.3      PSWinDocumentation                  {Start-Documentation, Start-ActiveDirectoryDocumentation, Get-WinADForestInformation, Get-WinADDomainInformation...}
Script     0.3.0      PSWinDocumentation                  {Start-Documentation, Start-ActiveDirectoryDocumentation, Get-WinADForestInformation, Get-WinADDomainInformation...}
Script     0.2.1      PSWinDocumentation                  {Start-Documentation, Start-ActiveDirectoryDocumentation, Get-WinADForestInformation, Get-WinADDomainInformation...}
Script     0.0.6      PSWinDocumentation                  {Start-Documentation, Start-WinDocumentationWorkstation, Start-ActiveDirectoryDocumentation, Get-WinADForestInformation...}


PS C:\Windows\system32> Get-Content -Raw -Path ((get-module -ListAvailable PSWinDocumentation).Path) | Invoke-Expression | ForEach-Object RequiredModules
PSWriteWord
PSWriteExcel
PSWriteColor
PSSharedGoods
PSWriteWord
PSWriteExcel
PSWriteColor
PSSharedGoods
PSWriteWord
PSWriteExcel
PSWriteColor
PSSharedGoods
PSWriteWord
PSWriteExcel
PSWriteColor
PSSharedGoods
PSWriteWord
PS C:\Windows\system32> Get-Content -Raw -Path ((get-module -ListAvailable PSWinDocumentation)[0].Path) | Invoke-Expression | ForEach-Object RequiredModules
PSWriteWord
PSWriteExcel
PSWriteColor
PSSharedGoods
PS C:\Windows\system32> update-module PSWinDocumentation

Untrusted repository
You are installing the modules from an untrusted repository. If you trust this repository, change its InstallationPolicy value by running the Set-PSRepository cmdlet. Are you sure you want to install the modules
from 'PSGallery'?
[Y] Yes  [A] Yes to All  [N] No  [L] No to All  [S] Suspend  [?] Help (default is "N"): y
PS C:\Windows\system32> get-module -ListAvailable PSWinDocumentation


    Directory: C:\Program Files\WindowsPowerShell\Modules


ModuleType Version    Name                                ExportedCommands
---------- -------    ----                                ----------------
Script     0.4.0      PSWinDocumentation                  Start-Documentation
Script     0.3.4      PSWinDocumentation                  {Start-Documentation, Start-ActiveDirectoryDocumentation, Get-WinADForestInformation, Get-WinADDomainInformation...}
Script     0.3.3      PSWinDocumentation                  {Start-Documentation, Start-ActiveDirectoryDocumentation, Get-WinADForestInformation, Get-WinADDomainInformation...}
Script     0.3.0      PSWinDocumentation                  {Start-Documentation, Start-ActiveDirectoryDocumentation, Get-WinADForestInformation, Get-WinADDomainInformation...}
Script     0.2.1      PSWinDocumentation                  {Start-Documentation, Start-ActiveDirectoryDocumentation, Get-WinADForestInformation, Get-WinADDomainInformation...}
Script     0.0.6      PSWinDocumentation                  {Start-Documentation, Start-WinDocumentationWorkstation, Start-ActiveDirectoryDocumentation, Get-WinADForestInformation...}


PS C:\Windows\system32> Get-Content -Raw -Path ((get-module -ListAvailable PSWinDocumentation)[0].Path) | Invoke-Expression | ForEach-Object RequiredModules
PSWriteWord
PSWriteExcel
PSSharedGoods
PSWinDocumentation.AD
PSWinDocumentation.AWS
PSWinDocumentation.O365
PS C:\Windows\system32>

So, after testing this more it seems everything works as designed. Not sure why it was failing for me before. I've not tested how it behaves with Module version vs RequiredVersion but it would seem that those options are there and it would be good to use them.

PrzemyslawKlys avatar Apr 30 '19 10:04 PrzemyslawKlys

Thanks @fmichaleczek ;-)

PrzemyslawKlys avatar Apr 30 '19 10:04 PrzemyslawKlys

I haven't looked at this issue in detail, but if you are finding that a whole new dependency is not being found by Update-Module I consider that a bug. I wasn't clear if that is the case or not.

Updating dependencies is more of a question - basically, when you say Update-Module X should we do the minimum possible, but updating the dependencies of X only if the have to be updated in order to update X, or should we update all of them to the latest versions which are compatible with the new version of X? I actually think the second is more consistent and useful, and I'm not sure that you should have to specify -Force to take advantage of it. But since this is a change in behavior which some people may be relying on, we need to be a little careful

edyoung avatar Apr 30 '19 20:04 edyoung

It seems it works correctly on new dependency. I believe I saw it not working correctly but after testing can't reproduce. So that's done.

After rereading documentation on RequiredModules and with @fMichaleczek advice I did something like that for my Module.

            RequiredModules = @(
                @{ ModuleName = 'PSEventViewer'; ModuleVersion = "1.0.5"; Guid = '5df72a79-cdf6-4add-b38d-bcacf26fb7bc' }
                @{ ModuleName = 'PSSharedGoods'; ModuleVersion = "0.0.74"; Guid = 'ee272aa8-baaa-4edf-9f45-b6d6f7d844fe' }
                @{ ModuleName = 'PSWriteExcel'; ModuleVersion = "0.1"; Guid = '82232c6a-27f1-435d-a496-929f7221334b' }
                @{ ModuleName = 'PSWriteHTML'; ModuleVersion = '0.0.30'; Guid = 'a7bdf640-f5cb-4acf-9de0-365b322d245c' }
            )

It seems that for Import-Module this means import newest version but not lower than specified. There's also RequiredVersion which can be specified for getting exact version regardless of what you have.

It seems that for Import-Module where only an array of module names is specified the action is to load newest available.

Now I've not tested yet those scenarios with Install-Module/Update-Module but I will soon. I see 2 scenarios:

  • [ ] if ModuleVersion is defined it will get that version if it's not installed
  • [ ] if ModuleVersion is defined it will get the newest version where it will fail if there's no version with at least ModuleVersion

Need to test that. I would prefer the newest version I guess since it would be similar to Import-Module

If there is RequiredModule with RequiredVersion I would expect Install-Module, Update-Module to always download that. Haven't tested, but I assume it works that way.

The tricky part is with modules that have RequiredModules as an array of module names. It seems the default behavior is if a module with any version exists use that and don't try to download newest. It's a bit counter-intuitive to what Import-Module does where it always loads the newest version, but I can understand the reason.

There are 2 choices here as I see it:

  • [ ] Leave it as it is (change in behavior may not be wanted - the question is how many people actually understand what are the defaults for this) - I guess I'll have a content to blog about this after all the tests ;-)
  • [ ] Start prompting people - There is a newer version of the module this module requires, would you like...

Again the tricky part is what is the intention of the author of the module. Does he know what happens if you configure it that way? I didn't know about the ability to define an array of hashes hence it was making me go nuts on the Update-Module because people would complain that things aren't working wasting their time trying to fix something.

But like I said above, it seems it is my fault for not reading the documentation and doing tests from A to Z. So I'll make that and hopefully, there will be nothing to complain anymore.

One more thing that people tend to complain to me is that if they open PowerShell, they use a function from my module, and then they do Update-Module -Force, even thou the module has been installed they still use the old module at this point. Maybe it would be worth an effort to add Import-Module <module> -Force or a prompt to do that? I guess if someone does Update-Module in the middle of the session their intention is to have that module loaded right? Of course it, it's tricky, because Import-Module does import-module only on the main module, not required modules so if those were updated... you would end up with the wrong set of modules loaded. Maybe a warning then?

The other complain we could have here is Update-Module basically does what Install-Module does in a way. It doesn't Update. It installs modules next to those already there. But I guess there's a reason it does that.

Again this all seems like I need to do all the tests first.

PrzemyslawKlys avatar May 01 '19 06:05 PrzemyslawKlys

The other complain we could have here is Update-Module basically does what Install-Module does in a way. It doesn't Update. It installs modules next to those already there. But I guess there's a reason it does that.

The official reason is here Concerns using Update-Module causing multiple versions of the same module

In my opinion, even if implemented, there will be a problem with module with dll. PowerShell can't unload a dll, so if you import this kind of module, you can't delete it.

fMichaleczek avatar May 12 '19 11:05 fMichaleczek

All my concerns have been addressed with your properly defining RequiredModules tip. It works as designed for me. Every time I release new modules I simply update other module and update module version requirement if it matters. So everything works for me.

PrzemyslawKlys avatar May 12 '19 11:05 PrzemyslawKlys