Skip to content

PowerShell included modules does not have a version directory like Windows PowerShell had, causing assembly conflict on module import #21199

Description

Prerequisites

Steps to reproduce

Issue

I recently experienced a problem with importing a newer version of Microsoft.PowerShell.PSResourceGet (v1.0.2) than what is included with PowerShell 7.4.1 (v1.0.1):

I started researching and noticed that:

  • With Windows PowerShell, included modules are added to a version directory:
    • %ProgramW6432%\WindowsPowerShell\Modules\<modulename>\<version>\<content>
  • PSResourceGet, PowerShellGet and PackageManagement installs modules to:
    • <installpath>\<modulename>\<version>\<content>.
  • PowerShell does not have this version directory for included modules:
    • %ProgramW6432%\PowerShell\7\Modules\<modulename>\<content>

Is this intentional? Can this cause the issue I experience with PSResourceGet?

My understanding of the issue

It seems that when Import-Module searches through $env:PSModulePath for available modules to import, and stumbles across a module that is not contained in a directory consisting of its' version number, it will lazily import assemblies and thus block importing of any other version of the same module.

Ways to mitigate this

Three different ways to get Import-Module -Name 'Microsoft.PowerShell.PSResourceGet' -Version 1.0.2 to work.

  • Delete the included module: %ProgramW6432%\PowerShell\7\Modules\Microsoft.PowerShell.PSResourceGet
  • Move included module to a versioned directory:
    • From: %ProgramW6432%\PowerShell\7\Modules\Microsoft.PowerShell.PSResourceGet\*
    • To: %ProgramW6432%\PowerShell\7\Modules\Microsoft.PowerShell.PSResourceGet\1.0.1\*
  • Reorder $env:PSModulePath to have the path with the newest version of the module first.
    • I do this in my PowerShell profile now.

Expected behavior

PS> Import-Module -Name 'Microsoft.PowerShell.PSResourceGet' -RequiredVersion 1.0.2
PS>

Actual behavior

PS> Import-Module -Name 'Microsoft.PowerShell.PSResourceGet' -RequiredVersion 1.0.2
Import-Module: Assembly with same name is already loaded
PS>

Error details

See: #21201

Environment data

  • Windows 11 23H2.
  • PowerShell 7.4.1 with Microsoft.PowerShell.PSResourceGet v1.0.1 included/embedded.
  • Microsoft.PowerShell.PSResourceGet v1.0.2 installed in some other directory added to PSModulePath.

Visuals

No response

Activity

  1. rhubarb-geek-nz commented on Feb 8, 2024

    @rhubarb-geek-nz

    Is this intentional? Can this cause the issue I experience with PSResourceGet?

    Have a look at $env:PSModulePath, for example mine is

    D:\OneDrive\Documents\PowerShell\Modules;C:\Program Files\PowerShell\Modules;c:\program files\powershell\7\Modules;C:\Program Files\WindowsPowerShell\Modules;C:\WINDOWS\system32\WindowsPowerShell\v1.0\Modules
    

    The directories that you listed at the ones that are part of the MSI install and should be static or managed by the MSI and updated with a new MSI. I suggest you should not be overwriting those.

    Your installed modules should go in, say in my case D:\OneDrive\Documents\PowerShell\Modules. Here install-module does give them the module-name/version directory structure.

    D:\> tree D:\OneDrive\Documents\PowerShell\Modules
    Folder PATH listing for volume data512
    Volume serial number is 3EE9-A4CC
    D:\ONEDRIVE\DOCUMENTS\POWERSHELL\MODULES
    ├───rhubarb-geek-nz.CancellationTokenEvent
    │   └───1.0.1
    ├───rhubarb-geek-nz.Forever
    │   └───0.0.2
    ├───rhubarb-geek-nz.MySqlConnection
    │   └───2.3.1
    ├───rhubarb-geek-nz.NpgsqlConnection
    │   └───7.0.6
    ├───rhubarb-geek-nz.OracleConnection.Core
    │   └───3.21.120
    ├───rhubarb-geek-nz.PowerShellDataFile
    │   └───1.0.0
    ├───rhubarb-geek-nz.SqlConnection
    │   └───1.0.4
    └───rhubarb-geek-nz.SQLiteConnection
        └───1.0.118.0
            ├───linux-arm
            ├───linux-arm64
            ├───linux-x64
            ├───osx-arm64
            ├───osx-x64
            ├───win-arm
            ├───win-arm64
            ├───win-x64
            └───win-x86
    
  2. o-l-a-v commented on Feb 8, 2024

    @o-l-a-v
    Author

    rhubarb-geek-nz

    Sure. Here's my scenario though:

    • If installing modules in user context/scope and you have OneDrive for Business (ODfB) Known Folder Move (KFM) enabled, PSResourceGet, PowerShellGet and PackageManagement will install modules to %OneDrive%\Documents\PowerShell\Modules% (due to the folder redirection by ODfB KFM), and thus sync thousands of small files to OneDrive.
    • I don't want this behavior, so I've made a directory %LOCALAPPDATA%\Microsoft\PowerShell\Modules where I install modules using Save-PSResource as Install-PSResource does not care about $env:PSModulePath and instead uses hardcoded paths for user and system context.

    I end up with:

    Module Version Path
    Microsoft.PowerShell.PSResourceGet v1.0.1 %ProgramW6432%\PowerShell\7\Modules\Microsoft.PowerShell.PSResourceGet\<content>
    Microsoft.PowerShell.PSResourceGet v1.0.2 %LOCALAPPDATA%\Microsoft\PowerShell\Modules\Microsoft.PowerShell.PSResourceGet\1.0.2\<content>

    Starting a fresh pwsh.exe v7.4.1 window gives me the following:

    PowerShell 7.4.1
    PS C:\Users\olavb> [System.Environment]::GetEnvironmentVariable('PSModulePath','Process').Split(';')
    C:\Users\olavb\Documents\PowerShell\Modules
    C:\Program Files\PowerShell\Modules
    c:\program files\powershell\7\Modules
    C:\Users\olavb\AppData\Local\Microsoft\PowerShell\Modules
    C:\Program Files\WindowsPowerShell\Modules
    C:\WINDOWS\system32\WindowsPowerShell\v1.0\Modules
    PS C:\Users\olavb> [System.Environment]::GetEnvironmentVariable('PSModulePath','User').Split(';')
    C:\Users\olavb\AppData\Local\Microsoft\PowerShell\Modules
    PS C:\Users\olavb> [System.Environment]::GetEnvironmentVariable('PSModulePath','Machine').Split(';')
    C:\Program Files\WindowsPowerShell\Modules
    C:\WINDOWS\system32\WindowsPowerShell\v1.0\Modules
    PS C:\Users\olavb>

    And

    PS C:\Users\olavb> Get-Module -ListAvailable 'Microsoft.PowerShell.PSResourceGet' | Format-List -Property 'Name','Version','Path'
    
    
    Name    : Microsoft.PowerShell.PSResourceGet
    Version : 1.0.1
    Path    : C:\program files\powershell\7\Modules\Microsoft.PowerShell.PSResourceGet\Microsoft.PowerShell.PSResourceGet.psd1
    
    Name    : Microsoft.PowerShell.PSResourceGet
    Version : 1.0.2
    Path    : C:\Users\olavb\AppData\Local\Microsoft\PowerShell\Modules\Microsoft.PowerShell.PSResourceGet\1.0.2\Microsoft.PowerShell.PSResourceGet.psd1
    
    
    PS C:\Users\olavb>

    Then, importing v1.0.2 gives:

    PS C:\Users\olavb> Import-Module -Name 'Microsoft.PowerShell.PSResourceGet' -RequiredVersion 1.0.2
    Import-Module: Assembly with same name is already loaded
    PS C:\Users\olavb>

    This indicates to me that something outside of my preferences and settings are having issues. What it is I don't know.

  3. rhubarb-geek-nz commented on Feb 8, 2024

    @rhubarb-geek-nz

    This indicates to me that something outside of my preferences and settings are having issues. What it is I don't know.

    It may be a chicken-and-egg problem with PSResourceGet where that is loaded early on before it starts recognizing PSModulePath.

    Can you do show the same scenario with a different module?

  4. o-l-a-v commented on Feb 8, 2024

    @o-l-a-v
    Author

    Yes, actually. v7.4.1 also got Microsoft.PowerShell.ThreadJob v2.0.3. Only that it's in directory ThreadJob:

    image

    If renaming that directory to Microsoft.PowerShell.ThreadJob, and renaming the psd1 file too, we get the following (with a newer version installed outside this dir):

    PS C:\Users\olavb> Get-Module -ListAvailable 'Microsoft.PowerShell.ThreadJob' | Format-List -Property 'Name','Version','Path'
    
    Name    : Microsoft.PowerShell.ThreadJob
    Version : 2.0.3
    Path    : C:\program files\powershell\7\Modules\Microsoft.PowerShell.ThreadJob\Microsoft.PowerShell.ThreadJob.psd1
    
    Name    : Microsoft.PowerShell.ThreadJob
    Version : 2.1.0
    Path    : C:\Users\olavb\AppData\Local\Microsoft\PowerShell\Modules\Microsoft.PowerShell.ThreadJob\2.1.0\Microsoft.PowerShell.ThreadJob.psd1
    
    PS C:\Users\olavb>

    And voila:

    PS C:\Users\olavb> Import-Module -Name 'Microsoft.PowerShell.ThreadJob' -RequiredVersion '2.1.0'
    Import-Module: Assembly with same name is already loaded
    PS C:\Users\olavb>

    Ergo:

    • This is module independent.
    • If adding a <version> directory for the PowerShell included/embedded modules, import works as expected.
      PS C:\Users\olavb> Get-Module -ListAvailable 'Microsoft.PowerShell.ThreadJob' | Format-List -Property 'Name','Version','Path'
      
      Name    : Microsoft.PowerShell.ThreadJob
      Version : 2.0.3
      Path    : C:\program files\powershell\7\Modules\Microsoft.PowerShell.ThreadJob\2.0.3\Microsoft.PowerShell.ThreadJob.psd1
      
      Name    : Microsoft.PowerShell.ThreadJob
      Version : 2.1.0
      Path    : C:\Users\olavb\AppData\Local\Microsoft\PowerShell\Modules\Microsoft.PowerShell.ThreadJob\2.1.0\Microsoft.PowerShell.ThreadJob.psd1
      
      PS C:\Users\olavb> Import-Module -Name 'Microsoft.PowerShell.ThreadJob' -RequiredVersion '2.1.0'
      PS C:\Users\olavb>
    • Thus this GitHub issue is still valid as far as I understand.
  5. rhubarb-geek-nz commented on Feb 8, 2024

    @rhubarb-geek-nz

    In your path

    C:\Users\olavb\Documents\PowerShell\Modules
    C:\Program Files\PowerShell\Modules
    c:\program files\powershell\7\Modules
    C:\Users\olavb\AppData\Local\Microsoft\PowerShell\Modules
    

    Your 1.0.2 in AppData\Local is after 1.0.1 in powershell\7 in the path sequence.

    So it finds 1.0.1 before 1.0.2

    If 1.0.2 was in C:\Users\olavb\Documents\PowerShell\Modules then does it find it?

  6. o-l-a-v commented on Feb 8, 2024

    @o-l-a-v
    Author

    I don't know how $env:PSModulePath in process context is stitched together.

    If I set my preferred module path first; yes, that also works.

    PowerShell 7.4.1
    PS C:\Users\olavb> $env:PSModulePath.Split(';')
    C:\Users\olavb\Documents\PowerShell\Modules
    C:\Program Files\PowerShell\Modules
    c:\program files\powershell\7\Modules
    C:\Users\olavb\AppData\Local\Microsoft\PowerShell\Modules
    C:\Program Files\WindowsPowerShell\Modules
    C:\WINDOWS\system32\WindowsPowerShell\v1.0\Modules
    
    PS C:\Users\olavb> [System.Environment]::SetEnvironmentVariable(
    >>     'PSModulePath',
    >>     (
    >>         $(
    >>             [string[]](
    >>                 [System.Environment]::GetEnvironmentVariable('PSModulePath','User'),
    >>                 [System.IO.Path]::Combine($PSHOME,'Modules')
    >>             ) -join [System.IO.Path]::PathSeparator
    >>         )
    >>     ),
    >>     'Process'
    >> )
    
    PS C:\Users\olavb> $env:PSModulePath.Split(';')
    C:\Users\olavb\AppData\Local\Microsoft\PowerShell\Modules
    C:\Program Files\PowerShell\7\Modules
    
    PS C:\Users\olavb> Get-Module -ListAvailable 'Microsoft.PowerShell.PSResourceGet' | Format-List -Property 'Name','Version','Path'
    
    Name    : Microsoft.PowerShell.PSResourceGet
    Version : 1.0.2
    Path    : C:\Users\olavb\AppData\Local\Microsoft\PowerShell\Modules\Microsoft.PowerShell.PSResourceGet\1.0.2\Microsoft.
              PowerShell.PSResourceGet.psd1
    
    Name    : Microsoft.PowerShell.PSResourceGet
    Version : 1.0.1
    Path    : C:\Program Files\PowerShell\7\Modules\Microsoft.PowerShell.PSResourceGet\Microsoft.PowerShell.PSResourceGet.p
              sd1
    
    PS C:\Users\olavb> Import-Module -Name 'Microsoft.PowerShell.PSResourceGet' -RequiredVersion 1.0.2
    PS C:\Users\olavb>

    So yes, adding a profile script to change the order of PSModulePath could be a workaround. But it shouldn't be neccessary for basic functionality one expects to work.

  7. rhubarb-geek-nz commented on Feb 8, 2024

    @rhubarb-geek-nz

    So yes, adding a profile script to change the order of PSModulePath could be a workaround. But it shouldn't be neccessary for basic functionality one expects to work.

    That is consistent with how paths normally work. I could have five different versions of pwsh.exe on my system, but the one that is found first in PATH is the one that will be run.

    Now you could argue that it should read all the entries in all the module path directories and then select the one with the highest version. That would be sensible but currently I don't think that is implemented.

  8. o-l-a-v commented on Feb 8, 2024

    @o-l-a-v
    Author

    That is consistent with how paths normally work. I could have five different versions of pwsh.exe on my system, but the one that is found first in PATH is the one that will be run.

    Except that it works as expected if you add a <version> directory to the PowerShell embedded modules.

    Example:

    • Before: %ProgramW6432%\PowerShell\7\Modules\Microsoft.PowerShell.PSResourceGet\<content>
    • After: %ProgramW6432%\PowerShell\7\Modules\Microsoft.PowerShell.PSResourceGet\1.0.1\<content>

    So there's currently two workarounds I know of:

    1. Add embedded module to a <version> directory
      • Before: %ProgramW6432%\PowerShell\7\Modules\<modulename>\<content>
      • After: %ProgramW6432%\PowerShell\7\Modules\<modulename>\<version>\<content>
    2. Change order of PSModulePath paths in process context to have directory with newest version of module first, then import.
  9. rhubarb-geek-nz commented on Feb 8, 2024

    @rhubarb-geek-nz

    You can set PSModulePath in your environment before you run pwsh.exe if that helps.

    I would avoid changing the contents of MSI installed directories. If you upgrade you will get the version-less directory back again.

  10. o-l-a-v commented on Feb 8, 2024

    @o-l-a-v
    Author

    You can set PSModulePath in your environment before you run pwsh.exe if that helps.

    Yes, which makes this a bug with PowerShell IMO.

    I would avoid changing the contents of MSI installed directories. If you upgrade you will get the version-less directory back again.

    I agree. This was more of a proof that theres a breaking change between how Windows PowerShell included modules vs. how PowerShell does it. :)

  11. jborean93 commented on Feb 8, 2024

    @jborean93
    Collaborator

    AFAIK There are three types of directories included in PSModulePath

    Scope WinPS Path Pwsh Path
    System C:\Windows\System32\WindowsPowerShell\v1.0\Modules C:\Program Files\PowerShell\7\Modules
    AllUsers C:\Program Files\WindowsPowerShell\Modules C:\Program Files\PowerShell\Modules
    CurrentUser C:\Users$username\Documents\WindowsPowerShell\Modules C:\Users$username\Documents\PowerShell\Modules

    PowerShell 7 muddies the water a bit as it also pulls in the System and AllUsers from WinPS but that's more for backwards compatibility support.

    The System scope is modules bundled specifically with the PowerShell install. You aren't meant to touch these as it's what PowerShell technically ships with. This does not have version specific directories as it's only ever meant to contain 1 version of the module. The AllUsers and CurrentUser scopes are what Install-Module, Install-PSResource can manage and contains versioned module entries.

    While you aren't meant to touch the System ones it seems like there might be an assembly conflict happening here stopping you from loading the newer version. I’ll have to take a closer look to see what that is and why PowerShell is still loading the existing module when a newer one should theoretically be preferred.

  12. jborean93 commented on Feb 9, 2024

    @jborean93
    Collaborator

    I've just done a test, you can install the version side by side but as the module loads a binary and .NET only allows one version of the same binary to be loaded it will fail when you attempt to import a newer version in the same process. This is only the case when trying to import straight after upgrading. Starting a fresh new process works just fine though as it will favour the new version.

    PowerShell 7.4.1
    PS C:\Users\vagrant-domain> Import-module Microsoft.PowerShell.PSResourceGet -PassThru
    
    ModuleType Version    PreRelease Name                                ExportedCommands
    ---------- -------    ---------- ----                                ----------------
    Binary     1.0.1                 Microsoft.PowerShell.PSResourceGet  {Find-PSResource, Get-InstalledPSResource, Get-PS…
    
    PS C:\Users\vagrant-domain> Install-module -Name Microsoft.PowerShell.PSResourceGet -Scope AllUsers -Force
    PS C:\Users\vagrant-domain> Import-module Microsoft.PowerShell.PSResourceGet -PassThru
    Import-Module: Assembly with same name is already loaded
    PS C:\Users\vagrant-domain> pwsh { Import-module Microsoft.PowerShell.PSResourceGet -PassThru }
    
    ModuleType Version    PreRelease Name                                ExportedCommands
    ---------- -------    ---------- ----                                ----------------
    Binary     1.0.2                 Microsoft.PowerShell.PSResourceGet  {Find-PSResource, Get-InstalledPSResource, Get-PS…

    TLDR: You can have newer versions that are favoured over the package provided ones, you just can't load multiple versions in the same process.

  13. o-l-a-v commented on Feb 9, 2024

    @o-l-a-v
    Author

    Try to change PSModulePath in process context to have the path to the packaged version first Jordan Borean (@jborean93), then try importing the newest version. Then loading the newest version fails, even in a fresh session, even is specifying -RequiredVersion. Somehow the packaged assembly gets loaded in the process.

    I use a non-standard path because of OneDrive for Business KFM. Then my path, even though I've added it to PSModulePath in user context, gets added as one if the lasts paths in PSModulePath in process context. Related issue:

    Edit: One more way to mitigate this; override path in Import-Module -Name like so:

    Import-Module -Name ('{0}\Microsoft\PowerShell\Modules\Microsoft.PowerShell.PSResourceGet' -f $env:LOCALAPPDATA) -RequiredVersion '1.0.2'
  14. o-l-a-v commented on Feb 9, 2024

    @o-l-a-v
    Author

    If I understand this correctly: Generation of PSModulePath does not work as documented here:

    Documentation says it will add PSModulePath in user context first if it exists. Which it does for me. Still $PSHOME gets prioritized over it.

    PowerShell 7.4.1
    PS C:\Users\olav.birkeland> [System.Environment]::GetEnvironmentVariable('PSModulePath','User').Split(';')
    %LOCALAPPDATA%\Microsoft\PowerShell\Modules
    
    PS C:\Users\olav.birkeland> [System.Environment]::GetEnvironmentVariable('PSModulePath','Process').Split(';')
    C:\Users\olav.birkeland\OneDrive - <my_employer>\Documents\PowerShell\Modules
    C:\Program Files\PowerShell\Modules
    c:\program files\powershell\7\Modules
    C:\Users\olav.birkeland\AppData\Local\Microsoft\PowerShell\Modules
    C:\Program Files\WindowsPowerShell\Modules
    C:\WINDOWS\system32\WindowsPowerShell\v1.0\Modules
    
    PS C:\Users\olav.birkeland>

    While Windows PowerShell functions as I'd expect in this regard.

    PS C:\Users\olav.birkeland> [System.Environment]::GetEnvironmentVariable('PSModulePath','Process').Split(';')
    C:\Users\olav.birkeland\AppData\Local\Microsoft\PowerShell\Modules
    C:\Program Files\WindowsPowerShell\Modules
    C:\WINDOWS\system32\WindowsPowerShell\v1.0\Modules
    
    PS C:\Users\olav.birkeland> [System.Environment]::GetEnvironmentVariable('PSModulePath','User').Split(';')
    %LOCALAPPDATA%\Microsoft\PowerShell\Modules
    
    PS C:\Users\olav.birkeland> $psVersionTable
    
    Name                           Value
    ----                           -----
    PSVersion                      5.1.22621.2506
    PSEdition                      Desktop
    PSCompatibleVersions           {1.0, 2.0, 3.0, 4.0...}
    BuildVersion                   10.0.22621.2506
    CLRVersion                     4.0.30319.42000
    WSManStackVersion              3.0
    PSRemotingProtocolVersion      2.3
    SerializationVersion           1.1.0.1
    
    
    PS C:\Users\olav.birkeland>

    If PSModulePath in user context was prioritized over $PSHOME\Modules loading newer versions of PSResourceGet and ThreadJob would work as expected.

  15. o-l-a-v commented on Feb 9, 2024

    @o-l-a-v
    Author

    Seems PowerShell is hardcoded to prioritize built in modules over PSModulePath:

    // If it is one of built-in modules, first try loading it from $PSHOME\Modules, otherwise rely on $env:PSModulePath.

  16. changed the title [-]PowerShell included modules does not have a version directory like Windows PowerShell had[/-] [+]PowerShell included modules does not have a version directory like Windows PowerShell had, causing assembly conflic on import[/+] on Feb 28, 2026
  17. changed the title [-]PowerShell included modules does not have a version directory like Windows PowerShell had, causing assembly conflic on import[/-] [+]PowerShell included modules does not have a version directory like Windows PowerShell had, causing assembly conflic on module import[/+] on Feb 28, 2026
  18. o-l-a-v commented on Feb 28, 2026

    @o-l-a-v
    Author

    Two years have gone by.

    Why can't included modules just be added to a versioned directory so we don't have to deal with this?

    I created this quick and dirty script to do this after installation:

    Click to expand
    <#
        .NOTES
            Author:   Olav Rønnestad Birkeland | github.com/o-l-a-v
            Created:  2026-02-28
            Modified: 2026-02-28
    
            It seems that when `Import-Module` searches through `$env:PSModulePath` for available modules to import,
            and stumbles across a module that is not contained in a directory consisting of its' version number,
            it will lazily import assemblies and thus block importing of any other version of the same module.
    
            * Triggers this: `Modules/<module_name>/<module_name>.psd1`
            * Does not trigger this: `Modules/<module_name>/<module_version>/<module_name>.psd1`
    
            Related:
    
            * 2025-02-08: <https://github.com/PowerShell/PowerShell/issues/21201>
            * 2024-02-08: <https://github.com/PowerShell/PowerShell/issues/21199>
    
            Thoughts on how to fix: Put included modules in a versioned directory.
    
            * Do not use `Get-Module` to find the module version as it might lazy load the module, which will block moving it.
              * Thus parse "<module_name>.psd1" manually.
    
        .EXAMPLE
            . $psEditor.GetEditorContext().CurrentFile.Path -ModulesDirectory (
                'C:\Users\olavb\scoop\apps\pwshp\7.6.0-rc.1\Modules'
            ) -WhatIf
    #>
    
    
    # Input and expected output
    [CmdletBinding(SupportsShouldProcess)]
    [OutputType([System.Void])]
    Param(
        [Parameter(Mandatory)]
        [ValidateNotNullOrWhiteSpace()]
        [ValidateScript({[System.IO.Directory]::Exists($_)})]
        $ModulesDirectory
    )
    
    
    # PowerShell preferences
    $ErrorActionPreference = 'Stop'
    $InformationPreference = 'Continue'
    
    
    # Find info
    $Modules = [array](Get-ChildItem -Path $ModulesDirectory -Directory)
    $ModulesDetails = [PSCustomObject[]](
        $Modules.ForEach{
            [PSCustomObject]@{
                'Name' = [string] $_.'Name'
                'Path' = [string] $_.'FullName'
                'Psd1' = [System.IO.Path]::Combine($_.'FullName', [string]::Format('{0}.psd1' -f $_.'Name'))
            }
        }.ForEach{
            Add-Member -InputObject $_ -PassThru -NotePropertyMembers @{
                'Psd1Exists' = [bool]([System.IO.File]::Exists($_.'Psd1'))
            }
        } | Sort-Object -Property 'Name'
    )
    
    
    # Move modules into a versioned directory
    foreach ($Module in $ModulesDetails) {
        # Output current module
        Write-Information -MessageData (
            '{0}# {1}' -f
            $(if($ModulesDetails.IndexOf($Module -ne 0)){[System.Environment]::NewLine}),
            $Module.'Name'
        )
        # Failproof: Make sure Psd1 file exists at expected path
        if (-not $Module.'Psd1Exists') {
            Write-Information -MessageData (
                '"{0}" was not found, has probably been processed already.' -f
                $Module.'Psd1'
            )
            Continue
        }
        # Get version from Psd1 file
        $Version = [System.Version](
            (
                [System.IO.File]::ReadAllLines($Module.'Psd1').Where(
                    {
                        -not [string]::IsNullOrWhiteSpace($_) -and
                        $_.Trim() -match '^ModuleVersion\s{0,}='
                    },
                    'First'
                )[0] -as [string] -replace '\s{1,}' -replace '''', '"'
            ).Split('"')[1]
        )
        # Failproof: Don't continue if version could not be parsed
        if ([string]::IsNullOrWhiteSpace($Version)) {
            Write-Information -MessageData 'Failed to find version.'
            Continue
        }
        # Generate new path
        $NewPath = [System.IO.Path]::Combine($Module.'Path', $Version)
        # Find items to be moved
        $ItemsToMove = [string[]](
            (Get-ChildItem -Path $Module.'Path').'FullName'
        )
        if ($PSCmdlet.ShouldProcess($NewPath, 'Move')) {
            $null = [System.IO.Directory]::CreateDirectory($NewPath)
            $ItemsToMove.ForEach{
                $null = Move-Item -Path $_ -Destination $NewPath
            }
            Write-Information -MessageData ('Successfully moved files into "{0}".' -f $NewPath)
        }
    }
    
  19. changed the title [-]PowerShell included modules does not have a version directory like Windows PowerShell had, causing assembly conflic on module import[/-] [+]PowerShell included modules does not have a version directory like Windows PowerShell had, causing assembly conflict on module import[/+] on Feb 28, 2026
  20. kilasuit commented on Jun 23, 2026

    @kilasuit
    Collaborator

    Why can't included modules just be added to a versioned directory

    This has been previously discussed in #2350

    Until the module is decoupled from PSCore itself, there's no value to have it in a versioned folder since it's not updatable outside of updating PSCore itself. The ones that have versioned folders are those obtained from PSGallery.

    This is by design for maintenance and supportability reasons

  21. o-l-a-v commented on Jun 23, 2026

    @o-l-a-v
    Author

    Ryan Yates (@kilasuit): I guess the fix is to fix the installed modules version lookup to not lazy load assemblies then, or whatever it does. Maybe it could do that discovery in a child process?

  22. rhubarb-geek-nz commented on Jun 23, 2026

    @rhubarb-geek-nz

    It seems to me that PowerShell is using a brute force module discovery mechanism that works for looking for executables on a PATH but not modules in nested subtrees. I suggest the problem is the promise that you can just add a module by copying into a directory on the path and PowerShell will eventually find it and use it.

    Does PowerShell manage a persistent index for the modules it knows about?

    If PowerShell maintained an index in a simple database where manifest files were added and removed by Install-Module/Install-PSResource/Uninstall-Module/Uninstall-PSResource etc then cmdlets etc would be found by referring to the manifests in the index rather than exhaustive searches in the file system.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    Needs-TriageThe issue is new and needs to be triaged by a work group.

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions