I have a form written in PowerShell (as it uses PS to run commands over hundreds of servers) but this bit had me stumped for awhile:
$listview.Invoke([System.Action[String]]{
Param
(
[String]$data
)
write-warning "1"
$LVitem = ($LVresults.Items | Where { $_.Name -eq "Test Account" })
write-warning "2"
$LVitem.Tag.Output += $data + "`n"
}, "Testing")
It's in a separate runspace that runs an Invoke-Command to a specific server and pipes the output to this code block.
Now if I run the Where statement in the main runspace (where the form is created) it works perfectly fine. In the separate runspace however it locks up the form. Warning 1 is displayed, Warning 2 is not.
Piping to a Foreach statement has the same problem, but I can use:
Foreach ($item in $listview.Items) {
if ($item.Name -eq "Test Account") { $LVitem = $item }
}
Can anyone explain this? I'm not doing anything fancy with the ListView or its items, it just seems the ListView doesn't like its items being piped in another runspace.
This is the problem with PowerShell event system. It deadlocks when event handler generate event with wait to completion option.
So, what your setup have to do with events?
Script blocks literals remembers current session state (including
Runspace
) at creation time. And if at script block invocation time currentRunspace
for current thread ([Runspace]::DefaultRunspace
) is different or busy processing something in different thread, then script block invoked by generating event to originalRunspace
with wait to completion option.Another interesting thing is that: if target
Runspace
does not start processing events in 250 milliseconds, then PowerShell start event processing in the thread waiting for event completion.In your code you have two nested script block invokations:
$listview.Invoke
method.Where-Object
cmdlet.As I see, your code have three possible outcomes:
Script block's original
Runspace
is free, so script block executed in different thread (not UI thread).Script block's original
Runspace
is busy, so script block executed in current thread and deadlocks on nested script block invocation.Script block's original
Runspace
initially busy, but get free before nested script block invocation, so script block executed in current thread and does not deadlocks.To workaround this issue you need to detach script block from its original
Runspace
. You can achieve that by creating new script block from string using[ScriptBlock]::Create
method.