Take the 2-minute tour ×
Super User is a question and answer site for computer enthusiasts and power users. It's 100% free, no registration required.

I have 2 computers. On the computer A, I have a custom module written in C# for powershell 3.0 and installed via a MSI. I also have a shortcut that open powershell with the module already loaded.

I can just double click on my shortcut and run my command Do-Something on this computer without any problem, like the Exchange Server powershell.

But now I would like to do it from a remote session on computer B in C#.

So my question is, how can I open a remote powershell session to computer A with my module already loaded and the shell configured so I can just run my command and obtain the same result than if I run it on computer A?

share|improve this question

migrated from stackoverflow.com Dec 9 '12 at 13:59

This question came from our site for professional and enthusiast programmers.

    
Did you have a look at psexec? –  Frank van Puffelen Dec 9 '12 at 13:22
    
No i didn't try psexec could you give me an example? I can open a remote powershell session whithout problem the problem is that it just start the regular powershell. I would prefer to start the powershell with my module already loaded but doing it from the remote session might be more hard because I don't know the installation path of the module at this point. I saw some information about PSSessionConfiguration which allow a startup script but I'm not sure its the good way to go. –  Yann Lebel Dec 9 '12 at 15:00

1 Answer 1

up vote 2 down vote accepted

I finally find a way to accomplish what I needed.

First I created a powershell script to import my module and module script file

ShellInitScript

function Get-ScriptDirectory
{
    $Invocation = (Get-Variable MyInvocation -Scope 1).Value
    Split-Path $Invocation.MyCommand.Path
}
$MyModuleDirectory = Get-ScriptDirectory
Set-Location $MyModuleDirectory 
Import-Module .\MyModule.psd1

MyModule.psd1

@{
GUID                = "[GENERATE A GUID HERE]" # Generate using $myGuid = [guid]::NewGuid() 

Author              = "Me"

CompanyName         = "My Company"

Copyright           = "© My Company. All rights reserved."

ModuleVersion       = "1.0.0.0"

ModuleToProcess     = "MyModule.psm1"
}

MyModule.psm1

Import-Module .\MyModuleCSharpAssembly.dll

function Enable-MyShellRemoting([switch]$Force)
{
    $proceed = 0

    if($Force -eq $false)
    {
        Write-Warning "Enable-MyShellRemoting restarts the WinRM service and all dependent services.`r`nAll WinRM sessions connected to Windows PowerShell session configurations are disconnected."

        $title = "Are you sure you want to perform this action?"
        $message = "Performing this operation will allow selected users to remotely run MyModule commands on this computer."

        $yes = New-Object System.Management.Automation.Host.ChoiceDescription "&Yes"

        $no = New-Object System.Management.Automation.Host.ChoiceDescription "&No"

        $options = [System.Management.Automation.Host.ChoiceDescription[]]($yes, $no)

        $proceed = $Host.UI.PromptForChoice($title, $message, $options, 0) 
    }

    if($proceed -eq 0)
    {
        Enable-PSRemoting -Force

        if((Get-WmiObject Win32_ComputerSystem).PartOfDomain -eq $false){
            Set-Item WSMan:\localhost\Client\TrustedHosts *
            Restart-Service WinRM
        }

        $path = Join-Path -Path $MyModuleDirectory  -ChildPath "ShellInitScript.ps1"
        Register-PSSessionConfiguration -Name "MyShellUri" -StartupScript $path -Force
    }
}
function Disable-MyShellRemoting([switch]$Force, [switch]$DisablePSRemoting)
{
    $proceed = 0

    if($Force -eq $false)
    {
        Write-Warning "Disable-MyShellRemoting restarts the WinRM service and all dependent services.`r`nAll WinRM sessions connected to Windows PowerShell session configurations are disconnected."

        $title = "Are you sure you want to perform this action?"
        $message = "Performing this operation will prevent all users to remotely run MyModule commands on this computer.`r`nUse the the -DisablePSRemoting switch to disable all PowerShell remoting features."

        $yes = New-Object System.Management.Automation.Host.ChoiceDescription "&Yes"

        $no = New-Object System.Management.Automation.Host.ChoiceDescription "&No"

        $options = [System.Management.Automation.Host.ChoiceDescription[]]($yes, $no)

        $proceed = $Host.UI.PromptForChoice($title, $message, $options, 0) 
    }

    if($proceed -eq 0)
    {
        if($DisablePSRemoting)
        {
            Disable-PSRemoting
        }

        if((Get-PSSessionConfiguration -Name "MyShellUri" -ErrorAction SilentlyContinue) -eq $null){
            Write-Host "The session configuration MyShellUri is already unregistered."
        }
        else {        
            Unregister-PSSessionConfiguration -Name "MyShellUri" -Force -ErrorAction Ignore
        }
    }
}

function Test-MyShellRemote()
{
    return "Test completed"
}

The dll MyModuleCSharpAssembly.dll is just a regular .Net assembly that contains custom Cmdlets.

The solution to the problem is in the function Enable-MyShellRemoting this method enable powershell remoting and register a custom Powershell Session Configuration with a statup script that load the module.

Then in C# all we have to do it's specify the ShellUri in the connection object like this

WSManConnectionInfo connectionInfo = new WSManConnectionInfo();
connectionInfo.ComputerName = "MyComputer";
connectionInfo.ShellUri = "http://schemas.microsoft.com/powershell/MyShellUri";
using (Runspace remoteRunspace = RunspaceFactory.CreateRunspace(connectionInfo))
{
     remoteRunspace.Open();
     using (PowerShell shell = PowerShell.Create())
     {
          shell.Runspace = remoteRunspace;
          shell.AddCommand("Test-MyShellRemote");
          Collection<PSObject> results = shell.Invoke();
          //the results collection contains the string return by the command
     }
     remoteRunspace.Close();
 }
share|improve this answer
    
You can use [guid]::NewGuid() then copy paste the generated guid. This guid should always be the same for you module. –  Yann Lebel Mar 21 '13 at 13:46
    
ShellInitScript can be included in profile.ps1, isn't ? –  Kiquenet Apr 9 '13 at 11:58
    
Yes it's possible but in this case the module will be loaded in all powershell console of the user but if you keep them separated you can create a separated shell more like the Exchange Server Shell. –  Yann Lebel Apr 9 '13 at 15:13

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

Not the answer you're looking for? Browse other questions tagged or ask your own question.