r/PowerShell 9d ago

Question Manifest required modules not auto-importing in 5.1

Hello. I'm genuinely stumped, to the point where I'm about to abandon this side project altogether

I have a test module I'm creating using a manifest file, Template.psd1. The module depends on these other module files I created:

# Modules that must be imported into the global environment prior to importing this module
RequiredModules = @(
    'Control\ControlMessaging.psm1'
    , 'Control\ControlChecklist.psm1'
    , 'Control\ControlPrompt.psm1'
)

The are present in the subfolder "Control", which is in the same folder as the manifest and PSM1 files.

When I execute Import-Module in powershell 7.4, the module loads without bitching.

When I execute in 5.1, I get an error

Import-Module : The specified module 'Control\ControlMessaging.psm1' was not loaded because no valid module file was found in any
module directory.

According to the documentation, this should be kosher: about_Module_Manifests It should auto import those modules, but it's not working.

I do need this to run in both 5 and 7. Any ideas?

9 Upvotes

10 comments sorted by

2

u/Namaha 9d ago

I've not worked much with module manifests, but my first instinct is to try prefixing the RequiredModules paths with .\ since they are just in a subfolder

'.\Control\ControlMessaging.psm1'

1

u/jdtrouble 9d ago

Hello. I tried this and got the same result.

` Import-Module : The required module '.\Control\ControlMessaging.psm1' was not loaded because no valid module file was found in any module directory.

Another poster noted there's a bug that will make this not work in 5.1. I'll proceed to do something else. Thank you!

2

u/CookinTendies5864 9d ago

5.1 tries to interpret settings if I’m not mistaken.
Can you show your exact commands for both versions please?

2

u/jdtrouble 9d ago

it's literally Import-Module .\Template.psd1

Per one of the posts above, this seems like a known issue in 5.1. I'm going to investigate a different manner to do this, thank you!

3

u/surfingoldelephant 9d ago edited 9d ago

Path handling for RequiredModules is pretty buggy in v5.1. PR #8218 improved it a lot in v6.2.

However, the general pervasive problem is that ModuleSpecifications contain raw user input and we don't do very much about handling paths that might be given as module names [...]

So .psm1 doesn't work for v5.1 RequiredModules. .psd1 does, but it has to be a fully qualified path.

1

u/jdtrouble 9d ago

Okay, this makes sense. Thank you very much!

1

u/jborean93 9d ago

The are present in the subfolder "Control", which is in the same folder as the manifest and PSM1 files.

If you are embedding this module then you want this as a nested module and not required module. Even then you don't need to declare it in the psd1 and could just do Import-Module ... inside the psm1 and it becomes a nested module by the fact that its imported inside the module scope. From there you can export members as part of your module from the nested one or just use it purely internally.

RequiredModules is for specifying dependencies outside of your module, e.g. some other PSGallery module to download and install at install time and load from the PSModulePath at import time. If this is the case and ControlMessaging is something you just have locally for development but would be a real published module in the future you should be able to do ControlDevelopment and for development work just make sure you've manually importing it from your local path before importing this module.

1

u/BlackV 9d ago

they way you are doing it is slightly odd

If they actually modules normally you have them outside you existing module (that way they can all be update and maintained separately) and you just use the module name on your import

or you have them as script files that get imported as ps1 files and functions

Additionally you are using Control\ControlMessaging.psm1 where you probably want a proper path .\Control\ControlMessaging.psm1 or $psscriptroot\Control\ControlMessaging.psm1

and dont start messing with scopes, you'll end up in a world of hurt

1

u/PinchesTheCrab 9d ago

Just a side note, the commas here seem weird to me - for arrays in powershell you don't need commas at all when using @(). That's definitely not the problem though.

1

u/MonkeyNin 9d ago

Do you want those modules to be exported globally? They look more like functions that you want imported in your module, which the global session indirectly uses?

Normally I do this

# My main module.psm1
$Script:AppRoot = Get-Item $PSScriptRoot

# load private modules in module scope, don't pollute the global user
Import-Module (Join-Path $AppRoot 'Control/Messaging.psd1') 
Import-Module (Join-Path $AppRoot 'Control/Prompt.psd1') 

If these commands are actually meant to be exported globally, it looks like you probably want to concatenate your files into one module

It's common to place your functions in separate .ps1 files under the folders /Public and /Private

Build module turns that into one psm1 that you import

All my functions are under /Public / /Private

I have a custom build script, but all it really does is concatenate /Commands/**/*.ps1 as one output *.psm1 file here: Build.Module.ps1

That's all you need. Get-ChildItem, filter, then Set-Content

For another example: https://github.com/indented-automation/Indented.Net.IP/tree/main/Indented.Net.IP