Reputation: 11330
I want to import external function from file, not converting it to a module (we have hundreds of file-per-function, so treat all them as modules is overkill).
Here is code explanation. Please notice that I have some additional logic in Import-Function like adding scripts root folder and to check file existence and throw special error, to avoid this code duplication in each script which requires that kind of import.
C:\Repository\Foo.ps1:
Function Foo {
Write-Host 'Hello world!'
}
C:\InvocationTest.ps1:
# Wrapper func
Function Import-Function ($Name) {
# Checks and exception throwing are omitted
. "C:\Repository\$name.ps1"
# Foo function can be invoked in this scope
}
# Wrapped import
Import-Function -Name 'Foo'
Foo # Exception: The term 'Foo' is not recognized
# Direct import
. "C:\Repository\Foo.ps1"
Foo # 'Hello world!'
Is there any trick, to dot source to global scope?
Upvotes: 14
Views: 6131
Reputation: 35901
Just dot-source the function as well:
. Import-Function -Name 'Foo'
Foo # Hello world!
Upvotes: 5
Reputation: 68293
You can't make the script run in a parent scope, but you can create a function in the global scope by explicitly scoping it.
Would something like this work for you?
# Wrapper func
Function Import-Function ($Path) {
# Checks and exception throwing are omitted
$script = Get-Content $Path
$Script -replace '^function\s+((?!global[:]|local[:]|script[:]|private[:])[\w-]+)', 'function Global:$1'
.([scriptblock]::Create($script))
}
The above regex only targets root functions (functions left justified; no white space to left of the word function
). In order to target all functions, regardless of spacing (including sub-functions), change the $Script -replace
line to:
$Script -replace '^\s*function\s+((?!global[:]|local[:]|script[:]|private[:])[\w-]+)','function Global:$1'
Upvotes: 7
Reputation: 47802
You can change the functions that are defined in the dot-sourced files so that they are defined in the global scope:
function Global:Get-SomeThing {
# ...
}
When you dot source that from within a function, the function defined in the dot sourced file will be global. Not saying this is best idea, just another possibility.
Upvotes: 6
Reputation: 54891
I can't remember a way to run a function in global scope right now. You could do something like this:
$name = "myscript"
$myimportcode= {
# Checks and exception throwing are omitted
. .\$name.ps1
# Foo function can be invoked in this scope
}
Invoke-Expression -Command $myimportcode.ToString()
When you convert the scriptblock to a string .ToString()
, the variable will expand.
Upvotes: 0