【问题标题】:How do I capture .NET trace output from a Powershell job?如何从 Powershell 作业捕获 .NET 跟踪输出?
【发布时间】:2015-03-26 05:25:49
【问题描述】:

我在 Powershell 中使用 .NET 组件,它使用 Trace.TraceWarningTrace.TraceInformation 等。

我想在运行我的 Powershell 脚本时将这些跟踪输出到控制台。

这在我在当前会话中使用组件时有效。例如(模拟跟踪的效果)给我 'Hello' 输出到控制台:

 $listener = new-object "system.diagnostics.consoletracelistener"
 [System.Diagnostics.Trace]::Listeners.Add($listener) | Out-Null
 [System.Diagnostics.Trace]::TraceInformation("Hello")

但是,如果我在 Powershell 作业中执行相同的操作,我将不会得到任何输出,即使 ConsoleTraceListener 应该写入 STDOUT,而我预计会被作业捕获。 (有趣的是,Console.WriteLine 也不能在工作中工作 - 但 Write-Host 可以)。

我的工作是这样开始的:

$work = {
     $listener = new-object "system.diagnostics.consoletracelistener"
     [System.Diagnostics.Trace]::Listeners.Add($listener) | Out-Null
     [System.Diagnostics.Trace]::TraceInformation("Hello")
}
$job = Start-Job -RunAs32 -ScriptBlock $work
$job | Receive-Job -Wait

【问题讨论】:

  • ConsoleTraceListener 写入控制台,因此相关:serverfault.com/questions/399854/powershell-start-job-output
  • ConsoleTraceListener 似乎正在写入标准输出 referencesource.microsoft.com/#System/compmod/system/…。但是由于某些原因,它没有被选中
  • 经过更多测试后,我发现了一些关于工作和子工作的有趣的事情。我认为最终的问题是 powershell 没有使用 System.Console 类,而是使用自定义 System.Management.Automation.Host.PSHost 类并重定向流。不过,在像您这样的某些边缘情况下,这似乎并没有按预期实现。
  • ConsoleTraceListener 只是使用 STDOUT。不知道我看到它是一个边缘案例!

标签: powershell trace powershell-jobs


【解决方案1】:

我记得在几年前遇到过类似于预期的 STDOUT 和 STDIN 在 start-job 和 exe 中的行为与预期不同的情况。我最终使用了 System.Diagnostics.Process 并重定向了 STDIN 和 STDOUT。下面是一个示例,它以一种可以帮助您完成您正在尝试做的事情的方式演示此解决方法。

#added extra trace messages with Get-Date and implemented a random delay for demo purpose
$work = {
     $listener = new-object "system.diagnostics.consoletracelistener"
     [System.Diagnostics.Trace]::Listeners.Add($listener) | Out-Null
     1..10 | % {
         Start-Sleep $(Get-Random 5)
         [System.Diagnostics.Trace]::TraceInformation((Get-Date))
    }
}
#Create a process
$process = New-Object System.Diagnostics.Process 
$process.StartInfo.UseShellExecute = $false
#redirect stdout
$process.StartInfo.RedirectStandardOutput = $true
#call powershell
$process.StartInfo.FileName = "powershell.exe"
#pass the $work scriptblock
$process.StartInfo.Arguments = "-noprofile -command $work"
#start the process
$process.Start() | Out-Null
#readlines as they come in and exit when process is done
while(-not $process.HasExited){
    $process.StandardOutput.ReadLine()
}

输出:

powershell.exe Information: 0 : 01/30/2015 12:27:17
powershell.exe Information: 0 : 01/30/2015 12:27:20
powershell.exe Information: 0 : 01/30/2015 12:27:21
powershell.exe Information: 0 : 01/30/2015 12:27:25
powershell.exe Information: 0 : 01/30/2015 12:27:26
powershell.exe Information: 0 : 01/30/2015 12:27:28
powershell.exe Information: 0 : 01/30/2015 12:27:29
powershell.exe Information: 0 : 01/30/2015 12:27:33
powershell.exe Information: 0 : 01/30/2015 12:27:36
powershell.exe Information: 0 : 01/30/2015 12:27:40

【讨论】:

  • 感谢您的回答,但我认为 Start-Process 是“作弊”;)。我正在尝试找出为什么它对工作不起作用
  • @JackUkleja 这个答案,和Start-Process 一样是你唯一的选择。 [System.Diagnostics.Trace]::TraceInformation(..) 的输出不能被任何类型的重定向捕获 *>&1[console]::WriteLine(..) 相同或试图捕获 -WhatIf 的输出。
【解决方案2】:

不清楚您希望捕获的输出到哪里。到目前为止,大多数讨论都围绕控制台展开,但是由于您将其称为“工作”(我认为您的意思是计划任务),因此我不确定控制台是否是最佳位置。你永远不会看到结果。日志文件听起来更合适。如果是这种情况,您应该创建一个TextWriteTraceLister。这将允许您为结果设置一个日志文件。

此外,.Net 中的 Tracing 的一大优点是您可以连接多个侦听器。因此,如果您想在运行时查看输出,还可以附加 ConsoleTraceListener,它不会干扰写入日志文件。

最后,也可以编写自己的 TraceListener。这对于写入日志数据库或 Web 服务等事情很有用。要在 PowerShell 中使用您自己的 TraceListener,您需要使用 .Net 语言构建侦听器,该语言可以编译为类库程序集 (dll),该程序集可以部署到 GAC 以在您的项目中使用。

【讨论】:

  • 这是一个 powershell 作业,就像使用 Start-Job 启动的一样。顺便说一句,我使用工作的原因是因为我需要从 64 位 powershell 加载和使用 x86 .NET 程序集。 Job 提供了一种非常简单的方法来做到这一点
  • 在常规 psh 会话中运行时的跟踪语句将输出到管道中。所以理想情况下,它们会以与正常输出结果相同的方式从 receive-job 命令返回。
  • 您可能会觉得这很有帮助:stackoverflow.com/questions/11973775/…
  • 谢谢,但不确定.NET 跟踪的解释是否真的对我有帮助。我对它相当熟悉。我曾考虑编写一个自定义跟踪侦听器来挂钩事件并将它们输出到我知道可以工作的 PSH 部分,例如 write-host 但我希望得到一个明确的答案,说明为什么问题中的场景不起作用.
  • 这是程序员相当于理论物理学家的标准借口。我们可以说“因为线程”,而不是“因为量子”。 Start-Job 将工作推送到单独的线程中,并且 Trace 事件仍然在单独的线程中触发。每个线程都有自己隐藏的标准输出。 Start-Job 保留这些结果并最终通过 Receive-Job 将它们推回。对于 Trace 事件...看起来并没有那么多,至少在这种情况下是这样。
猜你喜欢
  • 1970-01-01
  • 2012-05-10
  • 2021-09-08
  • 2013-08-30
  • 2020-02-28
  • 2012-03-02
  • 2021-06-29
  • 2018-06-09
  • 2022-07-15
相关资源
最近更新 更多