I've already read this question and even though it has lots of back and forth, I tried my best to follow the suggestions, but still not sure how to work around this.
I have defined multiple classes in the ScriptsToProcess .ps1 file like this:
The problem is that when I install the module in a clean state VM (where the module never existed before) and try to use the cmdlets, I get an error saying the type is not found, but if I close and reopen PowerShell or use Import-Module with -Force parameter then everything is okay.
I need to know how I can work around this problem without introducing too many repetitive code.
I'm using PowerShell 7.5
I don't fully understand the VM-related problem, but perhaps the following approach bypasses the problem:
Define your
classes as part of your script's root module (*.psm1, referenced via theRootModulemodule-manifest entry) instead of your current approach of using a*.ps1file that is loaded into the caller's scope via theScriptsToProcessmanifest entry.ScriptsToProcessentry (at least not for exporting yourclasses andenums).By itself, this makes your classes only available to callers that import the module with a parse-time
using modulestatement, but note the following:The linked documentation notes (emphasis added):
Only the importer and its descendent scopes see the imported module's
classes (andenums).Because
using moduleis a parse-time statement, the target module path must not contain variables, but modules discoverable via$env:PSModulePathcan be referenced by name only (e.g.using module MyModule); relative paths are resolved against the caller's own file-system location (rather than against the current directory).Once a module is imported with
using modulein a given session, it cannot be forcefully re-imported; that is, if you want to modify yourclassand/orenumdefinitions, you'll need to start a new session to see the changes.However, the Exporting classes with type accelerators section of the about_Classes help topic describes a workaround that makes classes of your choice available session-globally, in all scopes and runspaces, and also works with module auto-loading and
Import-ModuleThe sample code below demonstrates this approach, but comes with the following caveats:
As with the
using module-based approach, you won't be able to reload modifiedclassdefinitions in a given session - start a new session instead.Unlike with the
using module-based approach (which you may still choose to combine with the suggested approach), the (possibly implicit) importer must not rely on theclasses to be available at parse time, i.e. must not try to reference them via type literals inclassdefinition of its own - see this answer for details.classandenumdefinitions in a nested module or a*.ps1file dot-sourced from your root module, this is best avoided if you want your module to also support theusing moduleimporting technique for parse-time availability of the classes.Because the suggested approach (potentially) exposes the
classes to other runspaces too, they should be decorated with the[NoRunspaceAffinity()attribute, which is available in v7.4+ only. That said, the approach is safe to use in earlier versions as long as only a single runspace (the default runspace) is used.The linked help topic also includes event-based code for attempting to remove exported
classdefinitions when the module is unloaded (Remove-Module), however, this does not work (as of PowerShell 7.4.1), and has therefore been omitted in the code below.Note that with either approach above,
classes andenums won't be available until after your module has been imported into a given session. That is, unlike functions and cmdlets in auto-loading modules, they aren't discoverable prior to import.Example
*.psm1root-module content:Any (possibly implicit) importer of the module associated with this
*.psm1will have the[SomeClass]class available to them at runtime.That is,
[SomeClass]::new().Get()in the caller's scope and any scope thereafter should yield42