因为我的雇主不想使用编译软件,所以他们要求我创建一个使用PowerShell并行ping一系列设备的GUI。我的PowerShell脚本由该表单上的表单和按钮组成,用于ping设备。为了防止GUI锁定,我使用Runspace将ping操作卸载到一个单独的线程。我可以ping设备并使用来自Runspace的信息更新Form,但是当我完成应用程序时,我无法关闭/处理Runspace,因此即使在应用程序退出后它也会继续运行。
下面提供的函数ping localhost 10次,并将结果添加到GUI中的ListView。
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()
}
关闭应用程序时出现的错误是
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
我认为这个问题正在发生,因为Runspace正在执行,但是当它运行不正常时就会发生。但是当它全部耦合到像
这样的相同函数内时,它成功关闭而没有错误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()
}
如何让Runspace在其所在的同一函数之外释放所有资源?
答案 0 :(得分:1)
$powershell
很可能不是全局变量,因此您有2个不同的变量$powershell
,一个在函数PingDevices()
的上下文中填充,另一个(空)一个在函数CleanupResources()
的上下文中。使用scope modifier更改变量的范围以避免这种情况:$script:powershell
(或$global:powershell
)。