Forum Discussion

dirkabhau's avatar
dirkabhau
Copper Contributor
Aug 07, 2024

Function disappears after Import-Module

I have a problem with Import-Module.

I have a psm1 file which exports function "Write-FromWithinPsmFile". This psm1 is imported into two ps1 files using Import-Module.

Also the main ps1 files calls the other ps1 file.

Now I found two cases, where calling the function "Write-FromWithinPsmFile" works fine and the other way shows some confusing result, which I cannot explain. The function "disappears" after the main script executes the second script. But only in case it executes the second script from within a function.

 

This is the Test.psm1 file:

 

function Write-FromWithinPsmFile($Text)
{
    Write-Host "code in Test.psm1: $Text"
}
Export-ModuleMember -Function Write-FromWithinPsmFile

 

This is the script Start.ps1:

 

param (
    [Parameter()]
    [switch]
    $WillFail
)

Import-Module "C:\tmp\Test.psm1" -Scope Local -Force -ErrorAction Stop

function Invoke-ScriptFromFunction
{
    . "C:\tmp\CalledScript_repro.ps1"
}

Write-FromWithinPsmFile "called from Start.ps1 - first time"

if ($WillFail)
{
    # execute the script from within a function
    Invoke-ScriptFromFunction
}
else
{
    # execute the script directly
    . "C:\tmp\CalledScript_repro.ps1"
}

Write-FromWithinPsmFile "called from Start.ps1 - second time"

 

And this is the CalledScript_repro.ps1, which is called by the main script:

 

Import-Module "C:\tmp\Test.psm1" -Scope Local -ErrorAction Stop -Force

# do something .....

 

This is the successfull execution: powershell -File C:\tmp\Start.ps1 -Verbose

This is the failing one: powershell -File C:\tmp\Start.ps1 -WillFail -Verbose

It tells me:

Write-FromWithinPsmFile : The term 'Write-FromWithinPsmFile' is not recognized as the name of a
cmdlet, function, script file, or operable program.

Both calls will succeed, in case I change the CalledScript_repro.ps1 to this (I removed the -Force):

 

Import-Module "C:\tmp\Test.psm1" -Scope Local -ErrorAction Stop

# do something .....

 

 

Some time ago I added the -Force, because it is more convenient when debugging and writing the code.

So my question is:

What am I doing wrong? Do I need to do the Remove-Module explicitly? How should I use the Import-Module?

  • LainRobertson's avatar
    LainRobertson
    Silver Contributor

    dirkabhau 

     

    Hi, Dirk.

     

    I haven't tested this but my intuition says it's a scoping issue.

     

    When you import the module in your outer script (start.ps1), the module is imported into its own scope and linked to that outer script's session.

     

    When you then launch the inner script (calledsscript_repro.ps1), I expect that the relationship between the outer script and the module is destroyed when the module is being unloaded courtesy of using the "-Force" parameter.

     

    The module then loads into the inner script, with the module's session now linked only to the inner script's session, leaving the outer script unaware of the module and its exported functions.

     

    Because the module is now only linked to the inner script, when that inner script finishes, the module is once again automatically unloaded as it's no longer in scope for the outer script, to which execution control is returned, and any further calls to that module's exported functions ought to fail.

     

    I expect that you can keep the "-Force" in the outer script, but you should not use "-Force" in any inner/nested scripts.

     

    You can read more about scopes here:

     

     

    I'm not actually sure why you're loading the module in the inner script at all given it will inherit access to the module from the outer script - the "Local" parameter won't change that. But certainly you can, just not in conjunction with the "-Force" parameter.

     

    Cheers,

    Lain

    • dirkabhau's avatar
      dirkabhau
      Copper Contributor

      LainRobertson

      Hi Lain,

      Your explanation sounds very reasonable. So it looks like the function is the one which creates a scope, so that it does not work after leaving the function.

       

      The reason why I import the module in both scripts: I can call both of the scripts also standalone.

       

      The reason why I use the Import-Module with -Force is for debugging and development reason. Without -Force I have the following issue:

      • I start powershell or "Visual Studio Code"
      • execute a ps1, which imports a psm1
      • change code in the psm1
      • execute the same ps1 again

      In this case still the unchanged code in psm1 is executed. In case I use the Import-Module with -Force it is reloaded and the changed code is executed.

       

      I just had an idea how to resolve it :smile:. I execute the called script with a new powersehll.exe, like this:

      function Invoke-ScriptFromFunction
      {
          Write-Host "THIS WILL CAUSE THE ISSUE"
          . "C:\tmp\CalledScript_repro.ps1"
      }
      
      function Invoke-PowershellToExecuteScriptFromFunction
      {
          Write-Host "THIS WILL NOT CAUSE ANY ISSUE"
          powershell.exe -File "C:\tmp\CalledScript_repro.ps1"
      }

      The new exe of course resolves the scoping stuff, but needs some more performance.

      But I am still wondering, why there is not easy way to import and remove a module, without impacting calling scripts. Especially when I do not know, if my script will be called by another one after I developed it.

       

      But thanks for the hint.

       

      Cheers,

      Dirk

Resources