Please feel free to provide feedback or file bugs here.

Bug: Get-Module -List throws if an installed module uses Import-Module with $PSScriptRoot

In WMF 5.0 (tested on Win7 w/ KB3134760 and Win10 10240), the presence of certain Import-Module statements in a module in $env:PSModulePath will cause Get-Module -List to throw. In particular, if a module attempts to import another module with a path relative to $PSScriptRoot, it seems to break things. We do this type of thing within psm1s in cases where a manifest cannot express the behavior we need. Here's a repro:

## On Win7, using the re-released WMF 5.0 (KB3134760):

PS C:\> $PSVersionTable

Name Value
---- -----
PSVersion 5.0.10586.117
PSCompatibleVersions {1.0, 2.0, 3.0, 4.0...}
BuildVersion 10.0.10586.117
CLRVersion 4.0.30319.42000
WSManStackVersion 3.0
PSRemotingProtocolVersion 2.3
SerializationVersion 1.1.0.1

PS C:\> gwmi win32_operatingsystem | fl caption, version

caption : Microsoft Windows 7 Enterprise
version : 6.1.7601

## Say I have a directory of modules added to an otherwise stock %PSModulePath%, in this case C:\local\dummy:

PS C:\> $env:PSModulePath
C:\Users\whitema\Documents\WindowsPowerShell\Modules;C:\Program Files\WindowsPowerShell\Modules;C:\Windows\system32\WindowsPowerShell\v1.0\Modules;C:\local\dummy

## In that directory, I have two very simple modules with one function each, foo and bar. foo imports bar using $PSScriptRoot

PS C:\> ls -rec C:\local\dummy

Directory: C:\local\dummy

Mode LastWriteTime Length Name
---- ------------- ------ ----
d----- 3/5/2016 11:47 PM bar
d----- 3/5/2016 11:47 PM foo

Directory: C:\local\dummy\bar

Mode LastWriteTime Length Name
---- ------------- ------ ----
-a---- 3/6/2016 12:04 AM 24 bar.psm1

Directory: C:\local\dummy\foo

Mode LastWriteTime Length Name
---- ------------- ------ ----
-a---- 3/6/2016 12:05 AM 83 foo.psm1

PS C:\> cat C:\local\dummy\foo\foo.psm1
Import-Module (Join-Path $PSScriptRoot '..\bar')
function Get-Foo {'foo'; Get-Bar}
PS C:\> cat C:\local\dummy\bar\bar.psm1
function Get-Bar {'bar'}

## Now, get rid of any existing CommandAnalysis cache and make sure I'm in a fresh shell, otherwise this many not be reproducible, then run Get-Module -ListAvailable. This works without specifying the module name too, it's only shown here to limit the output. DO NOT PRESS TAB WHILE DOING THIS, it may cause a command analysis cache file to be created and break the repro.

PS C:\> get-module -list foo
get-module : The specified module '(Join-Path $PSScriptRoot '..\bar')' was not found. Update the Name parameter to
point to a valid path, and then try again.
At line:1 char:1
+ get-module -list foo
+ ~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : ResourceUnavailable: ((Join-Path $PSScriptRoot '..\bar'):String) [Get-Module], FileNotFo
undException
+ FullyQualifiedErrorId : Modules_ModuleNotFoundForGetModule,Microsoft.PowerShell.Commands.GetModuleCommand

Directory: C:\local\dummy

ModuleType Version Name ExportedCommands
---------- ------- ---- ----------------
Script 0.0 foo Get-Foo

## This error only occurs when running Get-Module without having already imported the module. Also, if there is a valid CommandAnalysis file for the module, then no error is thrown.

PS C:\> ipmo foo
PS C:\> get-module -list foo

Directory: C:\local\dummy

ModuleType Version Name ExportedCommands
---------- ------- ---- ----------------
Script 0.0 foo {Get-Foo, Get-Bar}

## Won't be reproducible immediately in a new shell because of the CommandAnalysis cache.

PS C:\> exit
PS C:\> powershell -noprofile
Windows PowerShell
Copyright (C) 2015 Microsoft Corporation. All rights reserved.

PS C:\> get-module -list foo

Directory: C:\local\dummy

ModuleType Version Name ExportedCommands
---------- ------- ---- ----------------
Script 0.0 foo {Get-Foo, Get-Bar}

## While attempting to debug this, I also noticed some strange behavior - in the debug shell $PSScriptRoot appears to be an empty string, but it seems to work in spite of that. I've also seen a scenario where the variable object from get-variable showed the expected path, but just using $PSScriptRoot evaluated to an empty string. I can't seem to repro that behavior reliably though. This does not cause any problem beyond confusion, but I'm mentioning it because perhaps it's related?

PS C:\> exit
PS C:\> rm -rec $env:localappdata\Microsoft\Windows\PowerShell\CommandAnalysis
PS C:\> powershell -noprofile
Windows PowerShell
Copyright (C) 2015 Microsoft Corporation. All rights reserved.

PS C:\> set-psbreakpoint -line 1 C:\local\dummy\foo\foo.psm1

ID Script Line Command Variable Action
-- ------ ---- ------- -------- ------
0 foo.psm1 1

PS C:\> $VerbosePreference = 'continue'
PS C:\> ipmo foo
VERBOSE: Loading module from path 'C:\local\dummy\foo\foo.psm1'.
Entering debug mode. Use h or ? for help.

Hit Line breakpoint on 'C:\local\dummy\foo\foo.psm1:1'

At C:\local\dummy\foo\foo.psm1:1 char:1
+ Import-Module (Join-Path $PSScriptRoot '..\bar')
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
[DBG]: PS C:\>> l

1:* Import-Module (Join-Path $PSScriptRoot '..\bar')
2: function Get-Foo {'foo'; Get-Bar}

[DBG]: PS C:\>> $PSScriptRoot

[DBG]: PS C:\>> Get-Variable PSScriptRoot

Name Value
---- -----
PSScriptRoot

## So the Join-Path subexpression should fail...

[DBG]: PS C:\>> (Join-Path $PSScriptRoot '..\bar')
Join-Path : Cannot bind argument to parameter 'Path' because it is an empty string.
At line:1 char:12
+ (Join-Path $PSScriptRoot '..\bar')
+ ~~~~~~~~~~~~~
+ CategoryInfo : InvalidData: (:) [Join-Path], ParameterBindingValidationException
+ FullyQualifiedErrorId : ParameterArgumentValidationErrorEmptyStringNotAllowed,Microsoft.PowerShell.Commands.Join
PathCommand

## But it doesn't?

[DBG]: PS C:\>> s
VERBOSE: Loading module from path 'C:\local\dummy\bar\bar.psm1'.
VERBOSE: Exporting function 'Get-Bar'.
VERBOSE: Importing function 'Get-Bar'.
VERBOSE: Exporting function 'Get-Bar'.
VERBOSE: Exporting function 'Get-Foo'.
VERBOSE: Importing function 'Get-Bar'.
VERBOSE: Importing function 'Get-Foo'.
PS C:\>

2 votes
Sign in
Check!
(thinking…)
Reset
or sign in with
  • facebook
  • google
    Password icon
    Signed in as (Sign out)

    We’ll send you updates on this idea

    Matt White shared this idea  ·   ·  Flag idea as inappropriate…  ·  Admin →

    Hi Matt,

    A lot of this code has since been rewritten to fix problems like this. I’m followed your steps very particularly on the latest internal build, and I can’t seem to get it to repro.

    I understand you’re using WMF 5 on Windows 7, but if you’ve got a test machine lying around, I highly encourage you to see if the Windows Insider build fixes your problem.

    Either way, this should be fixed in a future version of Windows 10 (and potentially WMF as well).

    Thanks,
    Joey

    2 comments

    Sign in
    Check!
    (thinking…)
    Reset
    or sign in with
    • facebook
    • google
      Password icon
      Signed in as (Sign out)
      Submitting...
      • AdminJoey Aiello [MSFT] (Program Manager, Windows Server) commented  ·   ·  Flag as inappropriate

        We just blogged about the WMF 5.1 update coming some time later this year: https://blogs.msdn.microsoft.com/powershell/2016/04/06/windows-management-framework-5-0-updates-and-wmf-5-1/

        WMF is generally tracked as closely as possible to Current Branch Windows 10, so I'd imagine that this fix would be delivered as part of that. WMF 5.0 will be supported for 4 months after 5.1, but only for critical security issues.

      • Matt White commented  ·   ·  Flag as inappropriate

        Sorry, took a couple days to get a Win10 box on an insider build. I've confirmed that the issue (both my reduced repro and the problem with our actual modules) are *not* reproducible on Win10 14295.

        While that's great to see that it's fixed in a forthcoming build of Win10, it's less clear what that means for older OSes. I understand you may not be able to commit to anything, but any guidance you could provide about whether this will fix will ship (and if so a very rough idea of when) for Win7/2008R2 and 2012R2 would be greatly appreciated. If the answer is that it may not ship at all, or won't ship for 6+ months or something like that, then we'll still have to go patch our modules to somehow avoid this bug.

      Feedback and Knowledge Base