在PowerShell中使用WebView2的GetCookiesAsync时出现冻结问题
问题原因
你当前的代码在NavigationCompleted事件处理中使用GetAwaiter().GetResult()同步等待异步任务完成,这会引发UI线程死锁:
NavigationCompleted事件运行在UI线程上GetCookiesAsync的后续回调需要回到UI线程执行- 同步等待会阻塞UI线程,导致WebView2无法处理后续操作,最终界面冻结
正确实现方式
需要避免在UI线程中同步等待异步任务,改用异步事件监听的方式获取Cookie,同时使用全局变量存储结果以便后续调用。
修改后的完整脚本
#Based on https://stackoverflow.com/questions/66106927/webview2-in-powershell-winform-gui #---------------------------------------------- #region Import the Assemblies #---------------------------------------------- [void][reflection.assembly]::LoadFile("$PSScriptRoot\assemblies\Microsoft.Web.WebView2.Winforms.dll") [void][reflection.assembly]::LoadFile("$PSScriptRoot\assemblies\Microsoft.Web.WebView2.Core.dll") [void][reflection.assembly]::Load('System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a') [void][reflection.assembly]::Load('System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089') #endregion Import Assemblies #---------------------------------------------- #region Generated Form Objects #---------------------------------------------- [System.Windows.Forms.Application]::EnableVisualStyles() $form1 = New-Object 'System.Windows.Forms.Form' $buttonRefresh = New-Object 'System.Windows.Forms.Button' $buttonGo = New-Object 'System.Windows.Forms.Button' $textbox1 = New-Object 'System.Windows.Forms.TextBox' [Microsoft.Web.WebView2.WinForms.WebView2] $webview = New-Object 'Microsoft.Web.WebView2.WinForms.WebView2' $webview.CreationProperties = New-Object 'Microsoft.Web.WebView2.WinForms.CoreWebView2CreationProperties' $webview.CreationProperties.UserDataFolder = $PSScriptRoot; $InitialFormWindowState = New-Object 'System.Windows.Forms.FormWindowState' #endregion Generated Form Objects # 全局变量存储Cookie结果 $global:authCookies = $null #---------------------------------------------- # User Generated Script #---------------------------------------------- $form1_Load={ $webview.Source = ([uri]::new($textbox1.Text)) $webview.Visible = $true } $buttonGo_Click={ $webview.Source = [System.Uri] $textbox1.Text } $webview_SourceChanged={ $form1.Text = $webview.Source.AbsoluteUri } $coreWebView2Initialized = { $cookieManager = $webview.CoreWebView2.CookieManager; $cookie = $cookieManager.CreateCookie("name", "value", "example.com", "/") $cookieManager.AddOrUpdateCookie($cookie); } $webview_OnNavigationCompleted={ # 启动异步Cookie获取任务,不阻塞UI线程 $getCookiesTask = $webview.CoreWebView2.CookieManager.GetCookiesAsync("") # 监听任务完成事件,异步处理结果 Register-ObjectEvent -InputObject $getCookiesTask -EventName Completed -Action { $global:authCookies = $EventArgs.Result Write-Host "成功获取到 $($global:authCookies.Count) 个Cookie" # 可选:将Cookie转换为REST API可用的格式 $cookieHeader = ($global:authCookies | ForEach-Object { "$($_.Name)=$($_.Value)" }) -join "; " Write-Host "Cookie请求头格式: $cookieHeader" } | Out-Null } # --End User Generated Script-- #---------------------------------------------- #region Generated Events #---------------------------------------------- $Form_StateCorrection_Load= { #Correct the initial state of the form to prevent the .Net maximized form issue $form1.WindowState = $InitialFormWindowState } $Form_Cleanup_FormClosed= { #Remove all event handlers from the controls try { $buttonGo.remove_Click($buttonGo_Click) $webview.remove_SourceChanged($webview_SourceChanged) $form1.remove_Load($form1_Load) $form1.remove_Load($Form_StateCorrection_Load) $form1.remove_FormClosed($Form_Cleanup_FormClosed) } catch { Out-Null <# Prevent PSScriptAnalyzer warning #> } } #endregion Generated Events #---------------------------------------------- #region Generated Form Code #---------------------------------------------- $form1.SuspendLayout() $form1.Controls.Add($buttonRefresh) $form1.Controls.Add($buttonGo) $form1.Controls.Add($textbox1) $form1.Controls.Add($webview) $form1.AutoScaleDimensions = New-Object System.Drawing.SizeF(6, 13) $form1.AutoScaleMode = 'Font' $form1.ClientSize = New-Object System.Drawing.Size(619, 413) $form1.Name = 'form1' $form1.Text = 'Form' $form1.add_Load($form1_Load) # # buttonRefresh # $buttonRefresh.Location = New-Object System.Drawing.Point(13, 13) $buttonRefresh.Name = 'buttonRefresh' $buttonRefresh.Size = New-Object System.Drawing.Size(75, 23) $buttonRefresh.TabIndex = 3 $buttonRefresh.Text = 'Refresh' $buttonRefresh.UseVisualStyleBackColor = $True # # buttonGo # $buttonGo.Location = New-Object System.Drawing.Point(538, 9) $buttonGo.Name = 'buttonGo' $buttonGo.Size = New-Object System.Drawing.Size(75, 23) $buttonGo.TabIndex = 2 $buttonGo.Text = 'Go' $buttonGo.UseVisualStyleBackColor = $True $buttonGo.add_Click($buttonGo_Click) # # textbox1 # $textbox1.Location = New-Object System.Drawing.Point(96, 13) $textbox1.Name = 'textbox1' $textbox1.Size = New-Object System.Drawing.Size(435, 20) $textbox1.TabIndex = 1 $textbox1.Text = 'https://www.bing.com' # # webview # $webview.Location = New-Object System.Drawing.Point(0, 49) $webview.Name = 'webview' $webview.Size = New-Object System.Drawing.Size(619, 364) $webview.TabIndex = 0 $webview.ZoomFactor = 1 $webview.add_SourceChanged($webview_SourceChanged) #Actions with cookies $webview.add_NavigationCompleted($webview_OnNavigationCompleted) $webview.add_CoreWebView2InitializationCompleted($coreWebView2Initialized) $form1.ResumeLayout() #endregion Generated Form Code #---------------------------------------------- #Save the initial state of the form $InitialFormWindowState = $form1.WindowState #Init the OnLoad event to correct the initial state of the form $form1.add_Load($Form_StateCorrection_Load) #Clean up the control events $form1.add_FormClosed($Form_Cleanup_FormClosed) #Show the Form $form1.ShowDialog() # 窗体关闭后输出Cookie if ($global:authCookies) { Write-Host "`n获取到的Cookie列表:" $global:authCookies | Select-Object Name, Value, Domain, Path | Format-Table -AutoSize } Read-Host
关键修改点
- 新增全局变量
$global:authCookies存储Cookie结果,避免局部变量作用域问题 - 在
NavigationCompleted事件中,不再同步等待任务完成,而是通过Register-ObjectEvent监听异步任务的Completed事件 - 任务完成后异步处理Cookie结果,同时提供了转换为REST API请求头格式的示例
补充说明
- 若需要针对特定域名获取Cookie,可将
GetCookiesAsync("")中的空字符串替换为目标域名(如"https://your-app-domain.com") - 全局变量
$global:authCookies可直接用于后续的REST API请求,例如:$headers = @{ "Cookie" = ($global:authCookies | ForEach-Object { "$($_.Name)=$($_.Value)" }) -join "; " } Invoke-RestMethod -Uri "https://your-api-endpoint" -Headers $headers
内容的提问来源于stack exchange,提问作者TedJ
相关产品推荐
相关产品推荐

