How do I host a Powershell script or app so it's accessible via WSManConnectionInfo? (like Office 365) How do I host a Powershell script or app so it's accessible via WSManConnectionInfo? (like Office 365) powershell powershell

How do I host a Powershell script or app so it's accessible via WSManConnectionInfo? (like Office 365)


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 DC1Invoke-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:

  1. 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.
  2. 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).
  3. Register the configuration on the machine.
  4. 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 RemoteMachineInvoke-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.