Remoting. Windows Remoting. Powershell. And variables. With functions….
When you use powershell to connect to remote machines, you have to worry about where and how variables gets defined.
$s = New-PSSession -Computer localhost
Invoke-Command -Session $s -ArgList 1 -ScriptBlock { param($number) $number }
Yep. That’s what it takes to define a local variable in a script block
Today, I found that the powershell session has it’s own scope that lasts as long as the powershell scope.
Invoke-Command -Session $s -ArgList "my_value" "value" -ScriptBlock {
param($name, $value)
Set-Item Variable:$name = $value
}
Invoke-Command -Session $s -ScriptBlock { $my_value }
This will set a variable on a session in one remote invocation, and retrieve it on another. Crazy! Or rather, just like an SSH session.
So I now want to make use of this to push local variables from my script over to a remote machine. Something like:
$wibble = "hi"
OnRemote -server "localhost" -locals "wibble" -action {
Write-Host "Hi I'm on remote machine with $wibble == hi"
}
What the devil should OnRemote look like? Here’s the signature…
function OnRemote() {
param($server, $locals=@(), [scriptblock]$action)
}
…and the body…
$s = New-PSSession -Computer $server
@($locals) | % { Invoke-Command -Session $s -ArgList $_ Variable:$_ -ScriptBlock {
param($name, $value)
New-Item -name Variable:$name -value $value
}
Invoke-Command -Session $s -ScriptBlock $action
End-Session $s
At the moment I’ve haven’t gone any further with this, and I’m sure there’s a way of binding variables into the remote context more consisely. As it is, you have to remember to keep your locals declaration in sync with the values being pushed.
If I were to go to the next step, I’d probably try to remove that need to keep local names in sync. I guess it would look something like this:
function MyFunction(){
$remote:wibble = 5 # or [remote]$wibble=5
OnRemote {
Write-Host "The value $wibble comes from the host"
}