There are several pieces to this, so I'll explain them separately and then bring them together.
Implicit Remoting
Exchange is using Implicit Remoting.
The way it works is that you establish a PSSession to a remote machine, then import some of the commands available from the remote instance into your own.
This is done using Import-Module -Session $session
or Import-PSSession
.
You can try this for yourself purely in Powershell. Use a workstation that does not have the Active Directory RSAT installed (doesn't have the ActiveDirectory powershell cmdlets), then connect to a machine that does (let's call it DC1
):
$s = New-PSSession -ComputerName DC1
Invoke-Command -Session $s -ScriptBlock { Import-Module ActiveDirectory }
Import-PSSession -Session $s -Module ActiveDirectory
Restricting the call to Import-PSSession
to just the one module lets you import just those cmdlets. At this point you would be able to execute Get-ADComputer
for example, as though it were available locally, even though the actual call is being done on DC1
.
Session Configurations
When you make a powershell remoting connection, you are connecting to a session configuration. If you don't specify one, you connect to one called Microsoft.PowerShell
. To see all of the configurations that are defined on a machine, call Get-PSSessionConfiguration
. You might see some others, for example Microsoft.PowerShell32
is a way to connect to a 32 bit powershell session.
To connect to a specific configuration, use New-PSSession -ConfigurationName
or New-PSSession -ConnectionUri
.
Defining Session Configurations
You can specify a lot of stuff in a session configuration; the version of powershell, the bitness, which modules are pre-imported, you can pre-define functions and code, you can prevent language features from being available, etc.
This answer provides a good overview of how to create your own configuration.
You can also put configuration information inside of an assembly, which would work well for what you're trying to do.
Wrapping Code in Modules
As you've seen with Import-PSSession
it's easier to import just the code you want if it exists in a module. Therefore you should make sure that your cmdlet is exposed through a module.
You said in a comment that you wanted to write your cmdlet in C#. This is not something I've done, but this article appears to provide detailed instructions on how to create a PowerShell Module in C#.
This is now something I have done (and that article is good). Writing a cmdlet in C# is, implicitly, already a module. In fact, you can use Import-Module
to load a compiled .NET assembly, whether it contains any PowerShell cmdlets or not.
For example if you created a public class and compiled it into a DLL, you can do Import-Module MyAssembly.dll
and that class is now available in your PowerShell session.
Defining the cmdlet in C# means including a reference to System.management.Automation
and then creating a class that inherits from Cmdlet
or PSCmdlet
.
Defining the module manifest is recommended but technically optional, just as it is with a script module.
I have not however included the session configuration information in an assembly (yet?), nor have I seen a reference for how to do that.
Bringing it Together
The steps should roughly resemble this:
- Compile module and make it available on the remote end, so that it can be imported to powershell from a local session on that machine.
- Create a new PSSession configuration file, and specify either
-AssembliesToLoad
or -ModulesToImport
(or both if necessary), or specify the configuration information in the assembly itself (probably preferred here).
- Register the configuration on the machine.
- On the client side, you wanted to make it available to PowerShell, so you would simply create the session, then import it:
$s = New-PSSession -ComputerName RemoteMachine -ConfigurationName MyConfig
# The configuration was defined in such a way
# that your module will already be imported in the remote session.
Import-PSSession -Module MyModule
Simplifying it?
You don't have to create a custom configuration on the remote side. As long as your module is available to any powershell session on the remote machine, you can skip the session configuration steps, and then you would just do:
$s = New-PSSession -ComputerName RemoteMachine
Invoke-Command -Session $s -ScriptBlock { Import-Module MyModule }
Import-PSSession -Session $s -Module MyModule
But you may want the additional customization and control you have by using a session configuration, so that's up to you. That's how exchange does it, but it may be overkill for your purposes.