5

I've defined a variable in a psm1 file but when I try to access it in another script, after importing the module, I'm not seeing the value set in the psm1 file.

globals.psm1

$blah = "hello world"

my-script.ps1

Import-Module "$PSScriptRoot\globals.psm1" -Force -Verbose
Write-Output "blah: ${blah}"

output

PS C:\blah> .\my-script.ps1
VERBOSE: Loading module from path 'C:\blah\globals.psm1'.
blah: ''

I thought all variables get exported by default. I must be interrupting this wrong:

Specifies the variables that the module exports to the caller's session state. Wildcard characters are permitted. By default, all variables ('*') are exported

source: MSFT Docs -> How to write a PowerShell module manifest
(CTRL + F on 'VariablesToExport' to find the quoted text)


And yes, if I export the variable, I can access it but the documentation says: 'By default, all varialbes ('*') are exported so what am I doing wrong or misunderstanding? 🤔

globals.psm1

$blah = "hello world"
Export-ModuleMember -Variable blah
0

1 Answer 1

5

Your module is not using a module manifest (a companion .psd1 file whose RootModule entry points to your .psm1 file in the case of script modules), whereas the documentation you quote pertains to module manifest-based modules.

If a module consists only of a .psm1 file, and that file contains no Export-ModuleMember calls, the following rule applies:

  • Only functions and aliases are automatically exported.

  • Conversely, this means: in order to also export variables, you must use an Export-ModuleMember call - and if you do, the slate is wiped clean, so to speak, and you must explicitly specify all definitions you want to export (in the simplest case, use Export-ModuleMember -Function * -Alias * -Variable *).
    Also, be sure to place this call at the end of your .psm1 file, to ensure that all definitions to export have already been defined.

Caveat, if a manifest (.psd1) is used:

  • The manifest's *ToExport keys apply on top of what the .psm1 file - implicitly or explicitly - exports, i.e. you can use it to further narrow what is to be exported, by explicitly enumerating the elements to export, which not only makes the module more self-describing, but also helps performance when PowerShell auto-discovers the commands in available, but not-(yet)-imported modules.

  • Therefore, if a manifest-based module wants to export variables, it too must have an explicit Export-ModuleMember call in its .psm1 file, with the manifest potentially narrowing down what variables are ultimately to be exported.

Generally, exporting variables from modules is best avoided, because:

  • it increases the risk of name collisions with variables of the same name defined elsewhere.

  • discovering which variables are exported by what module isn't as well-known as use of Get-Command is in order to determine what module a given function, cmdlet, or alias comes from. This is because (a) modules that export variables are rare and users generally don't expect it, and (b) the Get-Variable cmdlet - which can tell you what module a variable is defined in - isn't often used in practice.


To see which definitions a given module exports, pass -Verbose to the Import-Module call that imports it. Additionally, pass -Force in order to force re-loading of an already imported module.

Sign up to request clarification or add additional context in comments.

2 Comments

"exporting variables from modules is best avoided", sure, I can see that 👍 but what's the "right" way to share some variables amongst some scripts 🤔? that's a rhetorical question as it's really a separate SO Q/A.
@spottedmahn: If you dot-source (load with . ) a .ps1 file (regular script file), you'll (indiscriminately) see all its definitions, including variables.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.