I've been writing a Cmdlet, and, to keep my interfaces clean, I've been manually exporting the functions I care about with Export-ModuleMember
.
However, someone pointed out that I could also put my functions directly in the global:
scope instead, without calling Export-ModuleMember
.
Which one is preferable?
# Option A: Export-ModuleMember
function Do-Something {}
Export-ModuleMember -Function Do-Something
# Option B: global scope
function global:Do-AnotherThing {}
# Something else?
Thanks!
My hunch is that Export-ModuleMember
is better since it lets the caller decide which scope the function ends up in (e.g. another cmdlet could import my cmdlet without exposing those exported functions globally), but I'm not sure.
CodePudding user response:
You are spot on. Improperly exporting functions circumvents generally expected behavior when installing modules.
For example, Import-Module
protects against clobbering if a cmdlet stomps on a cmdlet already available to the current session, for example. Declaring a function with the global scope circumvents this, and there is rarely a time when this should be done unless the purpose of the module is to actually override something (like perhaps it sets or modifies the prompt in some way). Doing this as a matter of expectation should be crystal clear to who is installing the module via way of module documentation.
Note: Clobbering is the same basic principle of overloading or overriding members in class inheritance. Creating a new entity with the same name that may (overload) or may not (override) have a different signature.
And even though Import-Module
errors on clobbering by default, Import-Module -AllowClobber
is the solution if you need the cmdlet which would have clobbers the existing one, and lets the user choose whether or not to allow clobbering.
But I also don't recommend Export-ModuleMember either. Rather, you should prepare your module with a manifest (ModuleName.psd1
) instead, and specify the exported functions and cmdlets there. There are also many other things you can set in the manifest as well.
It has the benefit of making the module definition easier to understand operationally. And now you don't have to litter your code with a bunch of Export-ModuleMember
commands.
Note: If you don't specify the functions or cmdlets to export in your module manifest, or don't have one and do not make use of
Export-ModuleMember
, all functions and cmdlets will be exported. This may be desirable or it may not be for a given module, but it's important to understand.
Additional Info on Writing Modules
As requested in the comments, here are some additional links around designing and writing PowerShell modules:
- Writing a Windows PowerShell Module
- Despite this being in the Legacy SDK section, the information in this section is still useful for learning how to create modules. Avoid creating snap-ins though.
- PowerShell Module Authoring Considerations and PowerShell Scripting Performance Considerations
- The Scripting and Development section both pages are under contains a lot of good information about modules at the top level. If you are serious about module development, I suggest you give this section a good read.