Reputation: 507
Because my employer does not want to use compiled software they have asked me to create a GUI that pings a series of devices in parallel using PowerShell. My PowerShell script consists of a Form and a Button on that form that pings the devices. In order to prevent the GUI from locking up I use a Runspace to offload the pinging to a separate thread. I am able to ping the devices and update the Form with the information from the Runspace, however when I finish the application I am unable to close/Dispose of the Runspace and thus it keeps running even after the application exits.
The functions provided below pings localhost 10 times and adds the result to the ListView in the GUI.
Function PingDevices
{
Write-Host "Pinging Devices"
$items = $StorePingInfo_ListView.Items
$ScriptBlock =
{
$a = 0
for(;$a -lt 10; $a++)
{
$PingResult = Test-Connection 127.0.0.1 -Count 1
#[System.Windows.Forms.MessageBox]::Show($PingResult)
$items.Add("Name").SubItems.Add($PingResult)
sleep 1
}
}
$runspace = [RunspaceFactory]::CreateRunspace()
$runspace.Open()
$runspace.SessionStateProxy.SetVariable('Items',$items)
$powershell = [System.Management.Automation.PowerShell]::create()
$powershell.Runspace = $runspace
$powershell.AddScript($ScriptBlock)
$AsyncHandle = $powershell.BeginInvoke()
}
Function CleanupResources
{
#When I try to clean up the resources I get Null errors
Write-Host "AsyncHandle is Null = "($AsyncHandle -eq $null)
$data = $powershell.EndInvoke($AsyncHandle)
$powershell.Dispose()
$runspace.Close()
}
The errors I get when closing the application are
Pinging Devices AsyncHandle is Null = True You cannot call a method on a null-valued expression. At C:\Users\Loligans\Drive\dboardscript.ps1:673 char:5 + $data = $powershell.EndInvoke($AsyncHandle) + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + CategoryInfo : InvalidOperation: (:) [], RuntimeException + FullyQualifiedErrorId : InvokeMethodOnNull You cannot call a method on a null-valued expression. At C:\Users\Loligans\Drive\dboardscript.ps1:674 char:5 + $powershell.Dispose() + ~~~~~~~~~~~~~~~~~~~~~ + CategoryInfo : InvalidOperation: (:) [], RuntimeException + FullyQualifiedErrorId : InvokeMethodOnNull You cannot call a method on a null-valued expression. At C:\Users\Loligans\Drive\dboardscript.ps1:675 char:5 + $runspace.Close() + ~~~~~~~~~~~~~~~~~ + CategoryInfo : InvalidOperation: (:) [], RuntimeException + FullyQualifiedErrorId : InvokeMethodOnNull
I thought the issue was happening because the Runspace is executing but it happens when it is not running as well. However it closes successfully with no errors when it all is coupled inside the same function like this
Function PingDevices
{
Write-Host "Pinging Devices"
$items = $StorePingInfo_ListView.Items
$ScriptBlock =
{
$a = 0
for(;$a -lt 10; $a++)
{
$PingResult = Test-Connection 127.0.0.1 -Count 1
#[System.Windows.Forms.MessageBox]::Show($PingResult)
$items.Add("Name").SubItems.Add($PingResult)
sleep 1
}
}
$runspace = [RunspaceFactory]::CreateRunspace()
$runspace.Open()
$runspace.SessionStateProxy.SetVariable('Items',$items)
$powershell = [System.Management.Automation.PowerShell]::create()
$powershell.Runspace = $runspace
$powershell.AddScript($ScriptBlock)
$AsyncHandle = $powershell.BeginInvoke()
$data = $powershell.EndInvoke($AsyncHandle)
$powershell.Dispose()
$runspace.Close()
}
How can I get the Runspace to release all its resources outside the same function it resides in?
Upvotes: 1
Views: 2464
Reputation: 200193
$powershell
most likely isn't a global variable, so you have 2 different variables $powershell
, one that gets populated in the context of the function PingDevices()
, and another (empty) one in the context of the function CleanupResources()
. Change the scope of the variables with a scope modifier to avoid this: $script:powershell
(or $global:powershell
).
Upvotes: 1