Search code examples
windowspowershell.net-corepowershell-sdk

.Net Powershell SDK 6.2.6 - Why are PKI module commands unavailable on some systems?


The short question

Why, when I run the Get-Command powershell command within a .NET 5.0 application using the Microsoft.PowerShell.SDK nuget package I get different results on different systems, and those results are different to running the same command manually within powershell, even on the same system?

Example code

This basically shows how the code runs commands, though it does have more output stream handling etc..

var initialState = InitialSessionState.CreateDefault();
initialState.ExecutionPolicy = ExecutionPolicy.Unrestricted;
using (var ps = PowerShell.Create(initialState))
{
    ps.AddScript("Get-Command");
    var pipelineObjects = await ps.InvokeAsync();
    //**Snip code to interpret pipelineObjects here**
}

The app is explicitly published with a target runtime of win7-x86 if that makes any difference, but the intention is to never run it on anything older than win10 x64 systems really.

The basic problem

  • I need to run some powershell scripts from a .NET 5.0 Application which targets multiple OSes
  • these scripts rely on some PKI module commands e.g. New-SelfSignedCertificate and Export-PfxCertificate
  • running this code on my system, I can see the PKI commands are output
  • running Get-Command in powershell manually on my system, whilst the list of commands is not quite the same, those PKI commands are still there
  • running this code on some systems results in no PKI commands, which means if I try to use this code to run those scripts, it fails.
  • running Get-Command manually on the failing systems and I do see those commands - so the scripts work if I run them manually, just not via the app.

I understand that using the SDK I'm in effect bundling a PowerShell 6 runtime with the app which might have different/limited commands available, but since these commands do appear on mine then I believe this indicates it's "falling back" to the cmdlets available on the system (they can't be bundled in with the SDK as then surely I'd not be having this issue at all)

I have found that on some older Windows 10 installs, if you fully update the system via windows update it can fix this apparent problem, but all Windows Server 2016/2019 systems I've so far found seem to exhibit this issue.... but there has been one Windows 10 machine which seems to still have this problem even post-updates.

Currently I can work around this by manually running the various scripts, but this is precisely the sort of time waste that running them via an app was meant to solve.

I've searched around quite a bit but I've not found an answer to this. So:

  • if a cmdlet is not natively supported by the SDK, what are the rules for how it might "search" for other commands?
  • how can I explicitly Import the PKI module within the code above? I've attempted adding initialState.ImportPSModule("PKI"); prior to running but it had no effect (also didn't cause any error)

Happy to accept I've done something stupid somewhere, but it's frustrating how it works on 90% of systems.


Solution

  • OK, I have found what appears to be a workaround, having cobbled together some bits of info from various sources.

    The solution that seems to work is to inject this into the start of the script I'm trying to run:

    Import-Module PKI -SkipEditionCheck;
    

    The SDK means I'm effectively running Powershell Core, and the PKI module has apparently not been ported to this, so hence you need the -SkipEditionCheck param.

    Whilst as I said above I attempted to use the InitialSessionState.ImportPSModule() method to do the same thing, this did not work - perhaps because there doesn't seem to be an overload equivalent to the -SkipEditionCheck param? No idea.

    This appears to have worked based on preliminary testing, I will come back and edit this answer should I find further issues with it.