我需要在Power
Shell 2.0中使用WebClient下载文件,我想显示下载进度,所以我这样做:
$activity = "Downloading" $client = New-Object System.Net.WebClient $urlAsUri = New-Object System.Uri($url) $event = New-Object System.Threading.ManualResetEvent($false) $downloadProgress = [System.Net.DownloadProgressChangedEventHandler] { $progress = [int]((100.0 * $_.BytesReceived) / $_.TotalBytesToReceive) Write-Progress -Activity $activity -Status "${progress}% done" -PercentComplete $progress } $downloadComplete = [System.ComponentModel.AsyncCompletedEventHandler] { Write-Progress -Activity $activity -Completed $event.Set() } $client.add_DownloadFileCompleted($downloadComplete) $client.add_DownloadProgressChanged($downloadProgress) Write-Progress -Activity $activity -Status "0% done" -PercentComplete 0 $client.DownloadFileAsync($urlAsUri,$file) $event.WaitOne()
我收到一个错误没有可用Runspace在此线程中运行脚本.对于$downloadProgress处理程序中的代码,这是逻辑的.但是,如何为(可能)属于ThreadPool的线程提供Runspace?
更新:
请注意,这个问题的答案都值得阅读,如果可以的话我也会接受.
解决方法
谢谢stej点头.
Andrey,powershell有自己的线程池,每个服务线程保持一个线程指针到一个运行空间(System.Management.Automation.Runspaces.Runspace.DefaultRunspace静态成员暴露了这一点 – 并且在你的回调中将是一个空参考)最终这意味着使用自己的线程池(由.NET为异步方法提供的)很难(特别是在脚本中)来执行脚本块.
PowerShell 2.0
无论如何,没有必要玩这个,因为powershell v2完全支持事件发生:
$client = New-Object System.Net.WebClient $url = [uri]"http://download.microsoft.com/download/6/2/F/" + "62F70029-A592-4158-BB51-E102812CBD4F/IE9-Windows7-x64-enu.exe" try { Register-ObjectEvent $client DownloadProgressChanged -action { Write-Progress -Activity "Downloading" -Status ` ("{0} of {1}" -f $eventargs.BytesReceived,$eventargs.TotalBytesToReceive) ` -PercentComplete $eventargs.ProgressPercentage } Register-ObjectEvent $client DownloadFileCompleted -SourceIdentifier Finished $file = "c:\temp\ie9-beta.exe" $client.DownloadFileAsync($url,$file) # optionally wait,but you can break out and it will still write progress Wait-Event -SourceIdentifier Finished } finally { $client.dispose() }
PowerShell v1.0
如果你坚持v1(这不是专门为你提到v2中的问题),你可以使用我的powershell 1.0事件管理单元在http://pseventing.codeplex.com/
异步回调
.NET中另一个棘手的区域是异步回调.没有什么直接在v1或v2的powerhell可以帮助你在这里,但你可以转换一个异步回调到一个简单的管道事件,然后处理该事件使用常规事件.我在http://poshcode.org/1382发布了一个脚本(New-ScriptBlockCallback)
希望这可以帮助,
-Oisin