从C#在PowerShell 6中运行PowerShell脚本 [英] Run PowerShell script in PowerShell 6 from C#

查看:159
本文介绍了从C#在PowerShell 6中运行PowerShell脚本的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

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#.

所以基本上,我想从C#运行PowerShell脚本. 但是 ,在C#中,PowerShell.Create();创建一个使用PowerShell 5的PowerShell实例.
我已经替换了默认文件夹中的pwsh.exe,在所有位置删除了PowerShell 5,等等.当我在任何地方shift+right click使用在此处运行PowerShell" 时,我得到一个PowerShell 6窗口.但是由于某些原因,C#在使用PowerShell类时坚持使用PowerShell 5.

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.

这是我要重用的PowerShell代码:

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

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

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#版本1 ,使用PowerShell类:

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

由于某种原因,它始终在PowerShell 5上运行,因此无法使用.

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

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上运行,但仅输出我传递的参数,而不输出Get-JSONWebToken的输出.

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

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

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

这根本不起作用:

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调用时传递的参数.

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

推荐答案

从技术上讲,这并不能解决问题,但是我做到了 @MindSwipe 建议并完全用C#重写代码.这并不是一件容易的事,但最终还是一个不错的解决方案.

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.

如果您有关于如何正确解决此问题的想法,请在此处发布,因为我仍然对如何从C#调用PowerShell 6上的内容感兴趣.

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#.

这篇关于从C#在PowerShell 6中运行PowerShell脚本的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆