Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Dot-sourcing a script without executing it

Tags:

powershell

Is it possible in Powershell to dot-source or re-use somehow script functions without it being executed? I'm trying to reuse the functions of a script, without executing the script itself. I could factor out the functions into a functions only file but I'm trying to avoid doing that.


Example dot-sourced file:

function doA
{
    Write-Host "DoAMethod"
}

Write-Host "reuseme.ps1 main."

Example consuming file:

. ".\reuseme.ps1"

Write-Host "consume.ps1 main."
doA

Execution results:

reuseme.ps1 main.
consume.ps1 main.
DoAMethod

Desired result:

consume.ps1 main.
DoAMethod
like image 232
Frederik Avatar asked Dec 05 '22 09:12

Frederik


2 Answers

You have to execute the function definitions to make them available. There is no way around it.

You could try throwing the PowerShell parser at the file and only executing function definitions and nothing else, but I guess the far easier approach would be to structure your reusable portions as modules or simply as scripts that don't do anything besides declaring functions.

For the record, a rough test script that would do exactly that:

$file = 'foo.ps1'

$tokens = @()
$errors = @()
$result = [System.Management.Automation.Language.Parser]::ParseFile($file, [ref]$tokens, [ref]$errors)

$tokens | %{$s=''; $braces = 0}{
    if ($_.TokenFlags -eq 'Keyword' -and $_.Kind -eq 'Function') {
        $inFunction = $true
    }
    if ($inFunction) { $s += $_.Text + ' ' }
    if ($_.TokenFlags -eq 'ParseModeInvariant' -and $_.Kind -eq 'LCurly') {
        $braces++
    }
    if ($_.TokenFlags -eq 'ParseModeInvariant' -and $_.Kind -eq 'RCurly') {
        $braces--
        if ($braces -eq 0) {
            $inFunction = $false;
        }
    }
    if (!$inFunction -and $s -ne '') {
        $s
        $s = ''
    }
} | iex

You will have problems if functions declared in the script reference script parameters (as the parameter block of the script isn't included). And there are probably a whole host of other problems that can occur that I cannot think of right now. My best advice is still to distinguish between reusable library scripts and scripts intended to be invoked.

like image 84
Joey Avatar answered May 19 '23 12:05

Joey


After your function, the line Write-Host "reuseme.ps1 main." is known as "procedure code" (i.e., it is not within the function). You can tell the script not to run this procedure code by wrapping it in an IF statement that evaluates $MyInvocation.InvocationName -ne "."

$MyInvocation.InvocationName looks at how the script was invoked and if you used the dot (.) to dot-source the script, it will ignore the procedure code. If you run/invoke the script without the dot (.) then it will execute the procedure code. Example below:

function doA
{
    Write-Host "DoAMethod"
}

If ($MyInvocation.InvocationName -ne ".")
{
    Write-Host "reuseme.ps1 main."
}

Thus, when you run the script normally, you will see the output. When you dot-source the script, you will NOT see the output; however, the function (but not the procedure code) will be added to the current scope.

like image 28
SultanShell Avatar answered May 19 '23 12:05

SultanShell