Артур Гудиев
Артур Гудиев

Reputation: 1144

Reload the PowerShell module every time the script is executing

I have a class in the PowerShell module file. (A.psm1)

class A  {

    [void] printString() {
        write-host 111
    }

}

And I also have a simple script that uses that class.

Using module C:\temp\A.psm1

$a = [A]::new()
$a.printString()  # prints 111

But if I change the method from the class, for example, as shown here (replace 111 on 222)

[void] printString() {
     write-host 222
}

and if I relaunch my script it will still print 111. Only if I restart the PowerShell console it will print the new value. If I worked only in the console, I could use the Import-Module ... -Force command. But it doesn't work in the script.

So is there a way to reload the PowerShell module every time the script is launched without restarting the console itself?

Upvotes: 5

Views: 2867

Answers (2)

mklement0
mklement0

Reputation: 438208

As far as I know, there's no good solution, unfortunately (as of PowerShell 7.2): The using module statement - which is the prerequisite for also loading classes from a module - has no equivalent to the Import-Module's -Force switch for forcing reloading of a module.

Workaround:

# (Force-re)load the module and get a reference to the module.
# This does NOT give you access to the classes defined in the module.
$module = Import-Module C:\temp\A.psm1 -PassThru -Force

# Use the module reference to execute code *in the module's* context,
# where the class *is* defined, so you can obtain a reference to the
# [A] class (type) this way:
$classA = & $module { [A] }

$classA::new().printString()
  • As you can see, this requires modifying the source code.

  • If you're using Visual Studio Code with the PowerShell extension, you can avoid this, as shown in Mathias R. Jessen's helpful answer.

Upvotes: 4

Mathias R. Jessen
Mathias R. Jessen

Reputation: 174545

This unfortunate behavior is a well-known issue, and as mklement0 points out no real good solution exist at the moment.

The underlying cause is a bit convoluted (part of the reason the behavior persists after 5+ years), but it's basically a 3-way conflict between:

  • Module lifecycle management in PowerShell (modules are supposed to be reloadable)
  • Type definition lifecycle management in .NET (a type can never be "un-defined" for the lifetime of the process*)
  • The way using module provides parse-time resolution of custom types - its not a particularly mature feature to put it plainly

Although no good solution exists, the VSCode PowerShell extension has a configuration option allowing you to run debug sessions in a temporary shell, making it a non-issue:

enter image description here

{
  "powershell.debugging.createTemporaryIntegratedConsole": true
}

Once set, you can use the following workflow for testing/debugging:

  1. Open the script in the editor
  2. Run it via the debugger (Shift+Ctrl+D -> Run and Debug)
  3. Observe printString() prints 111
  4. Make changes to the module file, save it
  5. Run the script via the debugger again
  6. Observe printString() now prints the new value

Upvotes: 7

Related Questions