Must variable be global for Export-ModuleMember -Variable?

Suppose within *.psm1 module file you declare a variable like this:

$Variable1 = 0
New-Variable -Name Variable2 -Value 1

This are by default script scope variables.

Can I export script scope variable now with:

Export-ModuleMember -Variable Variable1, Variable2

OR

Do I need to declare variables as public like this in order to export them?

$global:Variable1 = 0
New-Variable -Name Variable2 -Value 1 -Scope Global

This is confusing, since if variable are declared global there is no need to export them with Export-ModuleMember right?
But if they are script scope variables then there should be no way to export them, no?

What is the behavior and best practice?

Also I noticed that regardless of what’s declared in *.psd1 manifest file, if you don’t use Export-ModuleMember private scripts will be shown as exported with Import-Module -Verbose however that’s only verbose, in fact they’re not exported, so that’s just to add to unusual behavior and confusion on why I want to explicitly use Export-ModuleMember

As documented in the documentation that only works in modules.

That would be the equivalent option for scripts. If you want to make a variable available outside the scope of a regular script you can declare them ‘GLOBAL:’. This way they are available for scripts or functions running in this console session.

I’d recommand not to mess with variable scopes at all and provide values for scripts or functions explicitly as parameters.

You may elaborate a little more detailed what problem you try to solve. There might be a better way. :wink:

documentation is lacking, otherwise I wouldn’t be asking for help.

Sure:

My module has both the *.psd1 and *.psm1 files.
manifest contains ex:

	FunctionsToExport = @(
		"Confirm-Installation"
		"Format-Path"
		"Get-AppCapability"
                #....
       )

module file contains:

$PublicScripts = @(
	"Confirm-Installation"
	"Format-Path"
	"Get-AllUserProgram"
          # ...
)

foreach ($Script in $PublicScripts)
{
       # dot sourcing scriptts into *.psm
       . "$PSScriptRoot\Public\$Script.ps1"
}

Documentation for manifest files states that those functions declared in manifest are exported and psm1 is ignored for additional exports if any.

However when I run Import-Module MODULE_NAME -Verbose I see also private scripts being exported even thogh I didn’t specify them in manifest, but they are not available in session.

My problem is that this create unecessary verbose messages about exporting something that is in fact not exported.

For this reason I want to explicitly use Export-ModuleMember -Function (in addition to manifest specification) which verboses out only those functions mentioned (+ those in manifest) resulting is less verbose spam to console.

When you run -Verbose you can see that each, psm and psd are being processed which results in duplicate verbose output about exports.

Do you think it’s good (and normal) to specify which functions to export in both *.psd1 and *.psm?

What happens anyway is that verbose import shows both files showing importing functions resulting in duplicate verbose “Exporting function xyz”

I really hate this because:

  1. redundant verbose messages makes it harder to debug code
  2. it feels like performance issue when same function is exported twice.

I have 100+ functions to import and want to make things as efficient as possible.

What would be the best practice in that case?

I only export the needed functions via the module manifest *.psd1. My module script files *.psm1 usually only has one line:

Get-ChildItem $psscriptroot\*.ps1 | ForEach-Object { . $_.FullName }

And I save my functions and helper functions in individual *.ps1 files.

But I do not have 100+ functions per module. Most of my modules only have up to 25 external functions - mostly significantly less. :man_shrugging:t4:

1 Like

If you use Get-ChildItem ... (I assume for all scripts) in psm in addition to specification in manifest please run your module with -Verbose switch and you’ll see functions are imported twice, at least so will verbose output say.

I also used to do simply Get-ChildItem $psscriptroot\*.ps1 | ForEach-Object { . $_.FullName } but I learned that is a potential security issue because you might lose control over what’s being imported, suppose you have a malicious program on your computer which puts a script into your module, what will happen is that this script will execute without you knowing it.

ofc. neither do I, I have some 10 modules with up to 15-25 functions but I import them all as part of development process, when I enable verbose output this spams my console with some 400 verbose outputs only about modules, not including verbose about stuff that I actually want to see.
This is why I want a better solution, I believe my design is lacking something, sadly documentation says nothing about my issue.

That does not happen in my environment - no. :man_shrugging:t4: I only see one verbose message per function/alias. But as I wrote already I do not use both ways of exporting functions and aliasses. And I do not export variables at all.

That’s a risk I live with. :wink:

So you may change your process?! Do you really need to import all of these modules at once every time? And do you really have to import them -Verbose? In my opinion that parameter only serves a purpose when you have problems importing some of the functions/scripts from your module.

1 Like

Interesting insight, I’ll definitely investigate why it’s happening in my case and will report back.

EDIT:
btw. how do you import your module with -Verbose? do you specify file name (psm or psd) or just module name?

I let it import automatically by PowerShell when needed. If I have to import it explicitly I just use the name of the module.

I found what’s the issue!

First of all I must admit that I wear glasses and I have poor eyesight :slightly_smiling_face:

What I declared as duplicate verbose output is acctualy this:

Import-Module .\Test\Experiment\Experiment.Module -Verbose -Force

VERBOSE: Exporting function 'Debug-Experiment'.
VERBOSE: Importing function 'Debug-Experiment'

It says Exporting and Importing but I didn’t notice that, I’ve read it as exporting twice.

Now I found a solution to reduce that output to just single line, in the above test module my *.psm does not make use of Export-ModuleMember -Function but if you explicitly add Export-ModuleMember -Function into *.psm in addition to FunctionsToExport = @() in manifest file then the output is this:

Import-Module .\Test\Experiment\Experiment.Module -Verbose -Force

VERBOSE: Importing function 'Debug-Experiment'

It no longer says “Exporting”, just importing and that’s awesome and exactly what I want.

However there is something I don’t understand now, what is the difference between:
Importing function and Exporting-Function?

I suppose that “Exporting” means to export function into global scope, but what is meant by “Importing” then, where is the function imported exactly?
Do you know what’s the difference and where is function exported or imported in both cases?

I’d expect those two methods to have the same result - the desired functions, aliasses and/or variables are available in the global scope.

I’d expect to just say “Exporting function” and end of story as that’s all that’s needed, I doubt “Importing” is the same thing.

Thank you for your insights.

This might be a matter of point of view … you export the function from the module and you import the functions into the session. The result is in both cases the same. :wink: :man_shrugging:t4: