【问题标题】:How to pass flag variables between Powershell and c#?如何在 Powershell 和 c# 之间传递标志变量?
【发布时间】:2020-05-01 14:14:58
【问题描述】:

我有一个脚本,它启动一个包含 c# 代码的脚本块的 powershell 作业。

现在我有一个 sleep 命令可以让代码正确定位自己,但更简洁的方法(如果可能的话)是让 psjob c# 代码设置一个标志并允许我的其余代码以尽快,而不是等待 5 秒钟的睡眠。这可能吗?

$containerScript = {a mix of c# and powershell}
Start-Job -ScriptBlock $containerScript ;
sleep 5; # wait here for c# code to set up
Connect-MsolService;

因此,如果我在 c# psjob 脚本中设置了一个变量,比如bool started = true;我怎么能通过循环而不是在上面显示的 powershell 代码中使用 sleep 5 来读取它,这在 psjob 运行空间和 c# 代码之外?

【问题讨论】:

  • 我想出了这么多@mklement0 $result = Receive-Job -id $returnValue.Id -InformationVariable infovariable;我可以从该输出中看到我在 psjobs 脚本中使用“Write-Host”的任何内容,但我没有看到 c# Console.Write("adfadf") 类型的输出?
  • 是的,我把它作为一个循环。我需要知道如何将值从 c# 代码传递到 psjobs 包装器,我才能让它工作?
  • 我不能返回一个值,因为它会停止 c# 代码的执行,这就是为什么我想做一个两个代码集都可读的标志。有没有办法在不使用返回函数的情况下写入管道?像 Pipeline.Write("asdfaf") 之类的东西?
  • 在c#部分可能是这样的吗? Runspace rs = RunspaceFactory.CreateRunspace(); rs.Open(); Pipeline pipe = rs.CreatePipeline(); pipe.Commands.AddScript("Write-Host loopFirstTime"); pipe.Invoke(); rs.Close();

标签: c# powershell environment-variables global-variables


【解决方案1】:

您正在寻找的是一种自定义 .NET 类型的方法,以异步写入 PowerShell 的输出流,以在方法本身返回之前向调用 PowerShell 代码发出条件信号。

Console.WriteLine()不能这样做,因为它直接写入控制台,完全绕过 PowerShell 的输出流。

最好的方法是将您的 .NET 类型实现为 PowerShell cmdlet,这将允许您使用其 .Write*() 方法立即写入 PowerShell 的输出流。

如果这不是一个选项,您可以使用 PowerShell SDK 写入调用运行空间的输出流,这有其局限性,如 this answer 中所述。

以下是适用于您的用例的技术演示:

# Start a background job.
$jb = Start-Job { 

  # Compile a sample type from C# source code.
  Add-Type -TypeDefinition @'
  using System.Management.Automation;

  public class SomeClass
  {

      public static string DoStuff()
      {
        // ... perform initialization

        // Instantly signal to the calling PowerShell session that initialization has
        // completed, by calling Write-Information, which writes to the information stream (6).
        using (PowerShell ps = PowerShell.Create(RunspaceMode.CurrentRunspace)) {
          // IMPORTANT: Use .AddScript(), not .AddCommand().
          //            Even though .AddCommand() + .AddParameter() is arguably a cleaner way to
          //            formulate the command, it results in output that cannot be captured.
          // Even though Write-Information is silent by default, the information *is* written to the stream.
          ps.AddScript("Write-Information 'Initialized'").Invoke();
        }

        // Do other things.
        System.Threading.Thread.Sleep(2000);

        return "Done";

      }

  }
'@

  # Call the sample type's method, which runs for a while, and partway
  # through signals completion of the initialization portion with Write-Host output.
  [SomeClass]::DoStuff()

 }

 # Wait for output from the job and output it as it arrives. 
 while ($jb.HasMoreData) {

  # Receive pending stream output from the background job, capturing information-stream output separately.
  Receive-Job $jb -InformationVariable iv

  # Check if the initialization notification was received via the information stream.
  # Note that $iv is always a *collection* type, even if there's only 1 message,
  # and that the elements of that collection are of type [System.Management.Automation.InformationRecord]
  if ($iv -and $iv[0].ToString() -eq 'Initialized') { 'Now initialized.'}

  Start-Sleep -Milliseconds 100

}

Remove-Job $jb # clean up.

【讨论】:

    猜你喜欢
    • 2011-07-31
    • 2021-01-05
    • 2015-05-23
    • 2016-12-20
    • 2011-09-14
    • 1970-01-01
    • 2019-04-26
    • 2010-10-27
    • 2013-07-23
    相关资源
    最近更新 更多