Module importing within remote session

by Ritmo2k at 2012-12-31 09:02:54

I have a situation where I need to stay within ps version 2 and cannot copy my module files over. I need to import, or make available somehow all my custom functions.

My framework originally built up very large script blocks and shipped them over with the Invoke-Command cmdlet but this has gotten unruly to maintain and I want to break everything out in modules.

Anyone have any ideas how I can accomplish this?

by DonJ at 2012-12-31 09:19:26
So the goal is to sit on ComputerA, have ComputerB run commands, and those commands involve functions/modules present on ComputerC. You have a few options.

A) Copy the module to ComputerB. You’ve said this isn’t an option.

B) Leave the module on ComputerC. Put it in a shared folder. Add that shared folder to the global PSModulePath environment variable on ComputerB. ComputerB (subject to its execution policy) can now load the module into memory from the shared folder. You may run into an authentication problem with the hop from ComputerB to ComputerC. You might be able to alleviate that if the permissions on the shared folder don’t require any kind of authentication (e.g., allow read permissions for anonymous), otherwise you’ll get into CredSSP or Kerberos tinkering.

C) Remote into ComputerB, and have it implicitly remote the module from ComputerC using Import-PSSession. This will involve a double-hop in Remoting, which means you’ll need to enable CredSSP or tinker with Kerberos to get authentication working. In this scenario, the module physically runs on ComputerC and the results return to ComputerB. This doesn’t sound like what you want.

D) Keep doing more or less what you’re doing. Read the contents of the module on ComputerA, and ship those functions to ComputerB via Invoke-Command. You can do this with functions as easily as unnamed script blocks.
by Ritmo2k at 2012-12-31 09:29:19
Hi Don,

The scenario is a tech workstation (ComputerA) remoting into several different servers and each running the commands, the Invoke cmdlet is looped over a list.

The infrastructure is large and I only have the original scope available to me which was defined as ports setup such that the tech wkst can remote into all the different servers. If I migrate the main script into modules, how does one construct the scriptblock to include a copy of the functions? That would certainly work well and remain within the initial constraints I have to work in.

Again, thanks a lot!
by DonJ at 2012-12-31 10:09:17
You have a few options.

Import the module locally on ComputerA. Then use Get-Content to retrieve the functions’ content from the FUNCTION drive. That gives you a copy of the function in a variable (you’d have to re-wrap them in a function declaration, I expect), which could be prepended to your scriptblock. It’s a little ghetto, but it’ll work.

Me… I’d cheat. Use Get-Content to read the module contents locally. Use Invoke-Command to send that, as a string and not as a script block, to the remote server. Have the remote server dump that to a file, which can then be loaded in the server’s scope using Import-Module. So technically you’re copying the file… but you’re doing so through the channel you have. You could delete the file afterwards if you wanted to clean-up.

# assumes you used New-PSSession to get a session running on the remote computers, and that
# the sessions are in $sessions
$module = Get-Content C:\Path\to\module.psm1
Invoke-Command -Session $sessions -ArgumentList $module -ScriptBlock { param($x) $x | Out-File C:\Path\To\Module.psm1 }
Invoke-Command -Session $sessions -ScriptBlock { Import-Module C:\Path\To\Module.psm1 }
Invoke-Command -Session $sessions -ScriptBlock { Run-CommandFromThatModule }
Invoke-Command -Session $sessions -ScriptBlock { Remove-Module Whatever ; Del C:\Path\To\Module.psm1 }

Something like that. Still ghetto, but a bit easier conceptually.
by Ritmo2k at 2012-12-31 14:28:37
Both neat ideas, I like the first idea as a result of me not having to worry about cleaning up after myself.

I have yet to figured out how to wrap the function contents back into a function though, as getting the scriptblock of the function and assigning it to a string var to send is simple.