Powershell: Feature Request - Bring back ConsoleShell functionallity

Created on 26 May 2019  路  24Comments  路  Source: PowerShell/PowerShell

Hey guys,
In my product team we created a custom powershell-based shell in as a way to controll our cloud service.
We did this based on the ConsoleShell object and customised RunspaceConfiguration.

As a part of moving to .Net Core we started examing the posibillity of moving our shell to powershell core but as we all know RunspaceConfiguration does not exist in the core version and there is no way to pass InitialSessionState to the ConsoleShell.Start() method.

if we could pass a initialSessionState to the Start method that would be great!

Thanks,
Asaf.

Resolution-Fixed WG-DevEx-SDK

Most helpful comment

It seems that when we removed RunspaceConfiguration, we should have added back an overload to accept InitialSessionState. cc @JamesWTruher

All 24 comments

@SteveL-MSFT Could you please comment the scenario and feature request? What is recommended way to create custom PowerShell console shell?

It seems that when we removed RunspaceConfiguration, we should have added back an overload to accept InitialSessionState. cc @JamesWTruher

:tada:This issue was addressed in #9802, which has now been successfully released as v7.0.0-preview.2.:tada:

Handy links:

@asrosent @SteveL-MSFT is ConsoleShell class included in Microsoft.PowerShell.SDK nuget package? I seem to have hard time finding it with version 6.2.3

As noted above by the bot, the change was made available in v7.0.0-preview.2 -- I expect a new SDK package will be published when 7.0.0 gets a GA release (which if I recall correctly may be sometime in December/January?)

Don't think the PS team tend to publish preview SDKs, historically speaking. 馃檪

Thanks @vexx32 for pointing that out, the related PR adds back taking InitialSessionState as parameter, but what I'm experiencing is I couldn't even find the ConsoleShell class. But before the PR, the class still exists publicly, so I was thinking if I'm looking at the wrong package...

Oh, that's a good point, my apologies! Not sure... have to defer to @SteveL-MSFT on that point. 馃檪

The Microsoft.PowerShell.ConsoleShell class has always been there. The only change was to add back an overload:

PS> [Microsoft.PowerShell.ConsoleShell]::Start

OverloadDefinitions
-------------------
static int Start(string bannerText, string helpText, string[] args)
static int Start(initialsessionstate initialSessionState, string bannerText, string helpText, string[] args)

@SteveL-MSFT that's what I thought, but I couldn't find it in PowerShell Core:
https://docs.microsoft.com/en-us/dotnet/api/?view=pscore-6.2.0&term=ConsoleShell
Is it part of the Microsoft.PowerShell.Sdk package?
https://www.nuget.org/packages/Microsoft.PowerShell.SDK/

https://docs.microsoft.com/en-us/dotnet/api/microsoft.powershell.consoleshell?view=powershellsdk-1.1.0

Not sure why it's missing from that API browser thought... weird. Pretty sure it should be in the SDK? Might be a docs issue, potentially.

This class provides an entry point which is called by minishell's main to transfer control to Msh console host implementation.

@vexx32 you referred to Windows PowerShell while I'm seeking it in PowerShell Core 馃槂

Yeah, I'm wondering if the API docs aren't entirely up to date. If the PS Core SDK includes the referenced DLL (Microsoft.PowerShell.ConsoleHost.dll) then ConsoleShell should be available.

OK, I think I may get the reason, Microsoft.PowerShell.ConsoleHost.dll is not included in Microsoft.PowerShell.SDK, instead it's part of another package Microsoft.PowerShell.ConsoleHost 馃槂

The nuget package contains Microsoft.PowerShell.ConsoleHost.dll in runtimes for different platforms. @SteveL-MSFT this may sound silly, but how do I reference the class ConsoleShell in my C# codes?

There might be a problem with the nupkg for ConsoleHost.dll. I tried a simple app and had to directly ref the assembly to get it to work, but still got this warning:

PS> dotnet publish --runtime osx-x64
Microsoft (R) Build Engine version 16.4.0-preview-19502-03+3af680463 for .NET Core
Copyright (C) Microsoft Corporation. All rights reserved.

  Restore completed in 1.06 sec for /Users/steve/test/consoleshell/consoleshell.csproj.
  You are using a preview version of .NET Core. See: https://aka.ms/dotnet-core-preview
CSC : warning CS8012: Referenced assembly 'Microsoft.PowerShell.ConsoleHost, Version=6.2.3.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35' targets a different processor. [/Users/steve/test/consoleshell/consoleshell.csproj]
  consoleshell -> /Users/steve/test/consoleshell/bin/Debug/netcoreapp2.1/osx-x64/consoleshell.dll
  consoleshell -> /Users/steve/test/consoleshell/bin/Debug/netcoreapp2.1/osx-x64/publish/

For now, to get unblocked, try referencing the assembly directly:

    <Reference Include="Microsoft.PowerShell.ConsoleHost">
      <HintPath>/Users/steve/.nuget/packages/microsoft.powershell.consolehost/6.2.3/runtimes/osx/lib/netcoreapp2.1/Microsoft.PowerShell.ConsoleHost.dll</HintPath>
    </Reference>

cc @adityapatwardhan

@SteveL-MSFT using your work-around I could get assembly reference in place, however, when the shell starts, I'm seeing following error:

The shell cannot be started. A failure occurred during initialization: Object reference not set to an instance of an object.

The issue is reproducible with Microsoft.PowerShell.SDK version 6.2.3 targeting netcoreapp2.1

using Microsoft.PowerShell;

namespace PSCore
{
    class Program
    {
        static void Main(string[] args)
        {
            ConsoleShell.Start("Hello", "", new string[0] { });
        }
    }
}

<Project Sdk="Microsoft.NET.Sdk">

  <PropertyGroup>
    <OutputType>Exe</OutputType>
    <TargetFramework>netcoreapp2.1</TargetFramework>
  </PropertyGroup>

  <ItemGroup>
    <PackageReference Include="Microsoft.PowerShell.SDK" Version="6.2.3" />
  </ItemGroup>

  <ItemGroup>
    <Reference Include="Microsoft.PowerShell.ConsoleHost">
      <!-- NETCORE workaround for GitHub issue https://github.com/PowerShell/PowerShell/issues/9734 -->
      <HintPath>$(NuGetPackageRoot)\microsoft.powershell.consolehost\6.2.3\runtimes\win-x64\lib\netcoreapp2.1\Microsoft.PowerShell.ConsoleHost.dll</HintPath>
    </Reference>
  </ItemGroup>

</Project>

The issue seems to be non-existent with version 7.0.0-preview4 forwards. Switching to this version would require us to target .netcoreapp3.0. Is there any work around to stay at version 6?

Unfortunately, it seems there was a bug in 6.2 that has since been fixed in 7. I don't see any workaround to stay on 6. We are planning to GA PS7 in Jan, so it's not too far off.

@SteveL-MSFT with preview-5, I updated my sample code to

using Microsoft.PowerShell;
using System.Management.Automation.Runspaces;

namespace ConsoleApp
{
    class Program
    {
        static void Main(string[] args)
        {
            InitialSessionState config = InitialSessionState.CreateDefault();
            config.StartupScripts.Add("Get-ChildItem");
            ConsoleShell.Start(config, "", "", args);
        }
    }
}

It seems like StartupScripts are not executed?

@ritchxu StartupScripts are executed, but the results are not collected and not displayed. The code that executes it is here:
https://github.com/PowerShell/PowerShell/blob/5ad4d2c399317e3b3cca9fbe448c3891ad6c1870/src/System.Management.Automation/engine/InitialSessionState.cs#L2893-L2903

@daxian-dbw Maybe add logging in the code or script block logging already works here?

@daxian-dbw here is my proof of concept code. I was expecting current working directory to become C:\ once the console shell is started. Did I miss anything?

Program.cs:

using Microsoft.PowerShell;
using System.Management.Automation.Runspaces;

namespace Test
{
    class Program
    {
        static void Main(string[] args)
        {
            InitialSessionState initialSessionState = InitialSessionState.CreateDefault2();
            initialSessionState.StartupScripts.Add(@"Set-Location C:\");
            ConsoleShell.Start("Hello", "", new string[0] { });
        }
    }
}

Test.csproj

<Project Sdk="Microsoft.NET.Sdk">

  <PropertyGroup>
    <OutputType>Exe</OutputType>
    <TargetFramework>netcoreapp3.1</TargetFramework>
  </PropertyGroup>

  <ItemGroup>
    <PackageReference Include="Microsoft.PowerShell.SDK" Version="7.0.0-preview.6" />
  </ItemGroup>

  <ItemGroup>
    <Reference Include="Microsoft.PowerShell.ConsoleHost">
      <HintPath>$(NuGetPackageRoot)\microsoft.powershell.consolehost\7.0.0-preview.6\runtimes\win\lib\netcoreapp3.1\Microsoft.PowerShell.ConsoleHost.dll</HintPath>
    </Reference>
  </ItemGroup>

</Project>

@ritchxu initialSessionState.StartupScripts is for you to run one more more script files (.ps1), not script code directly. Here is the code to process the startup scripts:
https://github.com/PowerShell/PowerShell/blob/5ad4d2c399317e3b3cca9fbe448c3891ad6c1870/src/System.Management.Automation/engine/InitialSessionState.cs#L2858-L2876

This line psToInvoke.AddCommand(new Command(startupScript, false, false)); creates a new command by specifying that it's not a script (the first false argument).

The name of that property is unfortunately vague 馃槮 The following is an example to use this property:

Program.cs:
```c#
using System;
using System.Management.Automation.Runspaces;
using Microsoft.PowerShell;

namespace testConsoleRef
{
class Program
{
static void Main(string[] args)
{
InitialSessionState config = InitialSessionState.CreateDefault();
config.ExecutionPolicy = ExecutionPolicy.RemoteSigned;
config.StartupScripts.Add(@"E:arenadotnetAppdotnet3testConsoleRefstartup.ps1");

        int ret = ConsoleShell.Start(config, "Hello", "", new string[0]);
        Console.WriteLine(ret);
    }
}

}

testConsoleRef.csproj:
```xml
<Project Sdk="Microsoft.NET.Sdk">

  <PropertyGroup>
    <OutputType>Exe</OutputType>
    <TargetFramework>netcoreapp3.1</TargetFramework>
  </PropertyGroup>

  <ItemGroup>
    <PackageReference Include="Microsoft.PowerShell.SDK" Version="7.0.0" />
  </ItemGroup>

</Project>

Here is the results from execute this sample. The startup.ps1 has cd f:\tmp in it, and the working directory is changed to that after dotnet run

[E:\arena\dotnetApp\dotnet3\testConsoleRef]
PS:22> cat .\startup.ps1
cd f:\tmp
[E:\arena\dotnetApp\dotnet3\testConsoleRef]
PS:23> dotnet run
Hello

[F:\tmp]
PS:1> $pshome
E:\arena\dotnetApp\dotnet3\testConsoleRef\bin\Debug\netcoreapp3.1\runtimes\win\lib\netcoreapp3.1
[F:\tmp]
PS:2> exit
0
[E:\arena\dotnetApp\dotnet3\testConsoleRef]
PS:24> 

You could add a command config.Commands.Add(...)

:tada:This issue was addressed in #11545, which has now been successfully released as v7.0.0-rc.2.:tada:

Handy links:

Was this page helpful?
0 / 5 - 0 ratings