JosefZ's helpful answer is probably the best approach.
While it is true that .
, the dot-sourcing operator runs everything directly in the caller's scope, including thereby making potentially auxiliary variables appear, there is is no need to use aux. variables in your case (and you can generally hide definitions you don't want the caller to see by running inside a child scope, via & { ... }
)):
function LoadFunction ()
{
# Just define the function directly.
# When the enclosing LoadFunction function is dot-sourced
# ConvertDecToHex is defined in the caller's scope.
function ConvertDecToHex ([int]$value){return "{0:x}" -f $value}
}
# Important: Dot-source (.) the LoadFunction call
. LoadFunction
# Now this should work.
ConvertDecToHex 12
Note:
The to-be-exported function is simply defined directly and normally inside the LoadFunction
body - no need for Invoke-Expression
(iex
), which should generally be avoided
To comply with PowerShell's naming conventions, it's better to name your functions Import-Function
and ConvertTo-Hex
.
If you want to avoid dot-sourcing, you can use Import-Module
:
If you place the functions to import in a separate *.ps1
file, you can use Import-Module
to achieve the same effect - but note that in effect that is nothing more than a - more descriptive - syntax alternative to dot-sourcing such a file - unless you use a stand-alone .psm1
module file; see below.
E.g, place the function definition(s) in a file named functions.ps1
:
function ConvertDecToHex([int]$value) { return "{0:x}" -f $value }
Then call Import-Module
to import them, i.e. to make the function(s) available in the caller's scope:
# Note: The "./" (or ".\") prefix is required in order to import
# from the current dir.
Import-Module ./functions.ps1
Note:
Import-Module
, as the name suggests, is designed to import modules, but it can also be used with regular script files (.ps1
).
Modules, even though they're typically and more robustly implemented as directories with a prescribed structure of related files, can also be implemented as stand-alone files, namely with filename extension .psm1
(note the m
).
Therefore, you could alternatively save your function in file functions.psm1
rather than functions.ps1
, for instance, but note that resulting behavior differs:
Modules create their own scope domain (a.k.a session (sub)state) that parallels the scopes in which non-module code runs; the only ancestral scope they share is the global scope, whereas the definitions from a non-global non-module scope - such as inside a regular .ps1
script - is not seen by functions imported from modules.
- This behavior can have unexpected side effects with respect to preference variables - see GitHub issue #4568.
The upshot is:
If you use Import-Module ./functions.ps1
(regular script file), the imported functions will see the caller's definitions (functions, variables, ...). For instance, thanks to PowerShell's dynamic scoping, a variable $foo
defined in the caller's scope would be visible in the body of your ConvertDecToHex
function.
If you use Import-Module ./functions.psm1
(stand-alone module file), they will not.
Conversely, the caller will not see variables defined in the .psm1
file, unless they're explicit exported with Export-ModuleMember
.
You may prefer this behavior, because it hides auxiliary variables by default, and because Export-ModuleMember
also gives you control over what functions and aliases should be exported, so you can also hide auxiliary functions.