3

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
spottedmahn
  • 14,823
  • 13
  • 108
  • 178

1 Answers1

3

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.

mklement0
  • 382,024
  • 64
  • 607
  • 775
  • "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 Aug 03 '22 at 16:32
  • 1
    @spottedmahn: If you [dot-source](https://learn.microsoft.com/en-us/powershell/module/microsoft.powershell.core/about/about_Operators#dot-sourcing-operator-) (load with `. `) a `.ps1` file (regular script file), you'll (indiscriminately) see all its definitions, including variables. – mklement0 Aug 03 '22 at 16:34