Powershell package missing/not working on release

I have a console application project where i'm using the powershell SDK, it works perfectly fine in debug but on release, everything except powershell works.

The only settings i've found where it works is when releasing the project as framework dependent and portable. Or at least it works on my pc, on other computers it says the dotnet runtime is missing, even when installed via the link provided.

Using self contained, .net6-windows and win-x86 doesn't work. Not quite sure what could be wrong? I've tried cleaning the project, the solution, restarting visual studio and my PC. Everything works as expected in debug but when I publish, powershell just doesn't work.

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

  <PropertyGroup>
      <OutputType>Exe</OutputType>
      <TargetFramework>net6.0-windows</TargetFramework>
      <UseWindowsForms>true</UseWindowsForms>
    <Nullable>enable</Nullable>
    <ImplicitUsings>enable</ImplicitUsings>
    <UserSecretsId>dotnet-SocketService-04A4D71F-C305-4A5B-BD0B-529C28B25DAD</UserSecretsId>
    <PlatformTarget>AnyCPU</PlatformTarget>
    <GeneratePackageOnBuild>True</GeneratePackageOnBuild>
  </PropertyGroup>

  <ItemGroup>
    <PackageReference Include="Microsoft.Extensions.Hosting" Version="6.0.0" />
    <PackageReference Include="Microsoft.Extensions.Hosting.WindowsServices" Version="6.0.0" />
    <PackageReference Include="Microsoft.PowerShell.SDK" Version="7.2.1" />
    <PackageReference Include="Microsoft.Toolkit.Uwp.Notifications" Version="7.1.2" />
    <PackageReference Include="System.Management" Version="6.0.0" />
    <PackageReference Include="System.Management.Automation" Version="7.2.1" />
  </ItemGroup>

  <ItemGroup>
    <Folder Include="Speedtest\" />
  </ItemGroup>

  <ItemGroup>
    <None Update="Speedtest\speedtest.exe">
      <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
    </None>
  </ItemGroup>
</Project>

Profile settings

enter image description here

EDIT:

I changed my powershell handler to use .EndInvoke(), now I finally get a proper error! I found an issue mentioning the error https://github.com/PowerShell/PowerShell/issues/7909 but installing Microsoft.Management.Infrastructure didn't resolve the issue, I installed version 2.0.0. If i try installing version 1 I get an error stating that the System.Management.Automation package requires a higher version (2.0.0)

public static string CMD(string script)
{
    string errorMsg = "";
    string output;

  
    ps.AddScript(script);

    //Make sure return values are outputted to the stream captured by C#
    ps.AddCommand("Out-String");

    PSDataCollection<PSObject> outputCollection = new PSDataCollection<PSObject>();
    ps.Streams.Error.DataAdded += (object sender, DataAddedEventArgs e) =>
    { errorMsg = ((PSDataCollection<ErrorRecord>)sender)[e.Index].ToString(); };

    IAsyncResult result = ps.BeginInvoke<PSObject, PSObject>(null, outputCollection);
    ps.EndInvoke(result);

    //while (!result.IsCompleted)
    //    Thread.Sleep(300);

    StringBuilder stringBuilder = new StringBuilder();
    foreach (PSObject outputItem in outputCollection)
    {
        stringBuilder.AppendLine(outputItem.BaseObject.ToString());
    }
    output = stringBuilder.ToString();

    //Clears commands added to runspace
    ps.Commands.Clear();

    if (!string.IsNullOrEmpty(errorMsg))
        return string.Empty;

    return output.Trim();
}

Here is the error message

Unhandled exception. System.IO.FileNotFoundException: Could not load file or assembly 'Microsoft.Management.Infrastructure, Version=1.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35'. Den angivne fil blev ikke fundet.
File name: 'Microsoft.Management.Infrastructure, Version=1.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35'
   at System.Management.Automation.Runspaces.AsyncResult.EndInvoke()
   at System.Management.Automation.PowerShell.EndInvoke(IAsyncResult asyncResult)
   at SocketService.PowerShellHandler.CMD(String script) in C:\Users\Blue\source\repos\SocketClientProject\Clientside\Handlers\PowershellHandler.cs:line 35
   at SocketService.Classes.SystemInfo..ctor() in C:\Users\Blue\source\repos\SocketClientProject\Clientside\Classes\SystemInfo.cs:line 21
   at SocketService.CommandHandler.Initialize() in C:\Users\Blue\source\repos\SocketClientProject\Clientside\Handlers\CommandHandler.cs:line 31
   at SocketService.SocketService..ctor() in C:\Users\Blue\source\repos\SocketClientProject\Clientside\SocketService.cs:line 27
   at SocketService.WindowsBackgroundService.StartAsync(CancellationToken cancellationToken) in C:\Users\Blue\source\repos\SocketClientProject\Clientside\WindowsBackgroundService.cs:line 17
   at Microsoft.Extensions.Hosting.Internal.Host.StartAsync(CancellationToken cancellationToken)
   at Microsoft.Extensions.Hosting.HostingAbstractionsHostExtensions.RunAsync(IHost host, CancellationToken token)
   at Microsoft.Extensions.Hosting.HostingAbstractionsHostExtensions.RunAsync(IHost host, CancellationToken token)
   at Program.<Main>$(String[] args) in C:\Users\Blue\source\repos\SocketClientProject\Clientside\Program.cs:line 14
   at Program.<Main>(String[] args)

[process exited with code 3762504530]

Line 14 is me calling PowerShell.Create();


Solution 1:

Without showing actual code and giving a more descriptive detailing about what's going on aside from "it doesn't work" it's difficult to say exactly what is occurring here but I'll do my best.

Thankfully, according to Microsoft's documentation you most certainly can run the Powershell SDK in a self-contained .Net application.

A self-contained .NET application can use Microsoft.PowerShell.SDK to run arbitrary PowerShell functionality without depending on any external PowerShell installations or libraries.

This leads me to believe that you may not be having an issue with the SDK itself but rather with the compiler.

Single-File deployments

I noticed in your screenshot that you are attempting to perform a single-file deployment. You could potentially be having a few issues here. One is to ensure that you're not using an incompatible API. If you are calling any of these within your application, that could be a factor:

  • Assembly.CodeBase
  • Assembly.EscapedCodeBase
  • Assembly.GetFile
  • Assembly.GetFiles
  • Assembly.Location
  • AssemblyName.CodeBase
  • AssemblyName.EscapedCodeBase
  • Module.FullyQualifiedName
  • Module.Name

As none of these are compatible with single-file deployments.

Trimming

Another issue you may be experiencing is referred to as trimming. This is where the compiler will 'trim' unused assemblies from the project at compile time and tends to happen on release runs. While I believe this is off by default you can add the following to your .csproj file to ensure that trimming is disabled:

<PropertyGroup>
    <PublishTrimmed>false</PublishTrimmed>
</PropertyGroup>

Optimizing

The JIT compiler tends to try to optimize code on release builds. When we run an application in debug mode the application is optimized for debugging the code. It tries to leave everything almost exactly as you wrote it with maybe some minor differences. When an application is run in release mode the actual code that is being run can be drastically different while maintianing the same logic. This is usually to try and make the final assembly as small and fast as possible. You can disable this optimization by the following steps:

  1. Right click on project
  2. Click "properties"
  3. Go to "Build"
  4. Under the section "general" deactivate "Optimize Code"

optimizecode

Other than the above mentioned possible causes I can't think of much more I can offer without seeing code, or error messages, or further details.

Solution 2:

What ended up solving my issue was this answer: Dotnet publish not publishing DLL to publish directory

I changed the target runtime to win10-x86 and that worked!

<TargetFramework>net6.0-windows</TargetFramework>
<RuntimeIdentifier>win10-x86</RuntimeIdentifier>