Home > Software design >  How to Host PowerShell 5 from WinUI 3 C# App
How to Host PowerShell 5 from WinUI 3 C# App

Time:02-15

Hoping to get some guidance around hosting PowerShell 5.1 within a C# WinUI 3 application targeting .NET 6. I've been trying numerous different NuGet packages and unfortunately, the only thing I've been able to get working will call PowerShell 7. In my case, I need to be able to call PowerShell 5.1...

Packages I've tried adding:

  • Microsoft.PowerShell.5.ReferenceAssemblies - Not compatible

    • Warning NU1701 Package 'Microsoft.PowerShell.5.ReferenceAssemblies 1.1.0' was restored using '.NETFramework,Version=v4.6.1, .NETFramework,Version=v4.6.2, .NETFramework,Version=v4.7, .NETFramework,Version=v4.7.1, .NETFramework,Version=v4.7.2, .NETFramework,Version=v4.8' instead of the project target framework 'net6.0-windows10.0.19041'. This package may not be fully compatible with your project.
  • Microsoft.PowerShell.SDK - Only available for use with PowerShell 7, not Windows PowerShell 5.1

  • PowerShellLibrary.Standard - I don't believe this is applicable for hosting PowerShell within an app

I can work around this a bit by just calling a new process:

var script = "C:\\scripts space\\MultiLineTestScript.ps1";
var process = new Process
{
     StartInfo = new ProcessStartInfo(@"C:\Windows\System32\WindowsPowerShell\v1.0\powershell.exe", "-ExecutionPolicy Bypass -NoProfile -File \""   script   "\"")
        {
            RedirectStandardOutput = true,
            CreateNoWindow = true
        }
 };
 process.Start();

This works, but with that said I'd rather use a supported SDK or reference assembly if possible. Particularly for easier implementation of runspaces and getting the PowerShell host to run on a separate thread without hanging the UI.

I've found this: https://devblogs.microsoft.com/powershell/depending-on-the-right-powershell-nuget-package-in-your-net-project/

Is it not supported/possible to host Windows PowerShell 5.1 within a WinUI 3 .net Core app? Any help would be appreciated, I am generally a PowerShell user not a C# dev but I am stumbling my way through.

CodePudding user response:

tl;dr

  • I don't think hosting the Windows PowerShell SDK in a .NET (Core) application is possible.

  • Calling PowerShell in a child process via its CLI, powershell.exe, may indeed be your only option.

Note: My knowledge of .NET Framework to .NET (Core) interop is limited; do let us know if I'm missing something.


To start with a recap:

Since Windows PowerShell is based on the legacy, Windows-only .NET Framework (as opposed to its successor, the cross-platform .NET Core / .NET 5 framework), so is the NuGet SDK package that allows hosting Windows PowerShell in an application, Microsoft.PowerShell.5.1.ReferenceAssemblies.

Your project targets .NET 6.0 (net60), which is why you're seeing a warning regarding the mismatch in target frameworks when you build your project.


While the fact that this is only a warning, not an error, suggests that this mismatched combination may situationally work nonetheless, this does not appear to be the case for trying to host Windows PowerShell in a .NET (Core) 6.0 application: an exception is thrown on trying to instantiate the PowerShell class: System.InvalidProgramException: Common Language Runtime detected an invalid program.

Using the Microsoft.Windows.Compatibility package (discussed in this article) doesn't help.

Therefore, I suspect that calling Windows PowerShell via its CLI, powershell.exe, as a child process may indeed be the only option.

Apart from being slower and more resource-intensive, an additional drawback is that only text output can be received.

CodePudding user response:

You may still use the Microsoft.PowerShell.5.ReferenceAssemblies package in a .NET 6 app despite the warning.

If you test your code properly to make sure that it doesn't use any .NET Framework APIs that are not available in the .NET 6 runtime behind the scenes you're safe.

You can then get rid of the warning by adding a <NoWarn> element to the .csproj project file:

<PackageReference Include="Microsoft.PowerShell.5.ReferenceAssemblies" Version="1.1.0">
    <NoWarn>NU1701</NoWarn>
</PackageReference>

It's either that or use the Process API to start a new Powershell process I guess.

  • Related