How to avoid WriteVerbose/WriteObject bad thread

708 views Asked by At

I've created a .NET assembly with five or six PSCmdlet's in them. They are all pipe-line cmdlets - that is they have setup in BeginProcessing, and do the work in ProcessRecord. They call into a library. I use "Trace.WriteLine" throughout the library to track what is going on.

I thought it would be very cool to just create a Trace listener and have it write to WriteVerbose.

This causes a crash, however:

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

It took me a while to figure out what is happening. I think I understand, but not how to fix it yet (at least, not easily).

  1. Get-GridJobInfo gets some info and calls WriteObject
  2. Since this is pipelined, that invokes the ProcessRecord in Invoke-GridJob.
  3. Invoke-GridJob has -Verbose, so it installs a Trace listener.
  4. Invoke-GridJob calls WriteObject.
  5. Powershell runtime "resumes" Get-GridJobInfo to have it generate the next pipeline object.
  6. Somewhere in Get-GridJobInfo a "Trace.WriteLine"
  7. This triggers the trace listener that calls WriteVerbose.
  8. Error occurs because we are currently in Get-GridJobInfo and we tried to call WriteVerbose on the Invoke-GridJob PSCmdLet object.

This issue is the TraceListener is a global thing, and so gets called inside and outside of Invoke-GridJob's ProcessRecord. So the question becomes: how to best detect in and out?

My first though was to check the CurrentThreadId - but that turns out to not work - PS keeps things on the same thread as much as possible.

Next, I thought if there was a global I could access in PowerShell that would tell me what command was currently executing - I could then compare it against the one where I should be writing verbose messages. However, I have not been able to find such a thing (you can find it in the debugger: PSCmdLet.Context.CurrentCommandProcessor).

Short of implementing some sort of tracking scheme and passing objects deep into the library on the callstack that do callbacks, I'm not sure what I can do.

Many thanks in advance!

0

There are 0 answers