运行 来自 C# 的 PowerShell 6 中的 PowerShell 脚本

Run PowerShell script in PowerShell 6 from C#

我有一个与 REST 服务器通信的 PowerShell 脚本。此脚本仅适用于 PowerShell 6。 我想从 C# 调用它,因为 C# 程序需要来自 REST 服务器的信息,我不想在 C# 中重写 REST 代码。

基本上,我想 运行 来自 C# 的 PowerShell 脚本。 但是,在 C# 中,PowerShell.Create(); 创建一个使用 PowerShell 5 的 PowerShell 实例。
我已经替换了默认文件夹中的 pwsh.exe,到处删除了 PowerShell 5 等等,当我 shift+right click 在任何地方使用 "Run PowerShell here" 时,我得到了 PowerShell 6 window。但出于某种原因,C# 在使用 PowerShell class.

时坚持使用 PowerShell 5

这是我要重用的 PowerShell 代码:

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
    }
}

所以现在我尝试手动调用 PowerShell 6,首先导入一个模块然后使用它。这是我的三次尝试,它们都应该做同样的事情 :调用 Get-JSONWebToken(在 rest-api.psm1 中)并正确检索输出。

C# 版本 1,使用 PowerShell class:

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

由于某种原因,这在 PowerShell 5 上总是 运行s,因此无法使用。

C# 版本 2,使用 Process 代替

         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()

PowerShell 6 上的 运行s,但只输出我传递的参数,而不输出 Get-JSONWebToken

C# 版本 3:从 C#PS5 调用 PS6

         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();

这根本不起作用:

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

PowerShell 版本:

        $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

这也只输出我从 C# 或 PS6 或 PS5

调用时传递的参数

这在技术上并不能解决问题,但我按照 @MindSwipe 的建议做了,并完全用 C# 重写了代码。这并非易事,但最终是一个很好的优雅解决方案。

如果您对如何正确解决这个问题有想法,请post在这里,因为我仍然对如何从 C# 调用 PowerShell 6 感兴趣。