Как избежать проблем с WriteVerbose/WriteObject
Я создал сборку.NET с пятью или шестью PSCmdlet в них. Все они являются конвейерными командлетами - то есть они настроены в 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
- Поскольку это конвейерно, это вызывает ProcessRecord в Invoke-GridJob.
- Invoke-GridJob имеет -Verbose, поэтому он устанавливает прослушиватель Trace.
- Invoke-GridJob вызывает WriteObject.
- Среда выполнения Powershell "возобновляет" Get-GridJobInfo, чтобы он генерировал следующий объект конвейера.
- Где-то в Get-GridJobInfo "Trace.WriteLine"
- Это запускает прослушиватель трассировки, который вызывает WriteVerbose.
- Ошибка возникает, потому что мы в настоящее время находимся в Get-GridJobInfo, и мы попытались вызвать WriteVerbose для объекта Invoke-GridJob PSCmdLet.
Эта проблема заключается в том, что TraceListener является глобальной вещью, и поэтому вызывается внутри и вне ProcessRecord Invoke-GridJob. Таким образом, возникает вопрос: как наилучшим образом обнаружить вход и выход?
Сначала я проверил CurrentThreadId, но оказалось, что он не работает - PS сохраняет все в одном потоке в максимально возможной степени.
Затем я подумал, что если бы в PowerShell был доступ к глобальному элементу, который мог бы сказать мне, какая команда выполнялась в данный момент, - тогда я мог бы сравнить ее с той, где я должен писать подробные сообщения. Однако я не смог найти такую вещь (вы можете найти это в отладчике: PSCmdLet.Context.CurrentCommandProcessor).
Если не считать реализацию какой-либо схемы отслеживания и передачи объектов глубоко в библиотеку в стеке вызовов, которые выполняют обратные вызовы, я не уверен, что я могу сделать.
Спасибо заранее!