Powershell – How to use shared functions in a remote Powershell session

powershellremote-accessremoting

I have some Powershell scripts for setting up IIS web applications, message queues, etc.

They use a set of shared function libraries we've created – so each script starts with the line

. .\common.ps1

to reference the shared library. The shared library contains a set of functions like Create-IisApplicationPool, Create-MessageQueue and the like, which are then called from the actual script. The problem with these scripts is that you need to log on via Remote Desktop and run them locally, so I'm writing some new scripts for deploying code to an Amazon EC2 instance, and using Powershell remoting to invoke them locally.

What I can't work out is how to make this shared library available in a remote Powershell session.

Here's a simple example:

functions.ps1

function Add-Title([string] $name) {
    "Mr. $name"
}

function Say-HelloWorld([string] $name = "World") {
    $computerName = $env:COMPUTERNAME
    $greeting = Add-Title($name)
    Write-Host "Hello, $greeting ($computerName)"
}

example.ps1

. ./functions.ps1


$remoteUsername = "username"
$remotePassword = "password"
$remoteHostname = "172.16.0.100"

$securePassword = ConvertTo-SecureString -AsPlainText -Force $remotePassword
$cred = New-Object System.Management.Automation.PSCredential $remoteUsername, $securePassword


Say-HelloWorld("Spolsky")

Running locally, this works great – and says "Hello, Mr. Spolsky (DYLAN_PC)" as expected.

Now, if I replace the Say-HelloWorld call with this remote script invocation:

Invoke-Command -computerName $remoteHostname -Credential $cred -ScriptBlock {
    Say-HelloWorld("Spolsky")
}

I get the Powershell error:

The term 'Say-HelloWorld' is not recognized as the name of a cmdlet, function, script file, or operable program. Check the spelling of the name, or if a path was included, verify that the path is co
rrect and try again.
    + CategoryInfo          : ObjectNotFound: (Say-HelloWorld:String) [], CommandNotFoundException
    + FullyQualifiedErrorId : CommandNotFoundException

Clearly, the remote session can't see the functions that have been imported locally.

For simple functions, this syntax works:

Invoke-Command -computerName $remoteHostname -Credential $cred -ScriptBlock ${function:Add-Title } -argumentlist "Spolsky"

but this fails for any function which depends on other functions.

I've tried various things using PS-ExportSession and trying to pass a -Session argument to Invoke-Command, but can't find any way of capturing local functions and their dependencies in a module that can be imported into a remote session. Any help gratefully received!

Best Answer

This is a bit of an old topic, but all of the answers are more round-about than this.

Import-Module .\Common.ps1 -Force
# Now you can call common functions locally

$commonFunctions = (Get-Command .\Common.ps1).ScriptContents
Invoke-Command -Session $session -ArgumentList $commonFunctions -ScriptBlock {
    param($commonFunctions)
    Invoke-Expression $commonFunctions

    # Now you can call common functions on the remote computer
}
Related Topic