寻找如何在没有C#Cmdlet定义的情况下向PowerShell运行空间编写详细消息或调试字符串消息

时间:2019-02-27 18:09:24

标签: c# powershell

我有一个C#类库,该库提供了许多可以从PowerShell脚本(.PS1)和高级模块(.PSM1)调用的接口。我有一个静态方法,可以使用System.Console类将详细信息和调试消息写入控制台:

public class Write
{

        public static void Verbose(string msg, string source)
        {

            if (Config.EnableVerbose)
            {

                ConsoleColor originalForeGroundColor = Console.ForegroundColor;
                ConsoleColor originalBackGroundColor = Console.BackgroundColor;
                Console.ForegroundColor = ConsoleColor.Yellow;
                Console.BackgroundColor = ConsoleColor.Black;
                Console.Write("VERBOSE: {0} {1}{2}", source, msg, Environment.NewLine);
                Console.ForegroundColor = originalForeGroundColor;
                Console.BackgroundColor = originalBackGroundColor;

            }

       }

}

但是,当这些消息显示在PowerShell控制台中时,无法使用重定向来捕获它们,例如使用Out-File>&0甚至使用Start-Transcript

我已阅读about_Redirection,并且使用redirect修饰符无法捕获控制台输出。例如,使用PowerShell高级功能(又名Cmdlet),我写了:

Get-CommandTrace -ScriptBlock { Get-Resource } *> C:\Temp\capture.log

Get-CommandTrace Cmdlet在执行ScriptBlock期间设置$VerbosePreference = 'Continue',并从那里的Get-Resource输出中捕获详细信息。但是不会从我的C#库中捕获控制台输出。

所以,我的问题很简单:既不是Cmdlet类,也不是继承类的C#类是否能够将输出写入从中调用它的现有PowerShell Runspace?

2 个答案:

答案 0 :(得分:2)

注意:

  • 这不是完整的答案,因为它有严重的局限性。
  • 我希望这是一个起点,也许其他人可以帮助改善它。

挑战在于写入调用管道的输出流(如您所见,通过Console进行的写入与PowerShell的输出流无关,并直接打印到控制台)。

虽然我能够获得对调用 runspace 的引用,但是我不知道如何从运行管道中获得一个,所以我能做到最好想到的是创建一个嵌套管道,该管道部分起作用,但以下代码的注释中讨论了限制:

Add-Type -TypeDefinition @'
  using System.Management.Automation;
  using System.Management.Automation.Runspaces;

  public class Write
  {

      public static void Verbose(string msg)
      {
        // Create a nested pipeline in the current runspace and
        // call Write-Verbose in it.
        var rs = Runspace.DefaultRunspace
                  .CreateNestedPipeline("Write-Verbose \"" + msg.Replace("\"", "\"\"") + "\"", false)
                  .Invoke();
      }

  }
'@

$VerbosePreference = 'Continue'

# Regular output to the verbose stream.
Write-Verbose 'msg1'

# Verbose output via the custom type.
# !! This can NOT be redirected from the outside.
[Write]::Verbose('msg2')

# !! SUPPRESSING or REDIRECTING TO A FILE only works
# !! when DIRECTLY APPLIED to the method call.
[Write]::Verbose('msg3') 4> $null
[Write]::Verbose('msg4') 4> t.txt

# !! REDIRECTING TO THE STANDARD OUTPUT STREAM (1) for the OUTSIDE works,
# !! but obviously it then merges with success output.
[Write]::Verbose('msg5') 4>&1

# !! To REDIRECT TO THE STANDARD OUTPUT STREAM (1) and capture the result
# !! INSIDE your script, invoke the method call in  (...) or $(...) or @(...)
$out = ([Write]::Verbose('msg6') 4>&1)
"[$out]"

答案 1 :(得分:0)

尽管上面来自mklement0的答案是一个很好的答案,但是如果您不建议使用CreateNestedPipeline API,则尝试将其与PowerShellCore配合使用或将.NetStandard 2.0用作目标时,它将无法正常工作。 (请参阅PowerShellStandard GitHub存储库上的this线程。)

因此,我有以下工作代码:

Add-Type -TypeDefinition @'
using System.Management.Automation;
using System.Management.Automation.Runspaces;

    public class Write
    {

        public static void Verbose(string msg)
        {

            using (PowerShell initialPowerShell = PowerShell.Create(RunspaceMode.CurrentRunspace))
            {

                initialPowerShell.Commands.AddScript("Write-Verbose " + msg.Replace("\"", "\"\"") + "\" -v");
                initialPowerShell.Invoke();

            }

        }

    }
'@

$VerbosePreference = 'Continue'

# Regular output to the verbose stream.
Write-Verbose 'msg1'

# Verbose output via the custom type.
# !! This can NOT be redirected from the outside.
[Write]::Verbose('msg2')

# !! SUPPRESSING or REDIRECTING TO A FILE only works
# !! when DIRECTLY APPLIED to the method call.
[Write]::Verbose('msg3') 4> $null
[Write]::Verbose('msg4') 4> t.txt

# !! REDIRECTING TO THE STANDARD OUTPUT STREAM (1) for the OUTSIDE works,
# !! but obviously it then merges with success output.
[Write]::Verbose('msg5') 4>&1

# !! To REDIRECT TO THE STANDARD OUTPUT STREAM (1) and capture the result
# !! INSIDE your script, invoke the method call in  (...) or $(...) or @(...)
$out = ([Write]::Verbose('msg6') 4>&1)
"[$out]"

可与Windows的PowerShell 5.1,Windows和Linux的PowerShell Core 6.2.2(Ubuntu / Debian)一起使用。

我仍然会将mklement0答复标记为原始问题的答案。我只是基于过去几天有关将类库迁移到.NetStandard 2.0的研究而编写的另一种。