Kae Travis

Call a PowerShell Function in Another PowerShell Script

This blog post provides an example of how we can call a PowerShell function in another PowerShell script.

Let’s first assume that we have a function in a script called AlkaneFunctions.ps1 that enables us to install an MSI using PowerShell like so:

function Install-7Zip {
    try {
        $MSIInstallArguments = @(
        "/i"
        '"C:\Alkane\7z2301-x64.msi"'
        "/qb!"
        "/norestart"
        "/l*v"
        '"C:\Alkane\7Zip.log"'
        )
    
        $ret = Start-Process "msiexec.exe" -ArgumentList $MSIInstallArguments -Wait -NoNewWindow -PassThru
        
        return $ret.ExitCode
    } catch {
        return 1
    }
}  

Of course, in the real world we might want this function to take arguments for the MSI path and log file name so we can install MSI files using PowerShell dynamically.

To call this function from another PowerShell script we need to use a technique called “dot sourcing”.

Dot Sourcing with PowerShell

Dot sourcing in PowerShell is a mechanism that allows us to run an external script within the current scope rather than in a separate scope. When we dot source a script, we essentially merge the script’s content with the current scope, enabling us to access its variables, functions, and other elements directly.

To dot source a script we simply place a dot and a space before the script’s path.  In this case, we can call our function Install-7Zip in the external script c:\Alkane\AlkaneFunctions.ps1 like so:

. 'c:\Alkane\AlkaneFunctions.ps1'
$ret = Install-7Zip
write-host "Return code is $ret" 

Scopes with Dot Sourcing and PowerShell

Depending upon the functionality we require, dot sourcing into the current script’s scope might cause issues.

Let’s assume we have a global variable in the ‘external’ script called ‘installerName’ like so:

$installerName = "7Zip Dot Sourced"

function Install-7Zip {
    try {
        $MSIInstallArguments = @(
        "/i"
        '"C:\Alkane\7z2301-x64.msi"'
        "/qb!"
        "/norestart"
        "/l*v"
        '"C:\Alkane\7Zip.log"'
        )
    
        $ret = Start-Process "msiexec.exe" -ArgumentList $MSIInstallArguments -Wait -NoNewWindow -PassThru
        
        return $ret.ExitCode
    } catch {
        return 1
    }
}  

And let’s also assume that we have a variable with the same name in our host script.

You will see that when we dot source the external script, the value of installerName in the dot sourced script will overwrite the value of installerName in our host script.

$installerName = "7Zip Host"

. 'c:\Alkane\AlkaneFunctions.ps1'
$ret = Install-7Zip
write-host "Return code is $ret for $installerName" 

The output is “Return code is 0 for 7Zip Dot Sourced”.

This might not be the desired functionality.  We might instead just want to isolate the execution of our dot sourced script in a separate scope, and just return the exit code!

We can do this using Invoke-Command, which by default runs a script block in a separate scope:

$installerName = "7Zip Host"
$ret = Invoke-Command -ScriptBlock { . 'c:\Alkane\AlkaneFunctions.ps1'; return Install-7Zip; } -ErrorAction Stop
write-host "Return code is $ret for $installerName" 

The output is “Return code is 0 for 7Zip Host”.

 

 

 

 

Call a PowerShell Function in Another PowerShell Script
Call a PowerShell Function in Another PowerShell Script

Leave a Reply