Skip to content

Provide a way to host PowerShell in a CoreCLR application #2291

Description

@vors

This is follow-up from #2284

Steps to reproduce

Create a simple coreclr app that hosts powershell thru Microsoft.PowerShell.SDK

Note: the current function of Microsoft.PowerShell.SDK is to provide an ability to compile binary modules that then could be imported and used in PowerShell on any platform. This issue asks a question: should we allow the same nuget package to enable hosting scenario?

Program.cs

using System;
using System.Management.Automation;

class Program
{
    static void Main(string[] args)
    {
        PowerShellAssemblyLoadContextInitializer.SetPowerShellAssemblyLoadContext(AppContext.BaseDirectory);

        using (var ps = PowerShell.Create())
        {
        ps.AddScript("Get-Process | Out-String");
        var result = ps.Invoke()[0];
            Console.WriteLine(result.ToString());
        }
    }
}

project.json

{
  "version": "1.0.0-*",
  "buildOptions": {
    "debugType": "portable",
    "emitEntryPoint": true
  },
  "dependencies": {},
  "frameworks": {
    "netcoreapp1.0": {
      "dependencies": {
        "Microsoft.NETCore.App": {
          "type": "platform",
          "version": "1.0.1"
        },
        "Microsoft.PowerShell.SDK" : "1.0.0-alpha10"
      },
      "imports": "dnxcore50"
    }
  }
}

nuget.config

<?xml version="1.0" encoding="utf-8"?>
<configuration>
  <config>
    <!-- install packages to a custom path -->
    <add key="repositoryPath" value="Packages"/>
  </config>
  <packageSources>
    <clear />
    <add key="nuget.org" value="https://api.nuget.org/v3/index.json" />
    <add key="powershell-core" value="https://powershell.myget.org/F/powershell-core/api/v3/index.json" />
  </packageSources>
</configuration>

dotnet restore works fine, dotnet run doesn't

Expected behavior

You should be able to run and execute

Actual behavior

On Unix (note that 6.0.0-alpha10 package doesn't have libs compile under Unix configuration, so that's expected)

Unhandled Exception: System.TypeInitializationException: The type initializer for 'System.Management.Automation.Runspaces.RunspaceFactory' threw an exception. ---> System.DllNotFoundException: Unable to load DLL 'api-ms-win-eventing-provider-l1-1-0.dll': The specified module could not be found.
 (Exception from HRESULT: 0x8007007E)
   at System.Management.Automation.Tracing.EtwActivity.UnsafeNativeMethods.EventActivityIdControl(ActivityControlCode controlCode, Guid& activityId)
   at System.Management.Automation.Tracing.EtwActivity.GetActivityId()
   at System.Management.Automation.Runspaces.RunspaceFactory..cctor()
   --- End of inner exception stack trace ---
   at System.Management.Automation.Runspaces.RunspaceFactory.CreateRunspace()
   at System.Management.Automation.PowerShell.Worker.CreateRunspaceIfNeededAndDoWork(Runspace rsToUse, Boolean isSync)
   at System.Management.Automation.PowerShell.CoreInvokeHelper[TInput,TOutput](PSDataCollection`1 input, PSDataCollection`1 output, PSInvocationSettings settings)
   at System.Management.Automation.PowerShell.CoreInvoke[TInput,TOutput](PSDataCollection`1 input, PSDataCollection`1 output, PSInvocationSettings settings)
   at System.Management.Automation.PowerShell.CoreInvoke[TOutput](IEnumerable input, PSDataCollection`1 output, PSInvocationSettings settings)
   at System.Management.Automation.PowerShell.Invoke(IEnumerable input, PSInvocationSettings settings)
   at System.Management.Automation.PowerShell.Invoke()
   at Program.Main(String[] args)

On Windows

Unhandled Exception: System.Management.Automation.Runspaces.PSSnapInException: Cannot load Windows PowerShell snap-in Microsoft.PowerShell.Diagnostics because of the following error: Could not load file or assembly 'Microsoft.PowerShell.Commands'. The system cannot find the file specified.
   at System.Management.Automation.Runspaces.RunspaceConfigForSingleShell.LoadMshSnapinAssembly(PSSnapInInfo mshsnapinInfo)
   at System.Management.Automation.Runspaces.RunspaceConfigForSingleShell.LoadPSSnapIn(PSSnapInInfo mshsnapinInfo)
   at System.Management.Automation.Runspaces.RunspaceConfigForSingleShell.LoadPSSnapIns(Collection`1 mshsnapinInfos, PSConsoleLoadException& warning)
   at System.Management.Automation.Runspaces.RunspaceConfigForSingleShell.LoadConsole(PSConsoleLoadException& warning)
   at System.Management.Automation.Runspaces.RunspaceConfigForSingleShell.CreateDefaultConfiguration()
   at System.Management.Automation.Runspaces.RunspaceConfiguration.Create()
   at System.Management.Automation.Runspaces.RunspaceFactory.CreateRunspace(PSHost host)
   at System.Management.Automation.Runspaces.RunspaceFactory.CreateRunspace()
   at System.Management.Automation.PowerShell.Worker.CreateRunspaceIfNeededAndDoWork(Runspace rsToUse, Boolean isSync)
   at System.Management.Automation.PowerShell.CoreInvokeHelper[TInput,TOutput](PSDataCollection`1 input, PSDataCollection`1 output, PSInvocationSettings settings)
   at System.Management.Automation.PowerShell.CoreInvoke[TInput,TOutput](PSDataCollection`1 input, PSDataCollection`1 output, PSInvocationSettings settings)
   at System.Management.Automation.PowerShell.CoreInvoke[TOutput](IEnumerable input, PSDataCollection`1 output, PSInvocationSettings settings)
   at System.Management.Automation.PowerShell.Invoke(IEnumerable input, PSInvocationSettings settings)
   at System.Management.Automation.PowerShell.Invoke()
   at Program.Main(String[] args)

Environment data

> $PSVersionTable
Name                           Value                                                                                                        
----                           -----                                                                                                        
PSVersion                      6.0.0-alpha                                                                                                  
PSEdition                      Core                                                                                                         
PSCompatibleVersions           {1.0, 2.0, 3.0, 4.0...}                                                                                      
BuildVersion                   3.0.0.0                                                                                                      
GitCommitId                    v6.0.0-alpha.10                                                                                              
CLRVersion                                                                                                                                  
WSManStackVersion              3.0                                                                                                          
PSRemotingProtocolVersion      2.3                                                                                                          
SerializationVersion           1.1.0.1                                                                                                      

Activity

  1. daviwil commented on Sep 17, 2016

    @daviwil
    Contributor

    Hosting PowerShell in your own process is more difficult due to the necessity of loading PowerShell's AssemblyLoadContext before CoreCLR's, or at least this is the impression I came away with after talking to Dongbo Wang (@daxian-dbw). Dongbo should be able to tell you more about it.

  2. vors commented on Sep 17, 2016

    @vors
    CollaboratorAuthor

    My understanding is it doesn't have to be before loading coreclr. In https://github.com/PowerShell/PowerShell/blob/master/src/powershell/Program.cs we are doing exactly that: initializing ALC in the managed code.

    I included a line

    PowerShellAssemblyLoadContextInitializer.SetPowerShellAssemblyLoadContext(AppContext.BaseDirectory);
    

    which I took from our XUnit tests, but it may need some alterations.
    Actually, that's indeed could be the problem with windows version (improper ALC init).

  3. daxian-dbw commented on Sep 19, 2016

    @daxian-dbw
    Member

    For a CoreCLR application to host powershell, if the powershell assemblies are in its TPA list, then it has to use one of the Initialize* method to call into the actual entry point:

    PowerShellAssemblyLoadContextInitializer.InitializeAndLoadEntryAssembly(string basePaths, AssemblyName entryAssemblyName);
    PowerShellAssemblyLoadContextInitializer.InitializeAndCallEntryMethod(string basePaths, AssemblyName entryAssemblyName, string entryTypeName, string entryMethodName, object[] args);
    

    You can find an example at https://github.com/PowerShell/PowerShell/blob/master/src/powershell/Program.cs#L27

    SetPowerShellAssemblyLoadContext is for CoreCLR applications that don't have powershell assemblies in their TPA list, which are usually native CoreCLR hosts. Initialize* APIs are for CoreCLR applications that have powershell assemblies in their TPA list, which are usually managed hosts that leverage dotnet.exe.

  4. erwinwildenburg commented on Sep 28, 2016

    @erwinwildenburg

    If I add the following code it works:
    PowerShellAssemblyLoadContextInitializer.SetPowerShellAssemblyLoadContext("C:\\Program Files\\PowerShell\\6.0.0.10");

    Seems like the required dll's are not being copied to the bin folder.

    For example:

    PowerShellAssemblyLoadContextInitializer.SetPowerShellAssemblyLoadContext("C:\\Program Files\\PowerShell\\6.0.0.10");
    
    using (PowerShell ps = PowerShell.Create())
    {
        ps.AddScript("Write-Host 'It works!'");
        var result = ps.Invoke()[0];
            Console.WriteLine(result.toString());
    }
    

    capture

  5. added this to the milestone on Nov 4, 2016
  6. modified the milestones: , on Dec 19, 2016
  7. iztokp commented on Jan 19, 2017

    @iztokp

    Any hints on how to make this work on Linux (CentOS)?

  8. changed the title [-]Provide a way to host powershell in coreclr application[/-] [+]Provide a way to host Powershell in a CoreCLR application[/+] on Mar 20, 2017
  9. changed the title [-]Provide a way to host Powershell in a CoreCLR application[/-] [+]Provide a way to host PowerShell in a CoreCLR application[/+] on Mar 20, 2017
  10. daxian-dbw commented on Mar 25, 2017

    @daxian-dbw
    Member

    A documentation about hosting powershell core is added: https://github.com/PowerShell/PowerShell/tree/master/docs/host-powershell

    Iztok Prelog (@iztokp) Unfortunately, as discussed here, all powershell NuGet packages that have been published so far only contain powershell assemblies built specifically for Windows. We need to publish NuGet packages that contain both Windows and Unix assemblies (#3417 is opened to track this), but dotnet pack doesn't seem to support that.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Labels

Issue-Metaan issue used to track multiple issuesWG-Maintainers-Buildspecific to affecting the build

Type

No type

Projects

No projects

    Milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions