我已经创建了一个包含五个或六个 PSCmdlet 的 .NET 程序集。它们都是管道 cmdlet——即它们在 BeginProcessing 中设置,并在 ProcessRecord 中完成工作。他们打电话到图书馆。我在整个库中使用“Trace.WriteLine”来跟踪正在发生的事情。
我认为只创建一个 Trace 侦听器并将其写入 WriteVerbose 会非常酷。
但是,这会导致崩溃:
PS C:\Users\Gordon\Documents\Code\calratio2015\JetCutStudies> .\Find-CalRatioSamples.ps1 mc15c | .\submit-all-samples.ps1
Get-GridJobInfo : The WriteObject and WriteError methods cannot be called from outside the overrides of the BeginProcessing, ProcessRecord, and EndProcessing methods, and they can only be called from within the same thread.
Validate that the cmdlet makes these calls correctly, or contact Microsoft Customer Support Services.
At C:\Users\Gordon\Documents\Code\calratio2015\JetCutStudies\submit-all-samples.ps1:23 char:14
+ Status = Get-GridJobInfo -JobStatus $_.ID
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : InvalidOperation: (:) [Get-GRIDJobInfo], PSInvalidOperationException
+ FullyQualifiedErrorId : InvalidOperation,PSAtlasDatasetCommands.GetGRIDJobInfo
我花了一段时间才弄清楚发生了什么。我想我明白了,但还不知道如何解决它(至少,不容易)。
- Get-GridJobInfo 获取一些信息并调用 WriteObject
- 由于这是流水线的,因此会调用 Invoke-GridJob 中的 ProcessRecord。
- Invoke-GridJob 有 -Verbose,所以它安装了一个 Trace 监听器。
- Invoke-GridJob 调用 WriteObject。
- Powershell 运行时“恢复”Get-GridJobInfo 以使其生成下一个管道对象。
- Get-GridJobInfo 中的某处“Trace.WriteLine”
- 这会触发调用 WriteVerbose 的跟踪侦听器。
- 发生错误是因为我们当前在 Get-GridJobInfo 中,并且我们尝试在 Invoke-GridJob PSCmdLet 对象上调用 WriteVerbose。
这个问题是 TraceListener 是一个全局的东西,因此在 Invoke-GridJob 的 ProcessRecord 内部和外部被调用。所以问题就变成了:如何最好地检测进出?
我的第一个想法是检查 CurrentThreadId - 但事实证明这不起作用 - PS 尽可能地将事情保持在同一个线程上。
接下来,我想如果我可以在 PowerShell 中访问一个全局变量,它会告诉我当前正在执行什么命令——然后我可以将它与我应该编写详细消息的那个进行比较。但是,我一直没能找到这样的东西(你可以在调试器中找到它:PSCmdLet.Context.CurrentCommandProcessor)。
由于没有实现某种跟踪方案并将对象深入到调用堆栈上的库中进行回调,我不确定我能做什么。
提前谢谢了!