Run PowerShell script in PowerShell 6 from C#

一曲冷凌霜 提交于 2019-12-11 03:56:44

问题


I have a PowerShell script which communicates with a REST server. This script only works in PowerShell 6. I want to call it from C#, because the C# program needs the info from the REST server, and I don't want to rewrite the REST code in C#.

So basically, I want to run a PowerShell script from C#. However, in C#, PowerShell.Create(); creates a PowerShell instance that uses PowerShell 5.
I already replaced pwsh.exe in the default folder, deleted PowerShell 5 everywhere etc. and when I shift+right click anywhere to use "Run PowerShell here" I get a PowerShell 6 window. But for some reason, C# sticks to using PowerShell 5, when using the PowerShell class.

This is the PowerShell code I want to reuse:

function Get-JSONWebToken {
    param (
      [Parameter(Mandatory=$True)][string] $BaseUri,
      [Parameter(Mandatory=$True)][string] $ApiToken
    )
    if ($PSVersionTable.PSVersion.Major -lt 6) {
        $version = $PSVersionTable.PSVersion
        Throw "Your PowerShell version is: $version. Please upgrade to PowerShell 6 or above"
    }

    $uri = "$BaseUri/auth/token"    
    $bodyJson = ConvertTo-Json @{token = $ApiToken} -Compress

    Write-Host "Authenticating ..."
    try {
        $response = Invoke-RestMethod `
            -Uri $uri `
            -Method Post `
            -ContentType "application/json" `
            -Body $bodyJson
        $jwtToken = $response.token
        $secureToken = ConvertTo-SecureString $jwtToken -AsPlainText -Force
        return $secureToken    
    }
    catch {
        #handle error
    }
}

So now I am trying to call PowerShell 6 manually, importing a module first and then using it. Here are my three attempts, which are all supposed to do the same thing: call Get-JSONWebToken (in rest-api.psm1) and retrieve the output correctly.

C# version 1, using PowerShell class:

         ps = PowerShell.Create();
         //module import...
         PSCommand cmd = ps.Commands.AddCommand("Get-JSONWebToken");
         cmd.AddParameter("baseUri", baseUri);
         cmd.AddParameter("apiToken", apiToken);
         ps.Invoke();

This always runs on PowerShell 5 for some reason so it can't be used.

C# version 2, using a Process instead

         Process ps6 = new Process();
         ps6.StartInfo = new ProcessStartInfo {
             FileName = "C:/Program Files/PowerShell/6/pwsh.exe",
             Arguments = "-Command {\n" +
                           "Import-Module " + modulePath + ";\n" +
                           "Get-JSONWebToken " + apiToken + ";\n" +
                         "}",
             UseShellExecute = false,
             RedirectStandardOutput = true,
             RedirectStandardError = true,
             CreateNoWindow = false
         };
         ps6.Start()

This runs on PowerShell 6, but only outputs the arguments I passed, and not the output of Get-JSONWebToken.

C# version 3: Calling PS6 from PS5 from C#

         PSCommand cmd = ps.Commands.AddCommand("C:/Program Files/PowerShell/6/pwsh.exe");
         ScriptBlock sb = ScriptBlock.Create("Import-Module " + modulePath + "; Get-JSONWebToken " + apiToken + ";");
         cmd.AddParameter("Command", sb);
         ps.Invoke();

This doesn't work at all:

Result: Usage: pwsh[.exe] [[-File] <filePath> [args]]
Result:                   [-Command { - | <script-block> [-args <arg-array>]
Result:                                 | <string> [<CommandParameters>] } ]
Result:                   [-ConfigurationName <string>] [-CustomPipeName <string>]
...
...

PowerShell version:

        $pinfo = New-Object System.Diagnostics.ProcessStartInfo
        $pinfo.FileName = $Ps6Path
        $pinfo.RedirectStandardError = $true
        $pinfo.RedirectStandardOutput = $true
        $pinfo.CreateNoWindow = $false
        $pinfo.Arguments = "-Command {Import-Module <myPath>\rest-api.psm1; Get-JSONWebToken 123inputStringExample;}"

        $p = New-Object System.Diagnostics.Process
        $p.StartInfo = $pinfo
        $p.Start() | Out-Null
        $p.WaitForExit()
        $stdout = $p.StandardOutput.ReadToEnd()
        $stderr = $p.StandardError.ReadToEnd()
        Write-Host "stdout: $stdout"
        Write-Host "stderr: $stderr"
        Write-Host "exit code: " + $p.ExitCode

This also only outputs the arguments I passed when called either from C# or from PS6 or PS5


回答1:


This doesn't technically solve the problem, but I did as @MindSwipe suggested and rewrote the code in C# entirely. It wasn't trivially easy but it's a nice and elegant solution in the end.

If you have an idea on how to solve this question properly, please post it here as I'm still interested in how to call stuff on PowerShell 6 from C#.



来源:https://stackoverflow.com/questions/58954588/run-powershell-script-in-powershell-6-from-c-sharp

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!